[xmds2] 01/22: Imported Upstream version 2.1.4

Rafael Laboissière rlaboiss-guest at moszumanska.debian.org
Fri Jan 3 21:46:56 UTC 2014


This is an automated email from the git hooks/post-receive script.

rlaboiss-guest pushed a commit to branch master
in repository xmds2.

commit 26b33227310390444f32a71f5c76d7c78f373847
Author: Rafael Laboissiere <rafael at laboissiere.net>
Date:   Fri Jan 3 22:40:06 2014 +0100

    Imported Upstream version 2.1.4
---
 COPYING                                            |  282 ++
 COPYRIGHT                                          |   14 +
 Makefile                                           |   25 +
 README                                             |    9 +
 ReleaseNotes                                       |   95 +
 admin/TODO                                         |   70 +
 admin/create_release_version.sh                    |   49 +
 admin/developer-doc-source/FFTW3MPI Design.graffle |  Bin 0 -> 94768 bytes
 admin/developer-doc-source/FFTW3MPI Design.pdf     |  Bin 0 -> 26598 bytes
 admin/developer-doc-source/Makefile                |   14 +
 admin/developer-doc-source/epydoc.cfg              |  100 +
 admin/fftw3-SnowLeopard.patch                      |   30 +
 admin/linux_installer.sh                           |  548 +++
 admin/releaseInstructions.txt                      |   31 +
 admin/svn2cl.xsl                                   |  442 ++
 admin/userdoc-source/Makefile                      |   70 +
 .../_static/mathjax-use-tex-fonts.js               |    9 +
 admin/userdoc-source/advanced_topics.rst           |  276 ++
 admin/userdoc-source/conf.py                       |  188 +
 admin/userdoc-source/developer.rst                 |  121 +
 admin/userdoc-source/documentation_toc.rst         |   33 +
 admin/userdoc-source/faq.rst                       |   64 +
 .../userdoc-source/images/FourierTransformEx1.pdf  |  Bin 0 -> 77448 bytes
 .../userdoc-source/images/FourierTransformEx1.png  |  Bin 0 -> 19510 bytes
 .../userdoc-source/images/FourierTransformEx2.pdf  |  Bin 0 -> 176877 bytes
 .../userdoc-source/images/FourierTransformEx2.png  |  Bin 0 -> 22681 bytes
 .../userdoc-source/images/FourierTransformEx3.pdf  |  Bin 0 -> 160165 bytes
 .../userdoc-source/images/FourierTransformEx3.png  |  Bin 0 -> 28754 bytes
 admin/userdoc-source/images/fibre1024.pdf          |  Bin 0 -> 1368197 bytes
 admin/userdoc-source/images/fibre1024.png          |  Bin 0 -> 242577 bytes
 admin/userdoc-source/images/fibreSingle.pdf        |  Bin 0 -> 1567250 bytes
 admin/userdoc-source/images/fibreSingle.png        |  Bin 0 -> 228778 bytes
 admin/userdoc-source/images/groundstateU2.pdf      |  Bin 0 -> 1098425 bytes
 admin/userdoc-source/images/groundstateU2.png      |  Bin 0 -> 42924 bytes
 admin/userdoc-source/images/groundstateU20.pdf     |  Bin 0 -> 1238733 bytes
 admin/userdoc-source/images/groundstateU20.png     |  Bin 0 -> 49507 bytes
 admin/userdoc-source/images/kubo10000.pdf          |  Bin 0 -> 3957 bytes
 admin/userdoc-source/images/kubo10000.png          |  Bin 0 -> 15178 bytes
 admin/userdoc-source/images/kuboSingle.pdf         |  Bin 0 -> 33828 bytes
 admin/userdoc-source/images/kuboSingle.png         |  Bin 0 -> 44572 bytes
 admin/userdoc-source/images/lorenz.pdf             |  Bin 0 -> 650829 bytes
 admin/userdoc-source/images/lorenz.png             |  Bin 0 -> 18377 bytes
 admin/userdoc-source/images/xmds_favicon.ico       |  Bin 0 -> 4286 bytes
 admin/userdoc-source/images/xmds_favicon.png       |  Bin 0 -> 2251 bytes
 admin/userdoc-source/images/xmds_logo.pdf          |  Bin 0 -> 27201 bytes
 admin/userdoc-source/images/xmds_logo.png          |  Bin 0 -> 30659 bytes
 admin/userdoc-source/index.rst                     |   17 +
 admin/userdoc-source/installation.rst              |  251 ++
 admin/userdoc-source/introduction.rst              |   31 +
 admin/userdoc-source/licensing.rst                 |   10 +
 admin/userdoc-source/news.rst                      |  100 +
 admin/userdoc-source/optimisation_hints.rst        |  171 +
 admin/userdoc-source/reference_elements.rst        | 1339 ++++++
 admin/userdoc-source/reference_index.rst           |   15 +
 .../reference_installation_and_configuration.rst   |   38 +
 admin/userdoc-source/reference_schema.rst          |  157 +
 admin/userdoc-source/reference_usefulXMLSyntax.rst |   24 +
 admin/userdoc-source/support/preview.sty           |  381 ++
 admin/userdoc-source/tutorial.rst                  |  258 ++
 admin/userdoc-source/upgrade.rst                   |   10 +
 admin/userdoc-source/worked_examples.rst           | 1359 ++++++
 admin/userdoc-source/xsil2graphics2.rst            |    8 +
 .../Syntaxes/Cheetah - xpdeint template.tmLanguage |   69 +
 admin/xpdeint.tmbundle/Syntaxes/xpdeint.tmLanguage |   75 +
 admin/xpdeint.tmbundle/info.plist                  |   15 +
 bin/xmds2                                          |    4 +
 bin/xsil2graphics2                                 |    4 +
 debian/changelog                                   |    5 +
 debian/compat                                      |    1 +
 debian/control                                     |   45 +
 debian/copyright                                   |   31 +
 debian/docs                                        |    3 +
 debian/pycompat                                    |    1 +
 debian/pyversions                                  |    1 +
 debian/rules                                       |   28 +
 debian/xmds2.examples                              |    1 +
 debian/xmds2.manpages                              |    2 +
 documentation/.buildinfo                           |    4 +
 documentation/_images/FourierTransformEx1.png      |  Bin 0 -> 19510 bytes
 documentation/_images/FourierTransformEx2.png      |  Bin 0 -> 22681 bytes
 documentation/_images/FourierTransformEx3.png      |  Bin 0 -> 28754 bytes
 documentation/_images/fibre1024.png                |  Bin 0 -> 242577 bytes
 documentation/_images/fibreSingle.png              |  Bin 0 -> 228778 bytes
 documentation/_images/groundstateU2.png            |  Bin 0 -> 42924 bytes
 documentation/_images/groundstateU20.png           |  Bin 0 -> 49507 bytes
 documentation/_images/kubo10000.png                |  Bin 0 -> 15178 bytes
 documentation/_images/kuboSingle.png               |  Bin 0 -> 44572 bytes
 documentation/_images/lorenz.png                   |  Bin 0 -> 18377 bytes
 documentation/_sources/advanced_topics.txt         |  276 ++
 documentation/_sources/developer.txt               |  121 +
 documentation/_sources/documentation_toc.txt       |   33 +
 documentation/_sources/faq.txt                     |   64 +
 documentation/_sources/index.txt                   |   17 +
 documentation/_sources/installation.txt            |  251 ++
 documentation/_sources/introduction.txt            |   31 +
 documentation/_sources/licensing.txt               |   10 +
 documentation/_sources/news.txt                    |  100 +
 documentation/_sources/optimisation_hints.txt      |  171 +
 documentation/_sources/reference_elements.txt      | 1339 ++++++
 documentation/_sources/reference_index.txt         |   15 +
 .../reference_installation_and_configuration.txt   |   38 +
 documentation/_sources/reference_schema.txt        |  157 +
 .../_sources/reference_usefulXMLSyntax.txt         |   24 +
 documentation/_sources/tutorial.txt                |  258 ++
 documentation/_sources/upgrade.txt                 |   10 +
 documentation/_sources/worked_examples.txt         | 1359 ++++++
 documentation/_sources/xsil2graphics2.txt          |    8 +
 documentation/_static/ajax-loader.gif              |  Bin 0 -> 673 bytes
 documentation/_static/basic.css                    |  540 +++
 documentation/_static/comment-bright.png           |  Bin 0 -> 3500 bytes
 documentation/_static/comment-close.png            |  Bin 0 -> 3578 bytes
 documentation/_static/comment.png                  |  Bin 0 -> 3445 bytes
 documentation/_static/default.css                  |  256 ++
 documentation/_static/doctools.js                  |  235 ++
 documentation/_static/down-pressed.png             |  Bin 0 -> 368 bytes
 documentation/_static/down.png                     |  Bin 0 -> 363 bytes
 documentation/_static/file.png                     |  Bin 0 -> 392 bytes
 documentation/_static/jquery.js                    |    2 +
 documentation/_static/mathjax-use-tex-fonts.js     |    9 +
 documentation/_static/minus.png                    |  Bin 0 -> 199 bytes
 documentation/_static/plus.png                     |  Bin 0 -> 199 bytes
 documentation/_static/pygments.css                 |   62 +
 documentation/_static/searchtools.js               |  622 +++
 documentation/_static/sidebar.js                   |  159 +
 documentation/_static/underscore.js                |   31 +
 documentation/_static/up-pressed.png               |  Bin 0 -> 372 bytes
 documentation/_static/up.png                       |  Bin 0 -> 363 bytes
 documentation/_static/websupport.js                |  808 ++++
 documentation/_static/xmds_favicon.ico             |  Bin 0 -> 4286 bytes
 documentation/_static/xmds_logo.png                |  Bin 0 -> 30659 bytes
 documentation/advanced_topics.html                 |  304 ++
 documentation/developer.html                       |  263 ++
 documentation/doctrees/advanced_topics.doctree     |  Bin 0 -> 49357 bytes
 documentation/doctrees/developer.doctree           |  Bin 0 -> 62205 bytes
 documentation/doctrees/documentation_toc.doctree   |  Bin 0 -> 3907 bytes
 documentation/doctrees/environment.pickle          |  Bin 0 -> 71024 bytes
 documentation/doctrees/faq.doctree                 |  Bin 0 -> 27012 bytes
 documentation/doctrees/index.doctree               |  Bin 0 -> 43040 bytes
 documentation/doctrees/installation.doctree        |  Bin 0 -> 106138 bytes
 documentation/doctrees/introduction.doctree        |  Bin 0 -> 24126 bytes
 documentation/doctrees/licensing.doctree           |  Bin 0 -> 4724 bytes
 documentation/doctrees/news.doctree                |  Bin 0 -> 36964 bytes
 documentation/doctrees/optimisation_hints.doctree  |  Bin 0 -> 47781 bytes
 documentation/doctrees/reference_elements.doctree  |  Bin 0 -> 389993 bytes
 documentation/doctrees/reference_index.doctree     |  Bin 0 -> 3243 bytes
 ...eference_installation_and_configuration.doctree |  Bin 0 -> 12471 bytes
 documentation/doctrees/reference_schema.doctree    |  Bin 0 -> 66967 bytes
 .../doctrees/reference_usefulXMLSyntax.doctree     |  Bin 0 -> 4601 bytes
 documentation/doctrees/tutorial.doctree            |  Bin 0 -> 47952 bytes
 documentation/doctrees/upgrade.doctree             |  Bin 0 -> 6081 bytes
 documentation/doctrees/worked_examples.doctree     |  Bin 0 -> 186948 bytes
 documentation/doctrees/xsil2graphics2.doctree      |  Bin 0 -> 5377 bytes
 documentation/documentation_toc.html               |  164 +
 documentation/faq.html                             |  145 +
 documentation/genindex.html                        |   95 +
 documentation/index.html                           |  206 +
 documentation/installation.html                    |  370 ++
 documentation/introduction.html                    |  114 +
 documentation/latex/FourierTransformEx1.pdf        |  Bin 0 -> 77448 bytes
 documentation/latex/FourierTransformEx2.pdf        |  Bin 0 -> 176877 bytes
 documentation/latex/FourierTransformEx3.pdf        |  Bin 0 -> 160165 bytes
 documentation/latex/Makefile                       |   66 +
 documentation/latex/fibre1024.pdf                  |  Bin 0 -> 1368197 bytes
 documentation/latex/fibreSingle.pdf                |  Bin 0 -> 1567250 bytes
 documentation/latex/fncychap.sty                   |  683 +++
 documentation/latex/groundstateU2.pdf              |  Bin 0 -> 1098425 bytes
 documentation/latex/groundstateU20.pdf             |  Bin 0 -> 1238733 bytes
 documentation/latex/kubo10000.pdf                  |  Bin 0 -> 3957 bytes
 documentation/latex/kuboSingle.pdf                 |  Bin 0 -> 33828 bytes
 documentation/latex/lorenz.pdf                     |  Bin 0 -> 650829 bytes
 documentation/latex/python.ist                     |   11 +
 documentation/latex/sphinx.sty                     |  520 +++
 documentation/latex/sphinxhowto.cls                |  104 +
 documentation/latex/sphinxmanual.cls               |  147 +
 documentation/latex/tabulary.sty                   |  452 ++
 documentation/latex/xmds2.aux                      |  424 ++
 documentation/latex/xmds2.idx                      |    0
 documentation/latex/xmds2.ilg                      |    5 +
 documentation/latex/xmds2.ind                      |    0
 documentation/latex/xmds2.log                      | 1333 ++++++
 documentation/latex/xmds2.out                      |   53 +
 documentation/latex/xmds2.pdf                      |  Bin 0 -> 6678016 bytes
 documentation/latex/xmds2.tex                      | 4465 ++++++++++++++++++++
 documentation/latex/xmds2.toc                      |  128 +
 documentation/latex/xmds_logo.pdf                  |  Bin 0 -> 27201 bytes
 documentation/licensing.html                       |   93 +
 documentation/news.html                            |  193 +
 documentation/objects.inv                          |  Bin 0 -> 1588 bytes
 documentation/optimisation_hints.html              |  262 ++
 documentation/reference_elements.html              | 1126 +++++
 documentation/reference_index.html                 |  118 +
 .../reference_installation_and_configuration.html  |  118 +
 documentation/reference_schema.html                |  237 ++
 documentation/reference_usefulXMLSyntax.html       |  109 +
 documentation/search.html                          |  105 +
 documentation/searchindex.js                       |    1 +
 documentation/tutorial.html                        |  313 ++
 documentation/upgrade.html                         |   94 +
 documentation/worked_examples.html                 | 1280 ++++++
 documentation/xsil2graphics2.html                  |   93 +
 examples/2DMultistateSE.xmds                       |  103 +
 examples/NLProjection.xmds                         |   87 +
 examples/bessel_cosine_groundstate.xmds            |  128 +
 examples/bessel_cosine_stochastic_groundstate.xmds |  132 +
 examples/bessel_transform.xmds                     |   78 +
 examples/bessel_transform2.xmds                    |   80 +
 examples/cpc_ex_scaling.xmds                       |   75 +
 examples/cpc_example1.xmds                         |   75 +
 examples/cpc_example2.xmds                         |   77 +
 examples/cpc_example3.xmds                         |   75 +
 examples/cpc_example4.xmds                         |   79 +
 examples/cpc_example4_3d.xmds                      |   81 +
 examples/cpc_example5.xmds                         |  112 +
 examples/cpc_example6.xmds                         |   83 +
 examples/cpc_ip_scaling.xmds                       |   75 +
 examples/diffusion.xmds                            |   63 +
 examples/diffusion_arguments.xmds                  |   90 +
 examples/diffusion_dst.xmds                        |   63 +
 examples/diffusion_mpi.xmds                        |   71 +
 examples/diffusion_openmp.xmds                     |   70 +
 examples/diffusion_win.xmds                        |   62 +
 examples/excitedstate_gaussian.xmds                |  135 +
 examples/fibre.xmds                                |   72 +
 examples/fibre_noisevectors.xmds                   |   82 +
 examples/gravity.xmds                              |  107 +
 examples/groundstate_demo2.xmds                    |  168 +
 examples/groundstate_gaussian.xmds                 |  118 +
 examples/groundstate_workedexamples.xmds           |  126 +
 examples/halt_non_finite.xmds                      |   56 +
 examples/hermitegauss_groundstate.xmds             |  113 +
 examples/hermitegauss_transform.xmds               |   80 +
 examples/hermitegauss_transform_2d.xmds            |   99 +
 examples/hermitegauss_transform_2d_mpi.xmds        |  101 +
 examples/integer_dimensions.xmds                   |   58 +
 .../integer_dimensions_with_runtime_lattice.xmds   |   62 +
 examples/kubo.xmds                                 |   56 +
 examples/kubo_integer_dimensions.xmds              |   59 +
 examples/kubo_integer_dimensions_mpi.xmds          |   75 +
 examples/lorenz.xmds                               |   75 +
 examples/lorenz_arguments.xmds                     |   63 +
 examples/lorenz_code.txt                           |    5 +
 examples/lorenz_entity.xmds                        |   74 +
 examples/lorenz_lyap.xmds                          |  107 +
 examples/lorenz_minimal.xmds                       |   45 +
 examples/lorenz_single.xmds                        |   64 +
 examples/nlse.xmds                                 |  100 +
 examples/photodetector.xmds                        |   55 +
 examples/schroedinger_gaussian.xmds                |  103 +
 examples/sech_soliton.xmds                         |   63 +
 examples/sine_cross.xmds                           |  118 +
 examples/tla.xmds                                  |  100 +
 examples/tla_sic.xmds                              |  100 +
 examples/van_der_pol.xmds                          |   61 +
 examples/vibstring.xmds                            |   94 +
 examples/vibstring2.xmds                           |  113 +
 examples/vibstring3.xmds                           |  149 +
 examples/vibstring_circle.xmds                     |  101 +
 examples/vibstring_circle_mpi.xmds                 |  108 +
 examples/vibstring_circle_spectral.xmds            |  128 +
 examples/vibstring_dct.xmds                        |   90 +
 examples/vibstring_dirichlet_boundary.xmds         |  114 +
 examples/vibstring_dirichlet_boundary2.xmds        |   97 +
 examples/vibstring_ellipse.xmds                    |   98 +
 examples/wigner.xmds                               |  115 +
 examples/wigner_argument_mpi.xmds                  |  103 +
 examples/wigner_spectral.xmds                      |  121 +
 ez_setup.py                                        |  284 ++
 man/xmds2.1                                        |   73 +
 man/xsil2graphics2.1                               |   43 +
 run_tests.py                                       |  350 ++
 setup.py                                           |   57 +
 testsuite/fast/RbGS_expected.xsil                  |  369 ++
 testsuite/fast/RbGS_expected_mg0.dat               |  Bin 0 -> 328224 bytes
 testsuite/fast/RbGS_expected_mg1.dat               |  Bin 0 -> 66064 bytes
 testsuite/fast/RbGS_expected_mg2.dat               |  Bin 0 -> 80 bytes
 testsuite/fast/RbGS_expected_mg3.dat               |  Bin 0 -> 24 bytes
 testsuite/fast/RbGSa_expected.dat                  |  Bin 0 -> 1573668 bytes
 testsuite/fast/RbGSa_expected.xsil                 |  317 ++
 testsuite/fast/RbGSdipoles.xmds                    |  281 ++
 .../fast/anharmonic_oscillator_wigner_mpi.xmds     |  164 +
 .../anharmonic_oscillator_wigner_mpi_expected.xsil |  299 ++
 ...harmonic_oscillator_wigner_mpi_expected_mg0.dat |  Bin 0 -> 345016 bytes
 ...harmonic_oscillator_wigner_mpi_expected_mg1.dat |  Bin 0 -> 345016 bytes
 ...harmonic_oscillator_wigner_mpi_expected_mg2.dat |  Bin 0 -> 452452 bytes
 ...harmonic_oscillator_wigner_mpi_expected_mg3.dat |  Bin 0 -> 452452 bytes
 ...harmonic_oscillator_wigner_mpi_expected_mg4.dat |  Bin 0 -> 452452 bytes
 ...harmonic_oscillator_wigner_mpi_expected_mg5.dat |  Bin 0 -> 452452 bytes
 ...harmonic_oscillator_wigner_mpi_initial_even.dat |  Bin 0 -> 22200 bytes
 ...armonic_oscillator_wigner_mpi_initial_even.xsil |  199 +
 ...nharmonic_oscillator_wigner_mpi_initial_odd.dat |  Bin 0 -> 22200 bytes
 ...harmonic_oscillator_wigner_mpi_initial_odd.xsil |  199 +
 .../anharmonic_oscillator_wigner_mpi_parsing.xmds  |  162 +
 testsuite/fast/bessel_cosine_evolution.xmds        |  102 +
 testsuite/fast/bessel_cosine_evolution_expected.h5 |  Bin 0 -> 91864 bytes
 .../fast/bessel_cosine_evolution_expected.xsil     |  128 +
 testsuite/fast/bessel_cosine_groundstate.xmds      |  134 +
 ...essel_cosine_groundstate_breakpoint_expected.h5 |  Bin 0 -> 26344 bytes
 ...sel_cosine_groundstate_breakpoint_expected.xsil |  164 +
 .../fast/bessel_cosine_groundstate_expected.xsil   |  165 +
 .../bessel_cosine_groundstate_expected_mg0.dat     |  Bin 0 -> 820544 bytes
 testsuite/fast/eigenvalues.xmds                    |  152 +
 testsuite/fast/eigenvalues_break_expected.h5       |  Bin 0 -> 18832 bytes
 testsuite/fast/eigenvalues_break_expected.xsil     |  176 +
 testsuite/fast/eigenvalues_expected.h5             |  Bin 0 -> 192800 bytes
 testsuite/fast/eigenvalues_expected.xsil           |  194 +
 testsuite/fast/groundstate.xmds                    |  126 +
 testsuite/fast/groundstate_expected.xsil           |  184 +
 testsuite/fast/groundstate_expected_break.dat      |  Bin 0 -> 40980 bytes
 testsuite/fast/groundstate_expected_break.xsil     |  149 +
 testsuite/fast/groundstate_expected_mg0.dat        |  Bin 0 -> 418204 bytes
 testsuite/fast/groundstate_expected_mg1.dat        |  Bin 0 -> 808 bytes
 testsuite/fast/groundstate_expected_mg2.dat        |  Bin 0 -> 808 bytes
 testsuite/fast/lorenz.xmds                         |   63 +
 testsuite/fast/lorenz_expected.xsil                |  587 +++
 testsuite/fast/potential_expected.dat              |  Bin 0 -> 262928 bytes
 testsuite/fast/potential_expected.xsil             |  318 ++
 testsuite/fast/tla.xmds                            |  103 +
 testsuite/fast/tla_expected.xsil                   |  144 +
 testsuite/fast/tla_expected_mg0.dat                |  Bin 0 -> 1624840 bytes
 testsuite/fast/tla_expected_mg1.dat                |  Bin 0 -> 3208848 bytes
 ...verse_integration_in_vector_initialisation.xmds |   48 +
 ...ntegration_in_vector_initialisation_expected.h5 |  Bin 0 -> 2856 bytes
 ...egration_in_vector_initialisation_expected.xsil |   70 +
 testsuite/fast/vibstring_circle_spectral.xmds      |  130 +
 .../fast/vibstring_circle_spectral_expected.xsil   |  209 +
 .../vibstring_circle_spectral_expected_mg0.dat     |  Bin 0 -> 49728 bytes
 .../vibstring_circle_spectral_expected_mg1.dat     |  Bin 0 -> 49728 bytes
 .../vibstring_circle_spectral_expected_mg2.dat     |  Bin 0 -> 1624 bytes
 testsuite/features/arguments.xmds                  |   94 +
 ...e.n_1.sigma_2e-6.stringTest_mollusc_expected.h5 |  Bin 0 -> 21968 bytes
 ...n_1.sigma_2e-6.stringTest_mollusc_expected.xsil |  170 +
 .../arguments_append_args_to_output_filename.xmds  |  147 +
 testsuite/features/arguments_expected.xsil         |  127 +
 testsuite/features/arguments_expected_mg0.dat      |  Bin 0 -> 26836 bytes
 .../features/arguments_with_similar_names.xmds     |   71 +
 .../arguments_with_similar_names_expected.xsil     |  101 +
 .../arguments_with_similar_names_expected_mg0.dat  |  Bin 0 -> 416 bytes
 ...k.n_1.sigma_2e-6.stringTest_mollusc_expected.h5 |  Bin 0 -> 15136 bytes
 ...n_1.sigma_2e-6.stringTest_mollusc_expected.xsil |  173 +
 testsuite/features/error_check_multipath.xmds      |   67 +
 .../features/error_check_multipath_expected.xsil   |   93 +
 .../error_check_multipath_expected_mg0.dat         |  Bin 0 -> 22604 bytes
 testsuite/features/halt_non_finite.xmds            |   60 +
 testsuite/features/halt_non_finite_expected.xsil   |   82 +
 .../features/halt_non_finite_expected_mg0.dat      |  Bin 0 -> 3232 bytes
 ...s_transform_2d_chunked_breakpoint1_expected.dat |  Bin 0 -> 6752 bytes
 ..._transform_2d_chunked_breakpoint1_expected.xsil |  141 +
 ...s_transform_2d_chunked_breakpoint2_expected.dat |  Bin 0 -> 6752 bytes
 ..._transform_2d_chunked_breakpoint2_expected.xsil |  141 +
 ...s_transform_2d_chunked_breakpoint3_expected.dat |  Bin 0 -> 6752 bytes
 ..._transform_2d_chunked_breakpoint3_expected.xsil |  141 +
 ...s_transform_2d_chunked_breakpoint4_expected.dat |  Bin 0 -> 6752 bytes
 ..._transform_2d_chunked_breakpoint4_expected.xsil |  141 +
 ...mitegauss_transform_2d_chunked_breakpoints.xmds |  119 +
 ...auss_transform_2d_chunked_breakpoints_hdf5.xmds |  119 +
 testsuite/features/realistic_Rb_and_fields.xmds    |  641 +++
 .../features/realistic_Rb_and_fields_expected.xsil |  680 +++
 .../realistic_Rb_and_fields_expected_mg0.dat       |  Bin 0 -> 136096 bytes
 testsuite/features/runtime_paths.xmds              |   57 +
 testsuite/features/runtime_paths_expected.h5       |  Bin 0 -> 2864 bytes
 testsuite/features/runtime_paths_expected.xsil     |   81 +
 testsuite/features/space in filename.xmds          |   96 +
 testsuite/geometry/integer_dimensions.xmds         |   61 +
 .../geometry/integer_dimensions_expected.xsil      |   88 +
 .../geometry/integer_dimensions_expected_mg0.dat   |  Bin 0 -> 4900 bytes
 .../geometry/integer_dimensions_reordered.xmds     |   62 +
 .../integer_dimensions_reordered_expected.xsil     |   89 +
 .../integer_dimensions_reordered_expected_mg0.dat  |  Bin 0 -> 4900 bytes
 .../geometry/nonlocal_edge_uniform_access.xmds     |   80 +
 .../nonlocal_edge_uniform_access_expected.h5       |  Bin 0 -> 34752 bytes
 .../nonlocal_edge_uniform_access_expected.xsil     |  103 +
 testsuite/geometry/nonlocal_index_access.xmds      |   80 +
 .../geometry/nonlocal_index_access_expected.h5     |  Bin 0 -> 34752 bytes
 .../geometry/nonlocal_index_access_expected.xsil   |  103 +
 .../geometry/nonlocal_negative_uniform_access.xmds |   80 +
 .../nonlocal_negative_uniform_access_expected.h5   |  Bin 0 -> 34752 bytes
 .../nonlocal_negative_uniform_access_expected.xsil |  102 +
 .../geometry/nonlocal_split_uniform_access.xmds    |   80 +
 .../nonlocal_split_uniform_access_expected.xsil    |  104 +
 .../nonlocal_split_uniform_access_expected_mg0.dat |  Bin 0 -> 26688 bytes
 .../integrators/bug_adaptive_timestep_hang.xmds    |  252 ++
 .../bug_adaptive_timestep_hang_expected.h5         |  Bin 0 -> 31520 bytes
 .../bug_adaptive_timestep_hang_expected.xsil       |  310 ++
 testsuite/integrators/vibstring_ark45.xmds         |   85 +
 testsuite/integrators/vibstring_ark89.xmds         |   85 +
 testsuite/integrators/vibstring_expected.xsil      |  132 +
 testsuite/integrators/vibstring_expected_mg0.dat   |  Bin 0 -> 42020 bytes
 testsuite/integrators/vibstring_expected_mg1.dat   |  Bin 0 -> 20812 bytes
 testsuite/integrators/vibstring_rk4.xmds           |   85 +
 testsuite/integrators/vibstring_rk45.xmds          |   85 +
 testsuite/integrators/vibstring_rk89.xmds          |   85 +
 testsuite/integrators/vibstring_rk9.xmds           |   85 +
 testsuite/integrators/vibstring_si.xmds            |   85 +
 testsuite/io/breakpoints.xmds                      |   68 +
 testsuite/io/breakpoints_2d_xspace_expected.dat    |  Bin 0 -> 412464 bytes
 testsuite/io/breakpoints_2d_xspace_expected.xsil   |   99 +
 testsuite/io/breakpoints_hdf5.xmds                 |   72 +
 .../io/breakpoints_hdf5_2d_xspace_expected.h5      |  Bin 0 -> 422272 bytes
 .../io/breakpoints_hdf5_2d_xspace_expected.xsil    |   95 +
 testsuite/io/breakpoints_hdf5_kspace_expected.h5   |  Bin 0 -> 10296 bytes
 testsuite/io/breakpoints_hdf5_kspace_expected.xsil |   94 +
 .../io/breakpoints_hdf5_mixed_space1_expected.h5   |  Bin 0 -> 422272 bytes
 .../io/breakpoints_hdf5_mixed_space1_expected.xsil |   95 +
 .../io/breakpoints_hdf5_mixed_space2_expected.h5   |  Bin 0 -> 422272 bytes
 .../io/breakpoints_hdf5_mixed_space2_expected.xsil |   95 +
 testsuite/io/breakpoints_hdf5_xspace_expected.h5   |  Bin 0 -> 10296 bytes
 testsuite/io/breakpoints_hdf5_xspace_expected.xsil |   94 +
 testsuite/io/breakpoints_kspace_expected.dat       |  Bin 0 -> 2412 bytes
 testsuite/io/breakpoints_kspace_expected.xsil      |   98 +
 testsuite/io/breakpoints_mixed_space1_expected.dat |  Bin 0 -> 412464 bytes
 .../io/breakpoints_mixed_space1_expected.xsil      |   99 +
 testsuite/io/breakpoints_mixed_space2_expected.dat |  Bin 0 -> 412464 bytes
 .../io/breakpoints_mixed_space2_expected.xsil      |   99 +
 testsuite/io/breakpoints_xspace_expected.dat       |  Bin 0 -> 2412 bytes
 testsuite/io/breakpoints_xspace_expected.xsil      |   98 +
 testsuite/io/mpi_xsilloading.xmds                  |   61 +
 testsuite/io/mpi_xsilloading_hdf5.xmds             |   61 +
 testsuite/io/mpi_xsilloading_hdf5_loose.xmds       |   61 +
 testsuite/io/mpi_xsilloading_hdf5_loose2.xmds      |   61 +
 testsuite/io/mpi_xsilloading_loose.xmds            |   61 +
 testsuite/io/mpi_xsilloading_loose2.xmds           |   61 +
 testsuite/io/nlse_sampling.xmds                    |  103 +
 testsuite/io/nlse_sampling_expected.h5             |  Bin 0 -> 37296 bytes
 testsuite/io/nlse_sampling_expected.xsil           |  160 +
 testsuite/io/xsilloading.xmds                      |   58 +
 testsuite/io/xsilloading_expected.xsil             |   85 +
 testsuite/io/xsilloading_expected2.xsil            |   80 +
 testsuite/io/xsilloading_expected2_mg0.dat         |  Bin 0 -> 816 bytes
 testsuite/io/xsilloading_expected_mg0.dat          |  Bin 0 -> 808 bytes
 testsuite/io/xsilloading_hdf5.xmds                 |   58 +
 testsuite/io/xsilloading_hdf5_loose.xmds           |   58 +
 testsuite/io/xsilloading_hdf5_loose2.xmds          |   58 +
 testsuite/io/xsilloading_loose.xmds                |   58 +
 testsuite/io/xsilloading_loose2.xmds               |   58 +
 testsuite/mpi/diffusion_mpi.xmds                   |   75 +
 testsuite/mpi/diffusion_mpi_chunked.xmds           |   75 +
 testsuite/mpi/diffusion_mpi_expected.xsil          |  127 +
 testsuite/mpi/diffusion_mpi_expected_mg0.dat       |  Bin 0 -> 26836 bytes
 testsuite/mpi/diffusion_mpi_expected_mg1.dat       |  Bin 0 -> 1313848 bytes
 testsuite/mpi/eigenvalues.xmds                     |  155 +
 testsuite/mpi/fibre_integer_dimensions_mpi.xmds    |   89 +
 .../mpi/fibre_integer_dimensions_mpi_expected.xsil |  112 +
 .../fibre_integer_dimensions_mpi_expected_mg0.dat  |  Bin 0 -> 53176 bytes
 ...ibre_integer_dimensions_mpi_kspace_expected.dat |  Bin 0 -> 4672 bytes
 ...bre_integer_dimensions_mpi_kspace_expected.xsil |  112 +
 ...ibre_integer_dimensions_mpi_xspace_expected.dat |  Bin 0 -> 4672 bytes
 ...bre_integer_dimensions_mpi_xspace_expected.xsil |  112 +
 testsuite/mpi/hermitegauss_transform_2d_mpi.xmds   |  107 +
 .../hermitegauss_transform_2d_mpi_expected.xsil    |  166 +
 .../hermitegauss_transform_2d_mpi_expected_mg0.dat |  Bin 0 -> 9080 bytes
 .../hermitegauss_transform_2d_mpi_expected_mg1.dat |  Bin 0 -> 984 bytes
 .../hermitegauss_transform_2d_mpi_expected_mg2.dat |  Bin 0 -> 2448 bytes
 .../mpi/hermitegauss_transform_2d_mpi_small.xmds   |  109 +
 testsuite/mpi/kubo_integer_dimensions_mpi.xmds     |   74 +
 .../kubo_integer_dimensions_mpi_break_expected.dat |  Bin 0 -> 24600 bytes
 ...kubo_integer_dimensions_mpi_break_expected.xsil |  100 +
 .../mpi/kubo_integer_dimensions_mpi_expected.xsil  |  118 +
 .../kubo_integer_dimensions_mpi_expected_mg0.dat   |  Bin 0 -> 12048 bytes
 .../kubo_integer_dimensions_mpi_expected_mg1.dat   |  Bin 0 -> 188536 bytes
 testsuite/mpi/kubo_mpi_paths.xmds                  |   57 +
 testsuite/mpi/kubo_mpi_paths_expected.xsil         |   86 +
 testsuite/mpi/kubo_mpi_paths_expected_mg0.dat      |  Bin 0 -> 2080 bytes
 testsuite/mpi/lorenz_mpi.xmds                      |   91 +
 testsuite/mpi/lorenz_mpi_expected.xsil             |  116 +
 testsuite/mpi/lorenz_mpi_expected_mg0.dat          |  Bin 0 -> 1608 bytes
 testsuite/mpi/mpi_dft.xmds                         |   72 +
 testsuite/mpi/mpi_dft_hdf5.xmds                    |   72 +
 testsuite/mpi/mpi_dft_kspace2_expected.dat         |  Bin 0 -> 16912 bytes
 testsuite/mpi/mpi_dft_kspace2_expected.xsil        |   97 +
 testsuite/mpi/mpi_dft_kspace_expected.dat          |  Bin 0 -> 16912 bytes
 testsuite/mpi/mpi_dft_kspace_expected.xsil         |   93 +
 testsuite/mpi/mpi_dft_small.xmds                   |   74 +
 testsuite/mpi/mpi_dft_small_kspace2_expected.dat   |  Bin 0 -> 1792 bytes
 testsuite/mpi/mpi_dft_small_kspace2_expected.xsil  |   98 +
 testsuite/mpi/mpi_dft_small_kspace_expected.dat    |  Bin 0 -> 1792 bytes
 testsuite/mpi/mpi_dft_small_kspace_expected.xsil   |   98 +
 testsuite/mpi/mpi_dft_small_xspace_expected.dat    |  Bin 0 -> 1792 bytes
 testsuite/mpi/mpi_dft_small_xspace_expected.xsil   |   98 +
 testsuite/mpi/mpi_dft_xspace_expected.dat          |  Bin 0 -> 16912 bytes
 testsuite/mpi/mpi_dft_xspace_expected.xsil         |   93 +
 testsuite/mpi/mpi_highdimcrossprop.xmds            |  226 +
 testsuite/mpi/nonlocal_access_test_expected.h5     |  Bin 0 -> 170128 bytes
 testsuite/mpi/nonlocal_access_test_expected.xsil   |  135 +
 .../mpi/partial_integration_computed_vector.xmds   |  179 +
 testsuite/mpi/vibstring_dst_mpi.xmds               |   87 +
 testsuite/mpi/vibstring_dst_mpi_chunked.xmds       |   86 +
 testsuite/mpi/vibstring_dst_mpi_expected.xsil      |  140 +
 testsuite/mpi/vibstring_dst_mpi_expected_mg0.dat   |  Bin 0 -> 49728 bytes
 testsuite/mpi/vibstring_dst_mpi_expected_mg1.dat   |  Bin 0 -> 49728 bytes
 testsuite/mpi/vibstring_mpi_aliases.xmds           |  113 +
 testsuite/mpi/vibstring_mpi_aliases_expected.h5    |  Bin 0 -> 141968 bytes
 testsuite/mpi/vibstring_mpi_aliases_expected.xsil  |  153 +
 testsuite/openmp/bessel_cosine_groundstate.xmds    |  136 +
 testsuite/openmp/diffusion_openmp.xmds             |   73 +
 testsuite/openmp/diffusion_openmp_chunked.xmds     |   73 +
 testsuite/openmp/eigenvalues.xmds                  |  153 +
 .../openmp/hermitegauss_transform_2d_openmp.xmds   |  105 +
 .../hermitegauss_transform_2d_openmp_small.xmds    |  107 +
 .../openmp/kubo_integer_dimensions_openmp.xmds     |   75 +
 ...bo_integer_dimensions_openmp_break_expected.dat |  Bin 0 -> 24600 bytes
 ...o_integer_dimensions_openmp_break_expected.xsil |   97 +
 .../kubo_integer_dimensions_openmp_expected.xsil   |  115 +
 ...kubo_integer_dimensions_openmp_expected_mg0.dat |  Bin 0 -> 12048 bytes
 ...kubo_integer_dimensions_openmp_expected_mg1.dat |  Bin 0 -> 188536 bytes
 testsuite/openmp/lorenz_openmp.xmds                |   84 +
 testsuite/openmp/openmp_dft.xmds                   |   70 +
 testsuite/openmp/openmp_dft_hdf5.xmds              |   70 +
 testsuite/openmp/openmp_dft_small.xmds             |   72 +
 testsuite/openmp/openmp_highdimcrossprop.xmds      |  225 +
 .../partial_integration_computed_vector.xmds       |  178 +
 testsuite/openmp/vibstring_dst_openmp.xmds         |   85 +
 testsuite/openmp/vibstring_dst_openmp_chunked.xmds |   84 +
 testsuite/operators/constant_complex_ip.xmds       |   64 +
 testsuite/operators/constant_double_ip.xmds        |   64 +
 testsuite/operators/constant_ex.xmds               |   64 +
 .../operators/constant_ex_arbitrary_code.xmds      |   65 +
 .../operators/constant_ex_arbitrary_order.xmds     |   67 +
 .../operators/constant_ex_arbitrary_order2.xmds    |   67 +
 .../constant_ex_arbitrary_order_expected.xsil      |   90 +
 .../constant_ex_arbitrary_order_expected_mg0.dat   |  Bin 0 -> 52456 bytes
 testsuite/operators/cross_propagation.xmds         |  128 +
 testsuite/operators/cross_propagation2.xmds        |   96 +
 .../operators/cross_propagation2_expected.xsil     |  119 +
 .../operators/cross_propagation2_expected_mg0.dat  |  Bin 0 -> 3084 bytes
 .../operators/cross_propagation_expected.xsil      |  151 +
 .../operators/cross_propagation_expected_mg0.dat   |  Bin 0 -> 5140 bytes
 testsuite/operators/cross_propagation_right.xmds   |  128 +
 .../cross_propagation_right_expected.xsil          |  151 +
 .../cross_propagation_right_expected_mg0.dat       |  Bin 0 -> 5140 bytes
 testsuite/operators/cross_propagation_sic.xmds     |  109 +
 .../operators/cross_propagation_sic_expected.xsil  |  133 +
 .../cross_propagation_sic_expected_mg0.dat         |  Bin 0 -> 3084 bytes
 .../operators/cross_propagation_sic_right.xmds     |  109 +
 .../cross_propagation_sic_right_expected.xsil      |  132 +
 .../cross_propagation_sic_right_expected_mg0.dat   |  Bin 0 -> 3084 bytes
 testsuite/operators/derivative_expected.xsil       |   88 +
 testsuite/operators/derivative_expected_mg0.dat    |  Bin 0 -> 26836 bytes
 testsuite/operators/highdimcrossprop.xmds          |  222 +
 testsuite/operators/highdimcrossprop_expected.h5   |  Bin 0 -> 6471360 bytes
 testsuite/operators/highdimcrossprop_expected.xsil |  412 ++
 testsuite/operators/nonconstant_complex_ip.xmds    |   64 +
 testsuite/operators/nonconstant_double_ip.xmds     |   64 +
 testsuite/operators/nonconstant_ex.xmds            |   64 +
 testsuite/runtime_lattice/breakpoints_hdf5.xmds    |   73 +
 testsuite/runtime_lattice/integer_dimensions.xmds  |   66 +
 .../integer_dimensions_with_fixed_lattice.xmds     |   66 +
 .../integer_dimensions_with_runtime_lattice.xmds   |   66 +
 .../runtime_lattice_diffusion_dst.xmds             |   71 +
 .../runtime_lattice_initialisation_order.xmds      |  163 +
 .../runtime_lattice_mpi_dft_small.xmds             |   80 +
 ...time_lattice_nonlocal_split_uniform_access.xmds |   85 +
 .../runtime_lattice_vibstring_ark89.xmds           |   92 +
 .../runtime_lattice_xsilloading_hdf5_loose2.xmds   |   65 +
 .../bessel_cosine_stochastic_groundstate.xmds      |  132 +
 ...essel_cosine_stochastic_groundstate_expected.h5 |  Bin 0 -> 832120 bytes
 ...sel_cosine_stochastic_groundstate_expected.xsil |  158 +
 .../stochastic/double_precision_noise_tests.xmds   |  129 +
 .../double_precision_noise_tests_expected.h5       |  Bin 0 -> 90464 bytes
 .../double_precision_noise_tests_expected.xsil     |  152 +
 testsuite/stochastic/dsfmt_single_precision.xmds   |   88 +
 .../stochastic/dsfmt_single_precision_expected.h5  |  Bin 0 -> 22960 bytes
 .../dsfmt_single_precision_expected.xsil           |  111 +
 testsuite/stochastic/fibre.xmds                    |   71 +
 testsuite/stochastic/fibre_expected.xsil           |   95 +
 testsuite/stochastic/fibre_expected_mg0.dat        |  Bin 0 -> 27044 bytes
 .../fibre_with_correlation_function_expected.xsil  |  147 +
 ...ibre_with_correlation_function_expected_mg0.dat |  Bin 0 -> 27044 bytes
 ...ibre_with_correlation_function_expected_mg1.dat |  Bin 0 -> 66576 bytes
 ...ibre_with_correlation_function_expected_mg2.dat |  Bin 0 -> 99348 bytes
 .../fibre_with_correlation_functions.xmds          |   89 +
 testsuite/stochastic/kubo.xmds                     |   56 +
 testsuite/stochastic/kubo_expected.xsil            |   80 +
 testsuite/stochastic/kubo_expected_mg0.dat         |  Bin 0 -> 2060 bytes
 testsuite/stochastic/kubo_fixedstep.xmds           |   56 +
 testsuite/stochastic/kubo_fixedstep_expected.xsil  |   82 +
 .../stochastic/kubo_fixedstep_expected_mg0.dat     |  Bin 0 -> 20060 bytes
 testsuite/stochastic/photodetector.xmds            |   51 +
 testsuite/stochastic/photodetector_bessel.xmds     |   63 +
 .../stochastic/photodetector_bessel_expected.h5    |  Bin 0 -> 116048 bytes
 .../stochastic/photodetector_bessel_expected.xsil  |  103 +
 testsuite/stochastic/photodetector_expected.h5     |  Bin 0 -> 25008 bytes
 testsuite/stochastic/photodetector_expected.xsil   |   73 +
 testsuite/stochastic/photodetector_linear.xmds     |   61 +
 .../stochastic/photodetector_linear_expected.h5    |  Bin 0 -> 116048 bytes
 .../stochastic/photodetector_linear_expected.xsil  |  101 +
 testsuite/stochastic/wigner_cool_HO.xmds           |  124 +
 testsuite/stochastic/wigner_cool_HO_expected.xsil  |  145 +
 .../stochastic/wigner_cool_HO_expected_mg0.dat     |  Bin 0 -> 3708 bytes
 testsuite/transforms/bessel_transform.xmds         |   82 +
 .../transforms/bessel_transform_expected.xsil      |  126 +
 .../transforms/bessel_transform_expected_mg0.dat   |  Bin 0 -> 82420 bytes
 .../transforms/bessel_transform_expected_mg1.dat   |  Bin 0 -> 81612 bytes
 .../transforms/bessel_transform_rectangular.xmds   |   82 +
 .../bessel_transform_rectangular_expected.xsil     |  125 +
 .../bessel_transform_rectangular_expected_mg0.dat  |  Bin 0 -> 82432 bytes
 .../bessel_transform_rectangular_expected_mg1.dat  |  Bin 0 -> 30208 bytes
 testsuite/transforms/diffusion_bessel.xmds         |   70 +
 .../transforms/diffusion_bessel_expected.xsil      |   97 +
 .../transforms/diffusion_bessel_expected_mg0.dat   |  Bin 0 -> 25768 bytes
 testsuite/transforms/diffusion_dst.xmds            |   66 +
 testsuite/transforms/diffusion_dst_expected.xsil   |   93 +
 .../transforms/diffusion_dst_expected_mg0.dat      |  Bin 0 -> 101784 bytes
 testsuite/transforms/disc.xmds                     |   58 +
 .../transforms/disc_coordinate_space1_expected.h5  |  Bin 0 -> 13088 bytes
 .../disc_coordinate_space1_expected.xsil           |   79 +
 .../transforms/disc_coordinate_space_expected.h5   |  Bin 0 -> 13088 bytes
 .../transforms/disc_coordinate_space_expected.xsil |   79 +
 testsuite/transforms/disc_expected.h5              |  Bin 0 -> 2856 bytes
 testsuite/transforms/disc_expected.xsil            |   78 +
 .../transforms/disc_spectral_space_expected.h5     |  Bin 0 -> 13088 bytes
 .../transforms/disc_spectral_space_expected.xsil   |   79 +
 testsuite/transforms/hermitegauss_fourier.xmds     |   63 +
 .../transforms/hermitegauss_fourier_1_expected.h5  |  Bin 0 -> 9664 bytes
 .../hermitegauss_fourier_1_expected.xsil           |   84 +
 .../transforms/hermitegauss_fourier_2_expected.h5  |  Bin 0 -> 9664 bytes
 .../hermitegauss_fourier_2_expected.xsil           |   84 +
 .../transforms/hermitegauss_fourier_3_expected.h5  |  Bin 0 -> 9664 bytes
 .../hermitegauss_fourier_3_expected.xsil           |   84 +
 .../transforms/hermitegauss_fourier_loading.xmds   |   49 +
 .../hermitegauss_fourier_loading_break_expected.h5 |  Bin 0 -> 14240 bytes
 ...ermitegauss_fourier_loading_break_expected.xsil |   71 +
 .../transforms/hermitegauss_transform_2d.xmds      |  104 +
 .../hermitegauss_transform_2d_chunked.xmds         |  103 +
 .../hermitegauss_transform_2d_expected.xsil        |  172 +
 .../hermitegauss_transform_2d_expected_mg0.dat     |  Bin 0 -> 35624 bytes
 .../hermitegauss_transform_2d_expected_mg1.dat     |  Bin 0 -> 3532 bytes
 .../hermitegauss_transform_2d_expected_mg2.dat     |  Bin 0 -> 2436 bytes
 testsuite/transforms/spherical_ball.xmds           |   58 +
 .../spherical_ball_coordinate_space1_expected.h5   |  Bin 0 -> 13088 bytes
 .../spherical_ball_coordinate_space1_expected.xsil |   79 +
 .../spherical_ball_coordinate_space_expected.h5    |  Bin 0 -> 13088 bytes
 .../spherical_ball_coordinate_space_expected.xsil  |   79 +
 testsuite/transforms/spherical_ball_expected.h5    |  Bin 0 -> 2856 bytes
 testsuite/transforms/spherical_ball_expected.xsil  |   78 +
 .../spherical_ball_spectral_space_expected.h5      |  Bin 0 -> 13088 bytes
 .../spherical_ball_spectral_space_expected.xsil    |   79 +
 testsuite/transforms/vibstring_dct.xmds            |   93 +
 testsuite/transforms/vibstring_dct_expected.xsil   |  141 +
 .../transforms/vibstring_dct_expected_mg0.dat      |  Bin 0 -> 41624 bytes
 .../transforms/vibstring_dct_expected_mg1.dat      |  Bin 0 -> 40816 bytes
 testsuite/vectors/initialisation_order.xmds        |  158 +
 .../vectors/initialisation_order_chunked.xmds      |  159 +
 testsuite/vectors/initialisation_order_expected.h5 |  Bin 0 -> 434560 bytes
 .../vectors/initialisation_order_expected.xsil     |  190 +
 .../partial_integration_computed_vector.xmds       |  176 +
 xpdeint/CallOnceGuards.py                          |  103 +
 xpdeint/CheetahTemplateOptions.mk                  |    1 +
 xpdeint/CodeParser.py                              |  648 +++
 xpdeint/Configuration.py                           |  223 +
 xpdeint/Features/Arguments.py                      |  583 +++
 xpdeint/Features/Arguments.tmpl                    |  186 +
 xpdeint/Features/AsciiFormat.py                    |  349 ++
 xpdeint/Features/AsciiFormat.tmpl                  |  103 +
 xpdeint/Features/AutoVectorise.py                  |  219 +
 xpdeint/Features/AutoVectorise.tmpl                |   36 +
 xpdeint/Features/Benchmark.py                      |  247 ++
 xpdeint/Features/Benchmark.tmpl                    |   41 +
 xpdeint/Features/BinaryFormat.py                   |  642 +++
 xpdeint/Features/BinaryFormat.tmpl                 |  235 ++
 xpdeint/Features/Bing.py                           |  212 +
 xpdeint/Features/Bing.tmpl                         |   31 +
 xpdeint/Features/CFlags.py                         |  212 +
 xpdeint/Features/CFlags.tmpl                       |   31 +
 xpdeint/Features/ChunkedOutput.py                  |  406 ++
 xpdeint/Features/ChunkedOutput.tmpl                |   87 +
 xpdeint/Features/Diagnostics.py                    |  449 ++
 xpdeint/Features/Diagnostics.tmpl                  |  101 +
 xpdeint/Features/ErrorCheck.py                     |  604 +++
 xpdeint/Features/ErrorCheck.tmpl                   |  164 +
 xpdeint/Features/Globals.py                        |  217 +
 xpdeint/Features/Globals.tmpl                      |   34 +
 xpdeint/Features/HDF5Format.py                     |  630 +++
 xpdeint/Features/HDF5Format.tmpl                   |  193 +
 xpdeint/Features/HaltNonFinite.py                  |  256 ++
 xpdeint/Features/HaltNonFinite.tmpl                |   56 +
 xpdeint/Features/MaxIterations.py                  |  174 +
 xpdeint/Features/MaxIterations.tmpl                |   46 +
 xpdeint/Features/OpenMP.py                         |  542 +++
 xpdeint/Features/OpenMP.tmpl                       |  186 +
 xpdeint/Features/Output.py                         |  538 +++
 xpdeint/Features/Output.tmpl                       |  125 +
 xpdeint/Features/OutputFormat.py                   |  694 +++
 xpdeint/Features/OutputFormat.tmpl                 |  212 +
 xpdeint/Features/Stochastic.py                     |  786 ++++
 xpdeint/Features/Stochastic.tmpl                   |  252 ++
 xpdeint/Features/Transforms/Basis.py               |  538 +++
 xpdeint/Features/Transforms/Basis.tmpl             |  114 +
 xpdeint/Features/Transforms/BesselBasis.py         |  286 ++
 xpdeint/Features/Transforms/BesselBasis.tmpl       |   42 +
 xpdeint/Features/Transforms/EPBasis.py             |  804 ++++
 xpdeint/Features/Transforms/EPBasis.tmpl           |  193 +
 .../Features/Transforms/FourierTransformFFTW3.py   |  777 ++++
 .../Features/Transforms/FourierTransformFFTW3.tmpl |  238 ++
 .../Transforms/FourierTransformFFTW3MPI.py         | 1296 ++++++
 .../Transforms/FourierTransformFFTW3MPI.tmpl       |  364 ++
 .../Transforms/FourierTransformFFTW3Threads.py     |  291 ++
 .../Transforms/FourierTransformFFTW3Threads.tmpl   |   46 +
 xpdeint/Features/Transforms/HermiteGaussEPBasis.py |  367 ++
 .../Features/Transforms/HermiteGaussEPBasis.tmpl   |   64 +
 .../Transforms/HermiteGaussFourierEPBasis.py       |  314 ++
 .../Transforms/HermiteGaussFourierEPBasis.tmpl     |   50 +
 .../Transforms/HermiteGaussTwiddleBasis.py         |  297 ++
 .../Transforms/HermiteGaussTwiddleBasis.tmpl       |   79 +
 xpdeint/Features/Transforms/MMT.py                 |  424 ++
 xpdeint/Features/Transforms/MMT.tmpl               |  100 +
 xpdeint/Features/Transforms/NoTransformMPI.py      |  311 ++
 xpdeint/Features/Transforms/NoTransformMPI.tmpl    |   62 +
 .../Features/Transforms/TransformMultiplexer.py    |  751 ++++
 .../Features/Transforms/TransformMultiplexer.tmpl  |  260 ++
 .../Features/Transforms/_FourierTransformFFTW3.py  |  209 +
 .../Transforms/_FourierTransformFFTW3MPI.py        |  216 +
 xpdeint/Features/Transforms/_MMT.py                |  365 ++
 xpdeint/Features/Transforms/_NoTransform.py        |   58 +
 xpdeint/Features/Transforms/_NoTransformMPI.py     |   48 +
 xpdeint/Features/Transforms/_Transform.py          |   75 +
 .../Features/Transforms/_TransformMultiplexer.py   |  517 +++
 xpdeint/Features/Transforms/__init__.py            |   21 +
 xpdeint/Features/Validation.py                     |  221 +
 xpdeint/Features/Validation.tmpl                   |   40 +
 xpdeint/Features/_AutoVectorise.py                 |   94 +
 xpdeint/Features/_ChunkedOutput.py                 |   74 +
 xpdeint/Features/_Diagnostics.py                   |   67 +
 xpdeint/Features/_ErrorCheck.py                    |   50 +
 xpdeint/Features/_Feature.py                       |   34 +
 xpdeint/Features/_HDF5Format.py                    |   32 +
 xpdeint/Features/_Stochastic.py                    |   52 +
 xpdeint/Features/_Validation.py                    |   35 +
 xpdeint/Features/__init__.py                       |   30 +
 xpdeint/FriendlyPlusStyle.py                       |   36 +
 xpdeint/Function.py                                |  115 +
 xpdeint/Geometry/BesselDimensionRepresentation.py  |  405 ++
 .../Geometry/BesselDimensionRepresentation.tmpl    |   69 +
 xpdeint/Geometry/DimensionRepresentation.py        |  300 ++
 xpdeint/Geometry/DimensionRepresentation.tmpl      |   71 +
 xpdeint/Geometry/FieldElement.py                   |  229 +
 xpdeint/Geometry/FieldElement.tmpl                 |   40 +
 xpdeint/Geometry/GeometryElement.py                |  187 +
 xpdeint/Geometry/GeometryElement.tmpl              |   30 +
 .../HermiteGaussDimensionRepresentation.py         |  328 ++
 .../HermiteGaussDimensionRepresentation.tmpl       |   51 +
 .../Geometry/NonUniformDimensionRepresentation.py  |  571 +++
 .../NonUniformDimensionRepresentation.tmpl         |  105 +
 .../SphericalBesselDimensionRepresentation.py      |  283 ++
 .../SphericalBesselDimensionRepresentation.tmpl    |   50 +
 .../SplitUniformDimensionRepresentation.py         |  717 ++++
 .../SplitUniformDimensionRepresentation.tmpl       |  117 +
 xpdeint/Geometry/UniformDimensionRepresentation.py |  671 +++
 .../Geometry/UniformDimensionRepresentation.tmpl   |  113 +
 xpdeint/Geometry/_Dimension.py                     |  142 +
 xpdeint/Geometry/_DimensionRepresentation.py       |  206 +
 xpdeint/Geometry/_FieldElement.py                  |  318 ++
 .../Geometry/_NonUniformDimensionRepresentation.py |   84 +
 .../_SplitUniformDimensionRepresentation.py        |   75 +
 .../Geometry/_UniformDimensionRepresentation.py    |   86 +
 xpdeint/Geometry/__init__.py                       |    0
 xpdeint/HDF5.py                                    |  699 +++
 xpdeint/HDF5.tmpl                                  |  207 +
 xpdeint/IndentFilter.py                            |  116 +
 xpdeint/Makefile                                   |   22 +
 xpdeint/MomentGroupElement.py                      |  457 ++
 xpdeint/MomentGroupElement.tmpl                    |  151 +
 xpdeint/Operators/ConstantEXOperator.py            |  349 ++
 xpdeint/Operators/ConstantEXOperator.tmpl          |   69 +
 xpdeint/Operators/ConstantIPOperator.py            |  370 ++
 xpdeint/Operators/ConstantIPOperator.tmpl          |   91 +
 xpdeint/Operators/CrossPropagationOperator.py      |  221 +
 xpdeint/Operators/CrossPropagationOperator.tmpl    |   31 +
 xpdeint/Operators/DeltaAOperator.py                |  348 ++
 xpdeint/Operators/DeltaAOperator.tmpl              |   84 +
 xpdeint/Operators/FilterOperator.py                |  258 ++
 xpdeint/Operators/FilterOperator.tmpl              |   49 +
 xpdeint/Operators/FunctionsOperator.py             |  216 +
 xpdeint/Operators/FunctionsOperator.tmpl           |   34 +
 xpdeint/Operators/NonConstantEXOperator.py         |  289 ++
 xpdeint/Operators/NonConstantEXOperator.tmpl       |   59 +
 xpdeint/Operators/NonConstantIPOperator.py         |  471 +++
 xpdeint/Operators/NonConstantIPOperator.tmpl       |  118 +
 xpdeint/Operators/Operator.py                      |  622 +++
 xpdeint/Operators/Operator.tmpl                    |  164 +
 xpdeint/Operators/OperatorContainer.py             |  182 +
 xpdeint/Operators/SICDeltaAOperator.py             |  533 +++
 xpdeint/Operators/SICDeltaAOperator.tmpl           |  142 +
 xpdeint/Operators/_CrossPropagationOperator.py     |  232 +
 xpdeint/Operators/_DeltaAOperator.py               |  293 ++
 xpdeint/Operators/_EXOperator.py                   |  136 +
 xpdeint/Operators/_FilterOperator.py               |   64 +
 xpdeint/Operators/_IPOperator.py                   |  155 +
 xpdeint/Operators/_Operator.py                     |  165 +
 xpdeint/Operators/_SICDeltaAOperator.py            |   79 +
 xpdeint/Operators/__init__.py                      |    1 +
 xpdeint/ParsedEntity.py                            |   36 +
 xpdeint/ParserException.py                         |   62 +
 xpdeint/Preferences.py                             |   10 +
 xpdeint/PrintfSafeFilter.py                        |   36 +
 xpdeint/Python24Support.py                         |   72 +
 xpdeint/RegularExpressionStrings.py                |   54 +
 xpdeint/ScriptElement.py                           | 1127 +++++
 xpdeint/ScriptElement.tmpl                         |  602 +++
 xpdeint/ScriptParser.py                            |   45 +
 xpdeint/Segments/BreakpointSegment.py              |  340 ++
 xpdeint/Segments/BreakpointSegment.tmpl            |   96 +
 xpdeint/Segments/FilterSegment.py                  |  226 +
 xpdeint/Segments/FilterSegment.tmpl                |   42 +
 xpdeint/Segments/Integrators/AdaptiveStep.py       | 1223 ++++++
 xpdeint/Segments/Integrators/AdaptiveStep.tmpl     |  401 ++
 xpdeint/Segments/Integrators/FixedStep.py          |  788 ++++
 xpdeint/Segments/Integrators/FixedStep.tmpl        |  281 ++
 xpdeint/Segments/Integrators/FixedStepWithCross.py |  229 +
 .../Segments/Integrators/FixedStepWithCross.tmpl   |   70 +
 xpdeint/Segments/Integrators/Integrator.py         |  644 +++
 xpdeint/Segments/Integrators/Integrator.tmpl       |  183 +
 xpdeint/Segments/Integrators/RK45Stepper.py        |  651 +++
 xpdeint/Segments/Integrators/RK45Stepper.tmpl      |  291 ++
 xpdeint/Segments/Integrators/RK4Stepper.py         |  461 ++
 xpdeint/Segments/Integrators/RK4Stepper.tmpl       |  166 +
 xpdeint/Segments/Integrators/RK89Stepper.py        | 1238 ++++++
 xpdeint/Segments/Integrators/RK89Stepper.tmpl      |  622 +++
 xpdeint/Segments/Integrators/RK9Stepper.py         | 1222 ++++++
 xpdeint/Segments/Integrators/RK9Stepper.tmpl       |  607 +++
 xpdeint/Segments/Integrators/SICStepper.py         |  301 ++
 xpdeint/Segments/Integrators/SICStepper.tmpl       |   77 +
 xpdeint/Segments/Integrators/SIStepper.py          |  340 ++
 xpdeint/Segments/Integrators/SIStepper.tmpl        |   89 +
 xpdeint/Segments/Integrators/_FixedStep.py         |   88 +
 .../Segments/Integrators/_FixedStepWithCross.py    |  172 +
 xpdeint/Segments/Integrators/_Integrator.py        |  188 +
 xpdeint/Segments/Integrators/_Stepper.py           |   59 +
 xpdeint/Segments/Integrators/__init__.py           |   11 +
 xpdeint/Segments/SequenceSegment.py                |  422 ++
 xpdeint/Segments/SequenceSegment.tmpl              |  104 +
 xpdeint/Segments/TopLevelSequenceElement.py        |  319 ++
 xpdeint/Segments/TopLevelSequenceElement.tmpl      |   91 +
 xpdeint/Segments/_BreakpointSegment.py             |   92 +
 xpdeint/Segments/_FilterSegment.py                 |   39 +
 xpdeint/Segments/_Segment.py                       |   76 +
 xpdeint/Segments/__init__.py                       |    1 +
 xpdeint/Simulation.py                              |  405 ++
 xpdeint/Simulation.tmpl                            |  216 +
 xpdeint/SimulationDrivers/DistributedMPIDriver.py  | 1079 +++++
 .../SimulationDrivers/DistributedMPIDriver.tmpl    |  343 ++
 xpdeint/SimulationDrivers/MPI.py                   |  358 ++
 xpdeint/SimulationDrivers/MPI.tmpl                 |   74 +
 xpdeint/SimulationDrivers/MPIMultiPathDriver.py    |  338 ++
 xpdeint/SimulationDrivers/MPIMultiPathDriver.tmpl  |   86 +
 xpdeint/SimulationDrivers/MultiPathDriver.py       |  516 +++
 xpdeint/SimulationDrivers/MultiPathDriver.tmpl     |  178 +
 xpdeint/SimulationDrivers/SimulationDriver.py      |  487 +++
 xpdeint/SimulationDrivers/SimulationDriver.tmpl    |  152 +
 xpdeint/SimulationDrivers/_DistributedMPIDriver.py |   90 +
 xpdeint/SimulationDrivers/_MPIMultiPathDriver.py   |   32 +
 xpdeint/SimulationDrivers/_MultiPathDriver.py      |   43 +
 xpdeint/SimulationDrivers/_SimulationDriver.py     |   42 +
 xpdeint/SimulationDrivers/__init__.py              |    1 +
 xpdeint/SimulationElement.py                       |  283 ++
 xpdeint/SimulationElement.tmpl                     |   72 +
 xpdeint/Stochastic/Generators/DSFMTGenerator.py    |  706 ++++
 xpdeint/Stochastic/Generators/DSFMTGenerator.tmpl  |  215 +
 xpdeint/Stochastic/Generators/Generator.py         |  468 ++
 xpdeint/Stochastic/Generators/Generator.tmpl       |  119 +
 xpdeint/Stochastic/Generators/MKLGenerator.py      |  394 ++
 xpdeint/Stochastic/Generators/MKLGenerator.tmpl    |   68 +
 xpdeint/Stochastic/Generators/POSIXGenerator.py    |  406 ++
 xpdeint/Stochastic/Generators/POSIXGenerator.tmpl  |   64 +
 xpdeint/Stochastic/Generators/SolirteGenerator.py  |  341 ++
 .../Stochastic/Generators/SolirteGenerator.tmpl    |   75 +
 xpdeint/Stochastic/Generators/__init__.py          |    0
 .../GaussianBoxMuellerRandomVariable.py            |  273 ++
 .../GaussianBoxMuellerRandomVariable.tmpl          |   72 +
 .../RandomVariables/GaussianMKLRandomVariable.py   |  192 +
 .../RandomVariables/GaussianMKLRandomVariable.tmpl |   32 +
 .../RandomVariables/GaussianRandomVariable.py      |  282 ++
 .../RandomVariables/GaussianRandomVariable.tmpl    |   77 +
 .../GaussianSolirteRandomVariable.py               |  199 +
 .../GaussianSolirteRandomVariable.tmpl             |   37 +
 .../RandomVariables/PoissonianRandomVariable.py    |  530 +++
 .../RandomVariables/PoissonianRandomVariable.tmpl  |  205 +
 .../RandomVariables/UniformRandomVariable.py       |  187 +
 .../RandomVariables/UniformRandomVariable.tmpl     |   33 +
 xpdeint/Stochastic/RandomVariables/__init__.py     |    0
 xpdeint/Stochastic/__init__.py                     |    0
 xpdeint/Utilities.py                               |  365 ++
 xpdeint/Vectors/ComputedVector.py                  |  285 ++
 xpdeint/Vectors/ComputedVector.tmpl                |   68 +
 xpdeint/Vectors/NoiseVector.py                     |  369 ++
 xpdeint/Vectors/NoiseVector.tmpl                   |   88 +
 xpdeint/Vectors/VectorElement.py                   |  654 +++
 xpdeint/Vectors/VectorElement.tmpl                 |  148 +
 xpdeint/Vectors/VectorInitialisation.py            |  253 ++
 xpdeint/Vectors/VectorInitialisation.tmpl          |   41 +
 xpdeint/Vectors/VectorInitialisationFromCDATA.py   |  271 ++
 xpdeint/Vectors/VectorInitialisationFromCDATA.tmpl |   56 +
 xpdeint/Vectors/VectorInitialisationFromHDF5.py    |  768 ++++
 xpdeint/Vectors/VectorInitialisationFromHDF5.tmpl  |  221 +
 xpdeint/Vectors/VectorInitialisationFromXSIL.py    | 1045 +++++
 xpdeint/Vectors/VectorInitialisationFromXSIL.tmpl  |  436 ++
 xpdeint/Vectors/_ComputedVector.py                 |   58 +
 xpdeint/Vectors/_NoiseVector.py                    |   95 +
 xpdeint/Vectors/_VectorElement.py                  |  203 +
 xpdeint/Vectors/_VectorInitialisationFromHDF5.py   |   32 +
 xpdeint/Vectors/__init__.py                        |    0
 xpdeint/Version.py                                 |    4 +
 xpdeint/XMDS2Parser.py                             | 2292 ++++++++++
 xpdeint/XMDSScriptLexer.py                         |   79 +
 xpdeint/XSILFile.py                                |  272 ++
 xpdeint/_MomentGroupElement.py                     |  157 +
 xpdeint/_ScriptElement.py                          |  568 +++
 xpdeint/_UserCodeBlock.py                          |  365 ++
 xpdeint/__init__.py                                |    1 +
 xpdeint/includes/dSFMT/dSFMT-params.h              |  102 +
 xpdeint/includes/dSFMT/dSFMT-params19937.h         |   66 +
 xpdeint/includes/dSFMT/dSFMT.c                     |  781 ++++
 xpdeint/includes/dSFMT/dSFMT.h                     |  578 +++
 xpdeint/includes/solirte/SFMTparams.h              |  196 +
 xpdeint/includes/solirte/prng.h                    | 2020 +++++++++
 xpdeint/includes/solirte/randpool.h                |  684 +++
 xpdeint/includes/solirte/u128simd.h                | 1225 ++++++
 xpdeint/includes/solirte/ziggurat.cpp              |  814 ++++
 xpdeint/includes/solirte/ziggurat.h                |   56 +
 xpdeint/includes/xpdeint.h                         |   53 +
 xpdeint/includes/xpdeint_platform.h                |  754 ++++
 xpdeint/minidom_extras.py                          |  250 ++
 xpdeint/parser2.py                                 |  498 +++
 xpdeint/support/Makefile                           |   11 +
 xpdeint/support/trang.jar                          |  Bin 0 -> 710214 bytes
 xpdeint/support/wscript                            |  604 +++
 xpdeint/support/xpdeint.rnc                        |  280 ++
 xpdeint/support/xpdeint.rng                        |  554 +++
 xpdeint/version.sh                                 |   21 +
 xpdeint/waf/waf-light                              |  164 +
 xpdeint/waf/waflib/Build.py                        | 1293 ++++++
 xpdeint/waf/waflib/Build.pyc                       |  Bin 0 -> 44551 bytes
 xpdeint/waf/waflib/ConfigSet.py                    |  337 ++
 xpdeint/waf/waflib/ConfigSet.pyc                   |  Bin 0 -> 11923 bytes
 xpdeint/waf/waflib/Configure.py                    |  570 +++
 xpdeint/waf/waflib/Configure.pyc                   |  Bin 0 -> 19318 bytes
 xpdeint/waf/waflib/Context.py                      |  595 +++
 xpdeint/waf/waflib/Context.pyc                     |  Bin 0 -> 18167 bytes
 xpdeint/waf/waflib/Errors.py                       |   70 +
 xpdeint/waf/waflib/Errors.pyc                      |  Bin 0 -> 3564 bytes
 xpdeint/waf/waflib/Logs.py                         |  274 ++
 xpdeint/waf/waflib/Logs.pyc                        |  Bin 0 -> 10070 bytes
 xpdeint/waf/waflib/Node.py                         |  845 ++++
 xpdeint/waf/waflib/Node.pyc                        |  Bin 0 -> 26717 bytes
 xpdeint/waf/waflib/Options.py                      |  252 ++
 xpdeint/waf/waflib/Options.pyc                     |  Bin 0 -> 9252 bytes
 xpdeint/waf/waflib/Runner.py                       |  360 ++
 xpdeint/waf/waflib/Runner.pyc                      |  Bin 0 -> 10657 bytes
 xpdeint/waf/waflib/Scripting.py                    |  574 +++
 xpdeint/waf/waflib/Scripting.pyc                   |  Bin 0 -> 18766 bytes
 xpdeint/waf/waflib/Task.py                         | 1239 ++++++
 xpdeint/waf/waflib/Task.pyc                        |  Bin 0 -> 38676 bytes
 xpdeint/waf/waflib/TaskGen.py                      |  754 ++++
 xpdeint/waf/waflib/TaskGen.pyc                     |  Bin 0 -> 25319 bytes
 xpdeint/waf/waflib/Tools/__init__.py               |    3 +
 xpdeint/waf/waflib/Tools/__init__.pyc              |  Bin 0 -> 185 bytes
 xpdeint/waf/waflib/Tools/ar.py                     |   22 +
 xpdeint/waf/waflib/Tools/asm.py                    |   74 +
 xpdeint/waf/waflib/Tools/bison.py                  |   49 +
 xpdeint/waf/waflib/Tools/c.py                      |   40 +
 xpdeint/waf/waflib/Tools/c_aliases.py              |  128 +
 xpdeint/waf/waflib/Tools/c_config.py               | 1201 ++++++
 xpdeint/waf/waflib/Tools/c_config.pyc              |  Bin 0 -> 40054 bytes
 xpdeint/waf/waflib/Tools/c_osx.py                  |  188 +
 xpdeint/waf/waflib/Tools/c_preproc.py              | 1030 +++++
 xpdeint/waf/waflib/Tools/c_preproc.pyc             |  Bin 0 -> 28226 bytes
 xpdeint/waf/waflib/Tools/c_tests.py                |  218 +
 xpdeint/waf/waflib/Tools/ccroot.py                 |  608 +++
 xpdeint/waf/waflib/Tools/compiler_c.py             |   98 +
 xpdeint/waf/waflib/Tools/compiler_cxx.py           |  102 +
 xpdeint/waf/waflib/Tools/compiler_d.py             |   59 +
 xpdeint/waf/waflib/Tools/compiler_fc.py            |   68 +
 xpdeint/waf/waflib/Tools/cs.py                     |  178 +
 xpdeint/waf/waflib/Tools/cxx.py                    |   43 +
 xpdeint/waf/waflib/Tools/d.py                      |   90 +
 xpdeint/waf/waflib/Tools/d_config.py               |   57 +
 xpdeint/waf/waflib/Tools/d_scan.py                 |  209 +
 xpdeint/waf/waflib/Tools/dbus.py                   |   70 +
 xpdeint/waf/waflib/Tools/dmd.py                    |   81 +
 xpdeint/waf/waflib/Tools/errcheck.py               |  211 +
 xpdeint/waf/waflib/Tools/fc.py                     |  205 +
 xpdeint/waf/waflib/Tools/fc_config.py              |  461 ++
 xpdeint/waf/waflib/Tools/fc_scan.py                |  126 +
 xpdeint/waf/waflib/Tools/flex.py                   |   46 +
 xpdeint/waf/waflib/Tools/g95.py                    |   65 +
 xpdeint/waf/waflib/Tools/gas.py                    |   17 +
 xpdeint/waf/waflib/Tools/gcc.py                    |  153 +
 xpdeint/waf/waflib/Tools/gdc.py                    |   56 +
 xpdeint/waf/waflib/Tools/gfortran.py               |   90 +
 xpdeint/waf/waflib/Tools/glib2.py                  |  378 ++
 xpdeint/waf/waflib/Tools/gnu_dirs.py               |  128 +
 xpdeint/waf/waflib/Tools/gxx.py                    |  153 +
 xpdeint/waf/waflib/Tools/icc.py                    |   42 +
 xpdeint/waf/waflib/Tools/icpc.py                   |   41 +
 xpdeint/waf/waflib/Tools/ifort.py                  |   58 +
 xpdeint/waf/waflib/Tools/intltool.py               |  176 +
 xpdeint/waf/waflib/Tools/irixcc.py                 |   63 +
 xpdeint/waf/waflib/Tools/javaw.py                  |  411 ++
 xpdeint/waf/waflib/Tools/kde4.py                   |   90 +
 xpdeint/waf/waflib/Tools/lua.py                    |   38 +
 xpdeint/waf/waflib/Tools/msvc.py                   |  938 ++++
 xpdeint/waf/waflib/Tools/nasm.py                   |   23 +
 xpdeint/waf/waflib/Tools/perl.py                   |  157 +
 xpdeint/waf/waflib/Tools/python.py                 |  494 +++
 xpdeint/waf/waflib/Tools/qt4.py                    |  639 +++
 xpdeint/waf/waflib/Tools/ruby.py                   |  193 +
 xpdeint/waf/waflib/Tools/suncc.py                  |   77 +
 xpdeint/waf/waflib/Tools/suncxx.py                 |   78 +
 xpdeint/waf/waflib/Tools/tex.py                    |  403 ++
 xpdeint/waf/waflib/Tools/vala.py                   |  339 ++
 xpdeint/waf/waflib/Tools/waf_unit_test.py          |  149 +
 xpdeint/waf/waflib/Tools/winres.py                 |   51 +
 xpdeint/waf/waflib/Tools/xlc.py                    |   69 +
 xpdeint/waf/waflib/Tools/xlcxx.py                  |   69 +
 xpdeint/waf/waflib/Utils.py                        |  601 +++
 xpdeint/waf/waflib/Utils.pyc                       |  Bin 0 -> 21201 bytes
 xpdeint/waf/waflib/__init__.py                     |    3 +
 xpdeint/waf/waflib/__init__.pyc                    |  Bin 0 -> 179 bytes
 xpdeint/waf/waflib/ansiterm.py                     |  241 ++
 xpdeint/waf/waflib/ansiterm.pyc                    |  Bin 0 -> 11852 bytes
 xpdeint/waf/waflib/extras/__init__.py              |    3 +
 xpdeint/waf/waflib/extras/__init__.pyc             |  Bin 0 -> 186 bytes
 xpdeint/waf/waflib/extras/add_objects.py           |    7 +
 xpdeint/waf/waflib/extras/batched_cc.py            |  161 +
 xpdeint/waf/waflib/extras/biber.py                 |   59 +
 xpdeint/waf/waflib/extras/bjam.py                  |  131 +
 xpdeint/waf/waflib/extras/boo.py                   |   81 +
 xpdeint/waf/waflib/extras/boost.py                 |  362 ++
 xpdeint/waf/waflib/extras/c_bgxlc.py               |   30 +
 xpdeint/waf/waflib/extras/c_dumbpreproc.py         |   61 +
 xpdeint/waf/waflib/extras/compat15.py              |  298 ++
 xpdeint/waf/waflib/extras/compat15.pyc             |  Bin 0 -> 11160 bytes
 xpdeint/waf/waflib/extras/cython.py                |  120 +
 xpdeint/waf/waflib/extras/dcc.py                   |   79 +
 xpdeint/waf/waflib/extras/doxygen.py               |  158 +
 xpdeint/waf/waflib/extras/dumbpreproc.py           |   61 +
 xpdeint/waf/waflib/extras/eclipse.py               |  308 ++
 xpdeint/waf/waflib/extras/erlang.py                |   19 +
 xpdeint/waf/waflib/extras/fc_bgxlf.py              |   33 +
 xpdeint/waf/waflib/extras/fc_cray.py               |   50 +
 xpdeint/waf/waflib/extras/fc_open64.py             |   56 +
 xpdeint/waf/waflib/extras/fc_pgfortran.py          |   65 +
 xpdeint/waf/waflib/extras/fc_solstudio.py          |   60 +
 xpdeint/waf/waflib/extras/fc_xlf.py                |   58 +
 xpdeint/waf/waflib/extras/fluid.py                 |   30 +
 xpdeint/waf/waflib/extras/freeimage.py             |   74 +
 xpdeint/waf/waflib/extras/fsb.py                   |   31 +
 xpdeint/waf/waflib/extras/fsc.py                   |   66 +
 xpdeint/waf/waflib/extras/gccdeps.py               |  123 +
 xpdeint/waf/waflib/extras/go.py                    |  262 ++
 xpdeint/waf/waflib/extras/gob2.py                  |   17 +
 xpdeint/waf/waflib/extras/local_rpath.py           |   19 +
 xpdeint/waf/waflib/extras/lru_cache.py             |   98 +
 xpdeint/waf/waflib/extras/make.py                  |  142 +
 xpdeint/waf/waflib/extras/md5_tstamp.py            |   69 +
 xpdeint/waf/waflib/extras/misc.py                  |  416 ++
 xpdeint/waf/waflib/extras/msvs.py                  | 1017 +++++
 xpdeint/waf/waflib/extras/netcache_client.py       |  328 ++
 xpdeint/waf/waflib/extras/objcopy.py               |   54 +
 xpdeint/waf/waflib/extras/ocaml.py                 |  326 ++
 xpdeint/waf/waflib/extras/package.py               |   76 +
 xpdeint/waf/waflib/extras/parallel_debug.py        |  341 ++
 xpdeint/waf/waflib/extras/pep8.py                  |  106 +
 xpdeint/waf/waflib/extras/pgicc.py                 |   69 +
 xpdeint/waf/waflib/extras/pgicxx.py                |   22 +
 xpdeint/waf/waflib/extras/print_commands.py        |   45 +
 xpdeint/waf/waflib/extras/proc.py                  |   56 +
 xpdeint/waf/waflib/extras/qnxnto.py                |   74 +
 xpdeint/waf/waflib/extras/relocation.py            |   85 +
 xpdeint/waf/waflib/extras/review.py                |  328 ++
 xpdeint/waf/waflib/extras/sas.py                   |   72 +
 xpdeint/waf/waflib/extras/scala.py                 |  130 +
 xpdeint/waf/waflib/extras/slow_qt4.py              |   95 +
 xpdeint/waf/waflib/extras/smart_continue.py        |   81 +
 xpdeint/waf/waflib/extras/softlink_libs.py         |   74 +
 xpdeint/waf/waflib/extras/subprocess.py            |  620 +++
 xpdeint/waf/waflib/extras/swig.py                  |  172 +
 xpdeint/waf/waflib/extras/syms.py                  |   71 +
 xpdeint/waf/waflib/extras/sync_exec.py             |   31 +
 xpdeint/waf/waflib/extras/valadoc.py               |  107 +
 xpdeint/waf/waflib/extras/why.py                   |   73 +
 xpdeint/waf/waflib/extras/xcode.py                 |  312 ++
 xpdeint/waf/waflib/fixpy2.py                       |   67 +
 xpdeint/waf_extensions/cheetah.py                  |   54 +
 xpdeint/waf_extensions/cheetah.pyc                 |  Bin 0 -> 1847 bytes
 xpdeint/wscript                                    |   51 +
 xpdeint/xsil2graphics2/MathematicaImport.py        |  418 ++
 xpdeint/xsil2graphics2/MathematicaImport.tmpl      |  106 +
 xpdeint/xsil2graphics2/MatlabOctaveImport.py       |  686 +++
 xpdeint/xsil2graphics2/MatlabOctaveImport.tmpl     |  158 +
 xpdeint/xsil2graphics2/PythonImport.py             |  256 ++
 xpdeint/xsil2graphics2/PythonImport.tmpl           |   56 +
 xpdeint/xsil2graphics2/__init__.py                 |    1 +
 xpdeint/xsil2graphicsParser.py                     |  165 +
 1093 files changed, 169438 insertions(+)

diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..67594b4
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,282 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+
diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644
index 0000000..7ac00eb
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,14 @@
+XMDS2 Copyright (c) 2007-2013, Graham Dennis, Andy Ferris, Joe Hope, Michael Hush, Mattias Johnsson, Gabriel McManus
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..0c04253
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,25 @@
+SUBDIRS = xpdeint
+
+.PHONY: all update clean check distclean
+
+all:
+	@for i in $(SUBDIRS); do \
+	(cd $$i; $(MAKE) $(MFLAGS) all); done
+
+update:
+	@svn up
+	@$(MAKE) $(MFLAGS) all
+
+# remove all compiled files
+clean:
+	@for i in $(SUBDIRS); do \
+	(cd $$i; $(MAKE) $(MFLAGS) clean); done
+
+# check examples compile
+check:
+	@for i in $(SUBDIRS); do \
+	(cd $$i; $(MAKE) $(MFLAGS) check); done
+
+distclean:
+	@for i in $(SUBDIRS); do \
+	(cd $$i; $(MAKE) $(MFLAGS) distclean); done
diff --git a/README b/README
new file mode 100644
index 0000000..fb97e4a
--- /dev/null
+++ b/README
@@ -0,0 +1,9 @@
+Welcome to XMDS2 (codename: xpdeint), a software package that allows the fast and easy solution of sets of ordinary, partial and stochastic differential equations, using a variety of efficient numerical algorithms.
+
+If you have any questions, please email xmds-user at lists.sourceforge.net
+
+The best place to begin your journey is with the documentation on our website: http://www.xmds.org 
+ 
+It will explain the program and the installation instructions. 
+
+Swim free, little fishy!
\ No newline at end of file
diff --git a/ReleaseNotes b/ReleaseNotes
new file mode 100644
index 0000000..9d58a11
--- /dev/null
+++ b/ReleaseNotes
@@ -0,0 +1,95 @@
+**** XMDS 2.1.4 "Well if this isn't nice, I don't know what is" ****
+
+The XMDS 2.1.4 update contains many new improvements and bugfixes:
+
+* `xsil2graphics2` now supports all output formats for MATLAB, Octave and Python.  The scripts generated for MATLAB/Octave are compatible with both.
+* Fix a bug when nonlocally referencing a dimension alias with subsampling in `sampling_group` blocks or in some situations when MPI is used.  This bug caused incorrect elements of the vector to be accessed.
+* Correct the Fourier basis for dimensions using Hermite-Gauss transforms.  Previously 'kx' was effectively behaving as '-kx'.
+* Improve the performance of 'nx' <--> 'kx' Hermite-Gauss transforms.
+* Stochastic error checking with runtime noise generation now works correctly.  Previously different random numbers were generated for the full-step paths and the half-step paths.
+* Documentation updates.
+
+**** XMDS 2.1.3 "Happy Mollusc" ****
+
+The XMDS 2.1.3 update is a bugfix release that includes the following improvements:
+
+* XMDS will work when MPI isn't installed (but only for single-process simulations).
+* Support for GCC 4.8
+* The number of paths used by the multi-path driver can now be specified at run-time (using `<validation kind="run-time">`)
+* Other bug fixes
+
+**** XMDS 2.1.2 "Happy Mollusc" ****
+
+We have published a paper in Computer Physics Communications.  If you use XMDS2 in your research, we would appreciate it if you cited us in your publications:
+
+G.R. Dennis, J.J. Hope, and M.T. Johnsson, Computer Physics Communications 184, 201–208 (2013)
+
+The XMDS 2.1.2 update has many improvements:
+
+* Named filters.  You can now specify a name for a filter block and call it like a function if you need to execute it conditionally.  See the documentation for the `<filter>` block for more information.
+* New `chunked_output` feature.  XMDS can now output simulation results as it goes, reducing the memory requirement for simulations that generate significant amounts of output.  See the documentation for more details.
+* Improved OpenMP support
+* The EX operator is now faster in the common case (but you should still prefer IP when possible)
+* If seeds are not provided for a `noise_vector`, they are now generated at simulation run-time, so different executions will give different results.  The generated noises can still be found in the output .xsil files enabling results to be reproduced if desired.
+* Advanced feature: Dimensions can be accessed non-locally with the index of the lattice point.  This removes the need in hacks to manually access XMDS's underlying C arrays.  This is an advanced feature and requires a little knowledge of XMDS's internal grid representation.  See the advanced topics documentation for further details.
+* Fixed adaptive integrator order when noises were used in vector initialisation
+* Fix the Spherical Bessel basis.  There were errors in the definition of this basis which made it previously unreliable.
+* Other bug fixes
+
+
+**** XMDS 2.1 "Happy Mollusc" ****
+
+XMDS 2.1 is a significant upgrade with many improvements and bug fixes since 2.0. We also now have installers for Linux and Mac OS X, so you no longer have to build XMDS from source! See http://www.xmds.org/installation.html for details about the installers.
+
+The documentation has been expanded significantly with a better tutorial, more worked examples, and description of all XMDS 2 script elements.  Take a look at the new documentation at http://www.xmds.org
+
+Existing users should note that this release introduces a more concise syntax for moment groups.  You can now use:
+
+    <sampling_group initial_sample="yes" basis="x y z">
+        ...
+    </sampling_group>
+
+Instead of:
+
+    <group>
+        <sampling initial_sample="yes" basis="x y z">
+            ...
+        </sampling>
+    </group>
+
+Another syntax change is that the initial basis of a vector should be specified with `initial_basis` instead of `initial_space`.
+
+In both cases, although the old syntax is not described in the documentation, it is still supported, so existing scripts will work without any changes.
+
+Other changes in XMDS 2.1 include:
+
+* The `lattice` attribute for dimensions can now be specified at run-time.  Previously only the minimum and maximum values of the domain could be specified at run-time.  See http://www.xmds.org/reference_elements.html#validation for details.
+* `noise_vector`s can now be used in non-uniform dimensions (e.g. dimensions using the Bessel transform for cylindrical symmetry).
+* "loose" `geometry_matching_mode` for HDF5 vector initialisation.  This enables extending the simulation grid from one simulation to the next, or coarsening or refining a grid when importing.
+* `vector`s can now be initialised by integrating over dimensions of other vectors.  `computed_vector`s always supported this, now `vector`s do too.
+* Update to latest version of waf, which is used for compiling simulations and detecting FFTW, HDF5, etc. This should lead to fewer waf-related problems.
+* Bug fixes.
+
+**** XMDS 2.0 "Shiny!" ****
+
+XMDS 2.0 is a major upgrade which has been rewritten from the ground up to make it easier for us to apply new features. And there are many. XMDS 2.0 is faster and far more versatile than previous versions, allowing the efficient integration of almost any initial value problem on regular domains.
+
+The feature list includes:
+
+* Quantities of different dimensionalities. So you can have a 1D potential and a 3D wavefunction.
+* Integrate more than one vector (in more than one geometry), so you can now simultaneously integrate a PDE and a coupled ODE (or coupled PDEs of different dimensions).
+* Non-Fourier transformations including the Bessel basis, Spherical Bessel basis and the Hermite-Gauss (harmonic oscillator) basis.
+* The ability to have more than one kind of noise (gaussian, poissonian, etc) in a simulation.
+* Integer-valued dimensions with non-local access. You can have an array of variables and access different elements of that array.
+* Significantly better error reporting. When errors are found when compiling the script they will almost always be reported with the corresponding line of your script, instead of the generated source.
+* `IP`/`EX` operators are separate from the integration algorithm, so you can have both `IP` and `EX` operators in a single integrate block. Also, `EX` operators can act on arbitrary code, not just vector components. (e.g. `L[phi*phi]`).
+* Cross propagation in the increasing direction of a given dimension or in the decreasing dimension. And you can have more than one cross-propagator in a given integrator (going in different directions or dimensions).
+* Faster Gaussian noises.
+* The ability to calculate spatial correlation functions.
+* OpenMP support.
+* MPI support.
+* Output moment groups use less memory when there isn't a `post_processing` element.
+* Generated source is indented correctly.
+* An `xmds1`-like script file format.
+* `xmds1`-like generated source.
+* All of the integrators from `xmds1` (`SI`, `RK4`, `ARK45`, `RK9`, `ARK89`).
diff --git a/admin/TODO b/admin/TODO
new file mode 100644
index 0000000..644edbe
--- /dev/null
+++ b/admin/TODO
@@ -0,0 +1,70 @@
+* Add the ability to distribute stochastic simulations using MPI with the scheduling method
+
+* In adaptive integrators, the ability to set an absolute cutoff (per vector component) in addition to a relative cutoff
+  for step-error calculations.
+
+* Add a 'moment group 0' which contains simulation constants. 
+  This moment group would be zero-d and would contain various constants depending on the
+  exact simulation. Constants that should be included are: the final value of the propagation dimension,
+   any passed-in arguments, the number of paths (if appropriate), and anything else appropriate.
+  - This can be added in the HDF5 output file.
+  - Add the simulation text to the HDF5 file.  I'd like to make the xsil file redundant.
+
+* Add support for moment post-processing (before stochastic averaging). This is only necessary for multi-path simulations where a temporal fourier transform needs to be averaged.
+
+* Add support for moment post-processing (after stochastic averaging).  This is useful for calculating, for example, Wigner standard deviations.  This means you don't need to do this in MATLAB.
+
+* Determine an appropriate transform and quasi-gauss quadrature for a polar coordinate representation.  I'm imagining a generalisation from our current 'bessel' transforms to allow a (r, \theta) -> (kr, m) transform.  Determining a good numerical method would probably be a moderate numerical-math project with implementation in MATLAB.  Implementation of the resulting work in XMDS would be a very advanced project due to the changes required in the TransformMultiplexer code.
+
+* Investigate performance of XMDS-type simulations for graphics cards using CUDA / OpenCL.  This would require experience with graphics card programming as there are lots of details about how you implement these algorithms which significantly affect performance.
+
+* Optimise MPI / OpenMP performance of XMDS simulations including determination of performance scaling limitations.  For example, on a given system, with 2 CPUs are we CPU-constrained or memory-bandwidth constrained?  What about 4 CPUs? 8? Is there anything we can do to resolve these constraints?  Another example: parts of integration algorithms are actually independent and could in principle be executed concurrently (different steps that are independent, not just the same step but on di [...]
+
+* Rewrite bindNamedVectors/preflight system. It's a mess. bindNamedVectors/preflight should probably be renamed to something like 'localPreflight'/'nonlocalPreflight'.
+
+
+* Make xmds/xpdeint code compile on Windows. Currently it works in Cygwin but suffers from 
+  SERIOUS performance degradation. I've been trying to compile a simple script (modified 
+  kubo.xmds) using the MS Visual Studio 2005 Express compiler. The following are compile issues:
+  - Headers <unistd.h> <sys/time.h> and <stdint.h> don't exist on Windows. Fixed with #ifdef POSIX.
+      unistd.h - not sure when we use it... perhaps for pthreads?
+      sys/time.h - we'll need to replace gettimeofday() with getsystemtime() or similar. Affects benchmark,
+      stdint.h - seems to be C99 but not in Visual studio 2005... strange... used for what exactly?
+  - M_PI/etc aren't defined by default in math.h. Defining _USE_CONSTANTS fixes that.
+  - _LOG lines reutrn syntax errors. Fixed with Grahams patch
+  - erand48 is not defined on Windows. dsfmt replacements work fine.
+  - fseeko is a POSIX thing as well and is missing on Windows. To use 64 bit offsets we 
+    could substitute with fsetpos and _filelengthi64. 
+  - fftw3 has compiled windows DLL's which they claim are well optimised. Linking with them is
+    easy but we can't do wisdom. #ifdef POSIX removes wisdom from windows.
+  Implementation notes:
+  - I don't think a Windows distribution needs MPI/OpenMP support. Otherwise, I don't see why the
+    things xmds does isn't easily portable...
+  - Now works fine with limited features, fftw without wisdom, and ASCII output. 
+  - kubo is MUCH faster compiled on MSVC++ than cygwin GCC
+  - diffusion_win works fine on windows.
+  - Next priorities: getting fftw3 working and porting the benchmark code...
+  - Investigate MinGW GCC 4.3 performance versus Visual Studio performance.
+
+* Breakpoint on signal? (e.g. USR1)
+
+Testcases needed:
+* MPI with Fourier transforms testing looping over both MPI dimensions with a vector that only has one of the two MPI dimensions.
+* Various tests using nonlocal dimension access
+* Tests of dumping fields with integer-valued dimensions using HDF5
+* Tests dumping fields where the testcase data was dumped on a big-endian machine (PPC)
+* More testcases doing stupid things with loading and dumping of various formats of data, including loading in MPI
+  simulations, writing of ascii/binary/HDF5 data and loading of binary/HDF5 data.
+
+* xsil2graphics2 needs finishing.
+
+* Trigger support (Ask Michael Hush).  Done "correctly", this would involve adding zero-crossing detection to the adaptive and/or fixed-step integrators.  This could be used for:
+   - Triggered-sampling: useful for Poincare plots or other situations where implicit sampling is desired
+   - Very fast Poisson noises that also scales well for large numbers of Poisson noises: useful for chemical reaction network modelling where each reaction has a rate constant and there are many (thousands?) of possible reactions.
+
+* Adaptive-order integrators (Gear method)
+
+* Make it easier to perform parameter scans (this is probably better done in an external tool, though), and more generally, graph-based processing (each node is a simulation that may have one or more inputs / outputs, etc).  This is probably insufficiently defined.
+
+* Add native support for matrix-vector multiplication and matrix-matrix multiplication (and use BLAS to make it fast). (What notation should be used for this?)
+
diff --git a/admin/create_release_version.sh b/admin/create_release_version.sh
new file mode 100755
index 0000000..4afef28
--- /dev/null
+++ b/admin/create_release_version.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+# Exit if anything fails
+set -o errexit
+
+# Run by typing ./create_release_version.sh in admin/ directory
+cd ..
+XMDS_VERSION=`python setup.py --version`
+
+# Create Version.py with subversion revision information
+cd xpdeint
+./version.sh
+cd ..
+
+if [ -d admin/staging ]; then 
+	rm -rf admin/staging;
+fi
+
+mkdir -p admin/staging/
+
+# Create a clean checkout
+svn export . admin/staging/xmds-${XMDS_VERSION}
+# Copy Version.py with revision information
+cp xpdeint/Version.py admin/staging/xmds-${XMDS_VERSION}/xpdeint
+
+cd admin/staging/xmds-${XMDS_VERSION}
+cd admin/userdoc-source
+# Build html docs
+make html
+# Copy built HTML docs into staging/ dir for later transfer to website
+cp -r ../../documentation ../../../
+# Build LaTeX docs
+make latex
+cd ../../documentation/latex
+# Actually make the PDF
+make all-pdf
+cd ../..
+
+# Compile Cheetah templates
+make
+
+# Clean up after waf
+make distclean
+
+cd ..
+tar -czf xmds-${XMDS_VERSION}.tar.gz xmds-${XMDS_VERSION}
+
+echo To release to sourceforge, execute the following commands.
+echo scp staging/xmds-${XMDS_VERSION}.tar.gz username at frs.sf.net:/home/frs/project/x/xm/xmds/
+echo "cd staging; scp -r documentation/* username at web.sf.net:/home/project-web/xmds/htdocs/"
diff --git a/admin/developer-doc-source/FFTW3MPI Design.graffle b/admin/developer-doc-source/FFTW3MPI Design.graffle
new file mode 100644
index 0000000..1e0873b
Binary files /dev/null and b/admin/developer-doc-source/FFTW3MPI Design.graffle differ
diff --git a/admin/developer-doc-source/FFTW3MPI Design.pdf b/admin/developer-doc-source/FFTW3MPI Design.pdf
new file mode 100644
index 0000000..8e72fec
Binary files /dev/null and b/admin/developer-doc-source/FFTW3MPI Design.pdf differ
diff --git a/admin/developer-doc-source/Makefile b/admin/developer-doc-source/Makefile
new file mode 100644
index 0000000..f34a3e5
--- /dev/null
+++ b/admin/developer-doc-source/Makefile
@@ -0,0 +1,14 @@
+SOURCE = $(wildcard ../xpdeint/*py)
+
+default: html
+
+pdf: $(SOURCE)
+	epydoc --config=epydoc.cfg --pdf
+
+html: $(SOURCE)
+	epydoc --config=epydoc.cfg --html
+
+.PHONY: clean
+clean:
+	rm -rf html
+	rm -rf pdf
diff --git a/admin/developer-doc-source/epydoc.cfg b/admin/developer-doc-source/epydoc.cfg
new file mode 100644
index 0000000..0fa5835
--- /dev/null
+++ b/admin/developer-doc-source/epydoc.cfg
@@ -0,0 +1,100 @@
+[epydoc]
+
+# The list of objects to document.  Objects can be named using
+# dotted names, module filenames, or package directory names.
+# Alases for this option include "objects" and "values".
+modules: ../../xpdeint
+
+# An integer indicating how verbose epydoc should be.  The default
+# value is 0; negative values will supress warnings and errors;
+# positive values will give more verbose output.
+verbosity: 0
+
+### Generation options
+
+# The default markup language for docstrings, for modules that do
+# not define __docformat__.  Defaults to epytext.
+docformat: restructuredtext
+
+# The format for showing inheritance objects.
+# It should be one of: 'grouped', 'listed', 'included'.
+inheritance: listed
+
+# Whether or not to include syntax highlighted source code in
+# the output (HTML only).
+sourcecode: yes
+
+exclude: xpdeint\.wafadmin\..*
+
+### Output options
+
+# The documented project's name.
+name: xpdeint
+
+# The CSS stylesheet for HTML output.  Can be the name of a builtin
+# stylesheet, or the name of a file.
+css: white
+
+# The documented project's URL.
+url: http://www.xmds.org/
+
+# HTML code for the project link in the navigation bar.  If left
+# unspecified, the project link will be generated based on the
+# project's name and URL.
+#link: <a href="somewhere">My Cool Project</a>
+
+# The "top" page for the documentation.  Can be a URL, the name
+# of a module or class, or one of the special names "trees.html",
+# "indices.html", or "help.html"
+#top: os.path
+
+# An alternative help file.  The named file should contain the
+# body of an HTML file; navigation bars will be added to it.
+#help: my_helpfile.html
+
+# Whether or not to include a frames-based table of contents.
+frames: no
+
+# Whether each class should be listed in its own section when
+# generating LaTeX or PDF output.
+separate-classes: no
+
+### API linking options
+
+# Define a new API document.  A new interpreted text role
+# will be created
+#external-api: epydoc
+
+# Use the records in this file to resolve objects in the API named NAME.
+#external-api-file: epydoc:api-objects.txt
+
+# Use this URL prefix to configure the string returned for external API.
+#external-api-root: epydoc:http://epydoc.sourceforge.net/api
+
+
+### Graph options
+
+# The list of graph types that should be automatically included
+# in the output.  Graphs are generated using the Graphviz "dot"
+# executable.  Graph types include: "classtree", "callgraph",
+# "umlclass".  Use "all" to include all graph types
+graph: classtree
+
+# The path to the Graphviz "dot" executable, used to generate
+# graphs.
+#dotpath: /usr/bin/dot
+
+# Specify the font used to generate Graphviz graphs.
+# (e.g., helvetica or times).
+graph-font: Helvetica
+
+# Specify the font size used to generate Graphviz graphs.
+graph-font-size: 10
+
+### Return value options
+
+# The condition upon which Epydoc should exit with a non-zero
+# exit status. Possible values are error, warning, docstring_warning
+#fail-on: error
+
+
diff --git a/admin/fftw3-SnowLeopard.patch b/admin/fftw3-SnowLeopard.patch
new file mode 100644
index 0000000..1e890a4
--- /dev/null
+++ b/admin/fftw3-SnowLeopard.patch
@@ -0,0 +1,30 @@
+--- libbench2/report.c.old	2009-09-24 10:23:36.000000000 +1000
++++ libbench2/report.c	2009-09-24 10:20:37.000000000 +1000
+@@ -92,21 +92,17 @@
+ 
+ static void sprintf_time(double x, char *buf, int buflen)
+ {
+-#ifdef HAVE_SNPRINTF
+-#  define BENCH_BUFARG buf, buflen
+-#else
+-#  define snprintf sprintf
+-#  define BENCH_BUFARG buf
++#ifndef HAVE_SNPRINTF
++#  define snprintf(str, len, ...) sprintf(str, __VA_ARGS__)
+ #endif
+      if (x < 1.0E-6)
+-	  snprintf(BENCH_BUFARG, "%.2f ns", x * 1.0E9);
++	  snprintf(buf, buflen, "%.2f ns", x * 1.0E9);
+      else if (x < 1.0E-3)
+-	  snprintf(BENCH_BUFARG, "%.2f us", x * 1.0E6);
++	  snprintf(buf, buflen, "%.2f us", x * 1.0E6);
+      else if (x < 1.0)
+-	  snprintf(BENCH_BUFARG, "%.2f ms", x * 1.0E3);
++	  snprintf(buf, buflen, "%.2f ms", x * 1.0E3);
+      else
+-	  snprintf(BENCH_BUFARG, "%.2f s", x);
+-#undef BENCH_BUFARG
++	  snprintf(buf, buflen, "%.2f s", x);
+ }
+ 
+ void report_verbose(const bench_problem *p, double *t, int st)
diff --git a/admin/linux_installer.sh b/admin/linux_installer.sh
new file mode 100755
index 0000000..ebec9b2
--- /dev/null
+++ b/admin/linux_installer.sh
@@ -0,0 +1,548 @@
+#!/bin/bash
+
+# This installer (currently) works for Debian and Debian based distros such
+# as Ubuntu, as well as Fedora and Red Hat. Other distros may or may not work.
+
+# Look for apt-get or yum to decide whether we should use a deb or rpm
+# type of installation. If more distro support is added later, a finer
+# grained detection scheme will probably be necessary.
+
+# If this entire script is run as root, all the files created under the user's home
+# directory will be owned by root, which can cause permissioning and deletion
+# problems. Only the copying of the binaries to locations outside the user's
+# directories should be run as sudo, which is taken care of within this script.
+
+XMDS_VERSION="2.1.4"
+KNOWN_GOOD_XMDS_REVISION="2872"
+
+if [ "$(whoami)" = "root" ]; then
+  echo
+  echo "It seems you are running this installer as root or with the \"sudo\" "
+  echo "command. Unless you're sure you know what you're doing, please exit"
+  echo "and re-run this installer as a normal user (i.e. without \"sudo\")."
+  echo
+  echo "Continue? (Y/N)"
+
+  read reply
+  if [ $reply = "N" -o $reply = "n" ]; then
+    exit
+  fi
+fi
+
+echo $reply
+
+echo
+echo
+echo "*** XMDS2 installer v0.4 ***"
+echo
+echo "A standard install downloads the XMDS $XMDS_VERSION version of the code. This"
+echo "is the default."
+echo
+echo "A developer install will download the latest cutting-edge version of"
+echo "the XMDS code, which may include bugs. To perform a developer install,"
+echo "run the installer with the --develop option."
+echo
+echo "In both cases an SVN repository will be created locally, and you can update"
+echo "to the latest version of the code at any time by running the command"
+echo "  make update"
+echo "in the xmds-$XMDS_VERSION/ directory."
+echo
+echo
+
+RPM_INSTALL=0
+DEB_INSTALL=0
+if [ `which apt-get | wc -l` -ne 0 ]; then
+  echo; echo "apt-get found; assuming Debian packaging scheme"; echo
+  DEB_INSTALL=1
+elif [ `which yum | wc -l` -ne 0 ]; then
+  echo; echo "yum found; assuming RPM packaging scheme"; echo
+  RPM_INSTALL=1
+else
+  echo
+  echo "ERROR!"
+  echo "This installer only works on Debian, Debian-based distributions such"
+  echo "as Ubuntu and Mint, Fedora and Red Hat. Since neither \"apt-get\" "
+  echo "nor \"yum\" is available, installation can't proceed."
+  echo
+  echo "Aborting install."
+  echo
+  exit
+fi
+
+XMDS2_install_directory=$HOME"/xmds-$XMDS_VERSION"
+NUM_CPUS=`cat /proc/cpuinfo | grep processor | wc -l`
+DEVELOPER_INSTALL=0
+
+# COMMITTER_INSTALL denotes whether the person installing is
+# allowed to make commits to the sourceforge svn repository.
+# If this is set to "1" via a command line argument, 
+# an https checkout of the repo is made, and if the
+# correct credentials are not stored on the user's machine
+# (e.g. from previously committing to that repo), the installer
+# prompts for the sourceforge username and password. This
+# ensures the person can then commit to repo.
+#
+# If COMMITTER_INSTALL is set to "0", an http checkout is made
+# (*NOT* an https checkout). This is the default. It means no
+# credentials are demanded during the install phase, but that
+# person cannot immediately make commits to the xmds repo.
+# In order to get committer rights in future, the local repo
+# must be switched from http to https via
+# svn switch --relocate http://svn.code.sf.net/p/xmds/code https://svn.code.sf.net/p/xmds/code
+COMMITTER_INSTALL=0
+
+XMDS_CONFIGURE_STRING=""
+
+parse_command_line_arguments() {
+  for i in $@; do
+    if [ $i = "--help" ] || [ $i = "-h" ]; then
+      echo
+      echo "This is the XMDS "$XMDS_VERSION" installer."
+      echo
+      echo "Usage: ./install [options]"
+      echo
+      echo "Options and arguments:"
+      echo "--help          : this help text"
+      echo
+      echo "--develop       : perform a developer install, downloading the absolute" 
+      echo "                  latest version of the code"
+      echo
+      echo "--commit-access : set up the local repo to allow commits to the XMDS SVN repo. A" 
+      echo "                  developer account on the XMDS sourceforge project is required"
+      echo
+      echo "If no options are given, a standard install without commit access will be performed."
+      echo
+      exit
+    elif [ $i = "--develop" ]; then
+      DEVELOPER_INSTALL=1
+    elif [ $i = "--commit-access" ]; then
+      COMMITTER_INSTALL=1
+    else
+      echo "Unknown option:" $i
+    fi
+  done
+}
+
+install_FFTW_from_source() {
+
+  # FFTW 3.3 wasn't in the repos, so install manually from source
+  current_directory=`pwd`
+  
+  cd $XMDS2_install_directory
+
+  echo; echo "Downloading FFTW from www.fftw.org..."; echo
+
+  wget http://www.fftw.org/fftw-3.3.2.tar.gz
+  fftwversion="3.3.2"
+  if [ ! -f fftw-3.3.2.tar.gz ]; then
+    # Fall back to the known-to-exist 3.3.1
+    wget ftp://ftp.fftw.org/pub/fftw/old/fftw-3.3.1.tar.gz
+    fftwversion="3.3.1"
+
+    # If *that's* not present, we can't continue
+    if [ ! -f fftw-3.3.1.tar.gz ]; then
+      echo
+      echo "ERROR: Couldn't obtain fftw-3.3.2.tar.gz or fftw-3.3.1.tar.gz from www.fftw.org."
+      echo "Aborting install."
+      exit
+    fi
+  fi
+
+  # Unpack the FFTW archive and install it under the user's home directory structure.
+  # This avoids conflicting with any other version of FFTW that may have been
+  # installed system-wide. Later we'll tell XMDS to use this specific version.
+
+  FFTW_install_directory=$XMDS2_install_directory"/fftw-"$fftwversion
+  tar -xzf fftw-${fftwversion}.tar.gz
+  rm fftw-${fftwversion}.tar.gz
+
+  # Need quotes in the below in case path contains spaces
+  cd "$FFTW_install_directory"
+
+  echo
+  echo "Installing FFTW. This can take several minutes if you only have a single CPU."
+  
+  NO_COMPILER_SUPPORT_FOR_AVX=0  
+
+  echo "  Configuring FFTW with single precision option..."
+
+  ./configure --disable-fortran --enable-mpi --enable-single --enable-sse2 --enable-openmp --enable-avx --prefix=$FFTW_install_directory > installer.log
+  if [ $? -ne 0 ]; then
+    # Nonzero error code returned, so something went wrong
+    echo "    Configuration failed. Retrying without assuming your compiler supports AVX..."
+    ./configure --disable-fortran --enable-mpi --enable-single --enable-sse2 --enable-openmp --prefix=$FFTW_install_directory > installer.log
+    if [ $? -ne 0 ]; then
+      # Still no success, so bail out
+      echo "Configuration failed due to some unknown reason. Aborting install."
+      echo "Check installer.log in "$FFTW_install_directory " for more information."
+      echo
+      exit
+    else
+      echo "    Configuration successful!"
+      NO_COMPILER_SUPPORT_FOR_AVX=1
+    fi
+  fi
+
+  rm -f installer.log > /dev/null
+
+  echo "  Compiling FFTW with single precision option..."
+  # The single precision install produces lots of warnings, so redirect both stdout and
+  # stderror to /dev/null
+  make -j $NUM_CPUS > /dev/null 2>&1
+  
+  echo "  Installing single precision libraries..."
+  make install > /dev/null
+
+  # Note: if precision is not specified, FFTW will compile double-precision libs by default
+  echo "  Configuring FFTW with double precision option..."
+  if [ $NO_COMPILER_SUPPORT_FOR_AVX -eq 1 ]; then
+    ./configure --disable-fortran --enable-mpi --enable-sse2 --enable-openmp --prefix=$FFTW_install_directory > /dev/null
+  else
+    ./configure --disable-fortran --enable-mpi --enable-sse2 --enable-avx --enable-openmp --prefix=$FFTW_install_directory > /dev/null
+  fi
+
+  echo "  Compiling FFTW with double precision option..."
+  make -j $NUM_CPUS > /dev/null
+
+  echo "  Installing double precision libraries..."
+  make install > /dev/null
+
+  XMDS_CONFIGURE_STRING=$XMDS_CONFIGURE_STRING" --lib-path "$FFTW_install_directory"/lib"
+  XMDS_CONFIGURE_STRING=$XMDS_CONFIGURE_STRING" --include-path "$FFTW_install_directory"/include"
+
+  cd $current_directory
+  echo
+  echo "FFTW installed!"
+  echo
+}
+
+
+install_HDF5_from_source() {
+  current_directory=`pwd`
+
+  HDF5_install_directory=$XMDS2_install_directory"/hdf5-1.8.8"
+  
+  cd $XMDS2_install_directory
+  echo; echo "Downloading HDF5 1.8.8 from www.hdfgroup.org.."; echo
+  wget http://www.hdfgroup.org/ftp/HDF5/prev-releases/hdf5-1.8.8/src/hdf5-1.8.8.tar.gz
+
+  # Make sure the HDF5 1.8.8 archive is present
+  if [ ! -f hdf5-1.8.8.tar.gz ]; then
+    echo
+    echo "ERROR: Couldn't obtain hdf5-1.8.8.tar.gz from www.hdfgroup.org."
+    echo "Aborting install."
+    exit
+  fi
+
+  # Unpack the HDF5 1.8.8 archive and install it in the user's home directory structure.
+  # This avoids conflicting with any other version of HDF5 that may have been
+  # installed system-wide. Later we'll tell XMDS to use this specific version.  
+  tar -xzf hdf5-1.8.8.tar.gz
+  rm hdf5-1.8.8.tar.gz
+  cd $HDF5_install_directory
+
+  echo
+  echo "Installing HDF5. This can take several minutes if you only have a single CPU."
+  echo "  Configuring HDF5..."
+  ./configure --prefix=$HDF5_install_directory > installer.log
+  if [ $? -ne 0 ]; then
+    # Nonzero error code returned, so something went wrong
+    echo "\nConfiguration failed due to some unknown reason."
+    echo "As HDF5 is required for XMDS2, I am aborting the install."
+    echo "Check installer.log in "$HDF5_install_directory " for more information."
+    echo
+    exit
+  fi
+
+  rm -f installer.log > /dev/null
+
+  echo "  Compiling HDF5..."
+  # The HDF5 compile produces stupid amounts of warnings, so if
+  # I echo the error stream to standard out, the user will see pages
+  # and pages of scary stuff. Consequently just dump everything to /dev/null
+  make -j $NUM_CPUS > /dev/null 2>&1
+  
+  echo "  Copying libraries..."
+  make install > /dev/null
+
+  XMDS_CONFIGURE_STRING=$XMDS_CONFIGURE_STRING" --lib-path "$HDF5_install_directory"/lib"
+  XMDS_CONFIGURE_STRING=$XMDS_CONFIGURE_STRING" --include-path "$HDF5_install_directory"/include"
+
+  cd $current_directory
+  echo
+  echo "HDF5 installed!"
+  echo
+}
+
+
+parse_command_line_arguments $@
+
+if [ $DEVELOPER_INSTALL -eq 1 ]; then
+  echo "Performing developer install..."
+else
+  echo "Performing standard install..."
+fi
+echo
+echo
+echo "By default XMDS will be installed in " $XMDS2_install_directory
+echo "Press [ENTER] to accept this default, or enter a new path:"
+read reply
+
+if [ ! -z $reply ]; then
+  XMDS2_install_directory=$reply
+fi
+
+# check if XMDS directory exists, if not create it
+if [ ! -d $XMDS2_install_directory ]; then
+  mkdir $XMDS2_install_directory
+fi
+
+echo
+echo "Installing required packages..."
+echo
+
+if [ $DEB_INSTALL -eq 1 ]; then
+  # Begin Debian package install
+  sudo apt-get -y install build-essential subversion libopenmpi-dev openmpi-bin python-dev python-setuptools python-cheetah python-numpy python-pyparsing python-lxml python-mpmath libhdf5-serial-dev libgsl0-dev python-sphinx python-h5py wget
+
+  # Find the optimum ATLAS version (i.e. CBLAS implementation) and install it
+  # Older versions of Ubuntu/Debian offered pre-optimized packages for various architectures,
+  # but newer versions don't, and only offer a single generic package.
+  if [ `cat /proc/cpuinfo | grep sse3 |wc -l` -gt 0 ]; then
+    if [ `cat /proc/cpuinfo | grep "Core(TM) i7" | wc -l` -ne 0 ] && [ `apt-cache --names-only search libatlas-corei7sse3-dev | wc -l` -ne 0 ]; then
+      sudo apt-get -y install libatlas-corei7sse3-dev
+    elif [ `apt-cache --names-only search libatlas-amd64sse3-dev | wc -l` -ne 0 ]; then
+      sudo apt-get -y install libatlas-amd64sse3-dev
+    else
+      sudo apt-get -y install libatlas-base-dev
+    fi
+  else
+    sudo apt-get -y install libatlas-base-dev
+  fi 
+  # End Debian packages install
+elif [ $RPM_INSTALL -eq 1 ]; then
+  # Begin RPM packages install
+  sudo yum -y install gcc gcc-c++ make automake subversion openmpi-devel python-devel python-setuptools python-cheetah numpy gsl-devel python-sphinx wget libxml2-devel libxslt-devel
+  
+  # Find the optimum ATLAS version (i.e. CBLAS implementation) and install it
+  # Older versions of Fedora offered pre-optimized packages for various architectures,
+  # but newer versions don't, and only offer a single generic package.
+  SUCCESS=0
+  if [ $SUCCESS -eq 0 ] && [ `cat /proc/cpuinfo | grep sse3 |wc -l` -gt 0 ]; then
+    sudo yum -y install atlas-sse3-devel
+    if [ $? -eq 0 ]; then
+        SUCCESS=1;
+    fi
+  fi
+  
+  if [ $SUCCESS -eq 0 ] && [ `cat /proc/cpuinfo | grep sse2 |wc -l` -gt 0 ]; then
+    sudo yum -y install atlas-sse2-devel
+    if [ $? -eq 0 ]; then
+        SUCCESS=1;
+    fi
+  fi
+  
+  if [ $SUCCESS -eq 0 ]; then
+    sudo yum -y install atlas-devel
+  fi
+
+  # The default Red Hat repo doesn't have hdf5-dev, but Fedora does. 
+  # Check if this package is available. If it is, install via the 
+  # package manager, otherwise download, compile and install the HDF5 source code.
+
+  if [ `yum info hdf5-devel | grep hdf5-devel | wc -l` -gt 0 ]; then
+    sudo yum -y install hdf5-devel
+  else
+    echo
+    echo "The HDF5 package isn't available in your standard repositories."
+    echo "I will download, compile and install the HDF5 source code."
+    install_HDF5_from_source
+  fi
+  
+  # The packages h5py, pyparsing, python-lxml, and python-mpmath are not available
+  # in the default Red Hat repository, but are are in the EPEL repository. See if
+  # they're available; if so use yum to get them, if not use easy_install
+
+  if [ `yum info pyparsing | grep pyparsing | wc -l` -gt 0 ]; then
+    sudo yum -y install pyparsing
+  else
+    sudo easy_install pyparsing
+  fi
+
+  if [ `yum info python-lxml | grep python-lxml | wc -l` -gt 0 ]; then
+    sudo yum -y install python-lxml
+  else
+    sudo easy_install lxml
+  fi
+
+  if [ `yum info h5py | grep h5py | wc -l` -gt 0 ]; then
+    sudo yum -y install h5py
+  else
+    if [ -z $HDF5_install_directory ]; then
+      sudo easy_install h5py
+    else
+      sudo /bin/bash -c "export HDF5_DIR=${HDF5_install_directory}; easy_install h5py;"
+    fi
+  fi
+
+  if [ `yum info python-mpmath | grep python-mpmath | wc -l` -gt 0 ]; then
+    sudo yum -y install python-mpmath
+  else
+    sudo easy_install mpmath
+  fi
+
+  # End RPM packages install
+fi
+
+# Some distros put MPI libraries and binaries in a location that
+# isn't in the default search path, allowing multiple MPI versions
+# to coexist. This can also happen with the ATLAS CBLAS libraries.
+# Since we need to know where they are in order to compile stuff,
+# find where they are located.
+
+ld_search_string=`ld --verbose | grep SEARCH`
+
+echo
+echo "Searching for correct BLAS implementation on your machine. This may take some time..."
+echo
+
+# Find the CBLAS library, and make sure it's not the GSL one
+CBLASLIB=`sudo find /usr/lib* -name *libcblas.so | grep -v -i gsl | head --lines=1`
+CBLASLIBDIR=`dirname $CBLASLIB`
+if [ `echo $ld_search_string | grep $CBLASLIBDIR | wc -w` -eq 0 ]; then
+  # CBLAS library not in standard linker path
+  # Need to add it to the XMDS configure string
+  XMDS_CONFIGURE_STRING=$XMDS_CONFIGURE_STRING" --lib-path "$CBLASLIBDIR
+fi
+
+CBLASHEADER=`sudo find /usr -name cblas.h | grep -v -i gsl | head --lines=1`
+CBLASHEADERDIR=`dirname $CBLASHEADER`
+if [ ! $CBLASHEADERDIR = "/usr/include" ]; then
+  if [ ! $CBLASHEADERDIR = "/usr/local/include" ]; then
+    XMDS_CONFIGURE_STRING=$XMDS_CONFIGURE_STRING" --include-path "$CBLASHEADERDIR
+  fi
+fi
+
+# Some distros don't have mpicc, mpic++ and mpirun in their default executable path, so we need to do stuff
+# to be able to use it. The user also must do stuff.
+if [ `which mpicc | wc -l` -eq 0 ]; then
+    # On some RedHat systems, we need to source /etc/profile.d/openmpi.sh
+    if [ -r /etc/profile.d/openmpi.sh ]; then
+        source /etc/profile.d/openmpi.sh;
+        load_openmpi;
+        COMPLETION_MESSAGE="\nYou must add the line 'load_openmpi' to the end of your login \nscript (probably ~/.bashrc) to use MPI.\n If you wish to load a \ndifferent MPI implementation, you can use 'module avail' to see \nwhat implementations are available as alternatives."
+    elif [ `which modulecmd | wc -l` -eq 1 ]; then
+        # This is the case for Fedora
+        source /etc/profile
+        module load mpi;
+        COMPLETION_MESSAGE="\nYou must add the line 'module load mpi' to the end of your \nlogin script (probably ~/.bashrc) to use MPI.\nIf you have multiple versions of MPI installed on your system \nand wish to use one that's not the default implementation, you \ncan use 'module avail' to see what is available and 'module load' \nthat version instead.\n"
+    fi
+fi
+
+
+# Install FFTW3.3 from package manager if available, otherwise build from source
+echo
+if [ $DEB_INSTALL -eq 1 ]; then
+  echo "Checking if MPI-enabled FFTW available in repository..."
+  if [ `apt-cache --names-only search libfftw3-mpi-dev | wc -l` -ne 0 ]; then
+    echo "Yes, it is available"
+    echo "Installing FFTW via package manager"
+    sudo apt-get -y install libfftw3-dev libfftw3-mpi-dev 
+  else 
+    echo "MPI-enabled FFTW not available in repository. Downloading, compiling and installing from source"
+    install_FFTW_from_source
+  fi
+elif [ $RPM_INSTALL -eq 1 ]; then
+  # Note Fedora 18 has fftw-3.3.3-4, fftw-devel-3.3.3-4, fftw-libs-3.3.3-4, 
+  # fftw-libs-double-3.3.3-4, fftw-libs-single-3.3.3-4, fftw-libs-quad-3.3.3-4.
+  # The fftw-devel-3.3.3-4 metapackage pulls in all the other libs: single, double, 
+  # quad and long double, plus OpenMP libs, as well as FFTW headers.
+  # As of Fedora 18, these libs are built with threads and OpenMP support, 
+  # but *NOT* MPI support, so we still have to build from source. 
+  install_FFTW_from_source
+fi
+
+
+# Fetch the XMDS2 source files
+echo
+echo "Contacting sourceforge to checkout XMDS2 source code. Please wait..."
+echo
+
+if [ $COMMITTER_INSTALL -eq 1 ]; then
+  SVN_REPOSITORY="https://svn.code.sf.net/p/xmds/code/trunk/xpdeint"
+else
+  SVN_REPOSITORY="http://svn.code.sf.net/p/xmds/code/trunk/xpdeint"
+fi
+
+if [ $DEVELOPER_INSTALL -eq 1 ]; then
+  # Fetch the latest XMDS2 source code from sourceforge
+  cd $XMDS2_install_directory
+  svn checkout $SVN_REPOSITORY .
+else
+  # Fetch a known good version of the XMDS2 source code from sourceforge
+  cd $XMDS2_install_directory
+  svn checkout -r $KNOWN_GOOD_XMDS_REVISION $SVN_REPOSITORY .
+fi
+
+# Compile the Cheetah templates into Python
+echo
+echo "Compiling Cheetah templates..."
+echo
+make
+
+# Creates the xmds2 and xsil2graphics2 files in /usr/bin (or wherever), 
+# and copy xmds2 python code into the python install path (typically 
+# something like /usr/lib/python2.7/site-packages), and tells Python
+# about the new package.
+echo
+echo "Installing XMDS..."
+echo
+sudo ./setup.py develop
+
+echo
+echo "Configuring XMDS with configure string: " $XMDS_CONFIGURE_STRING
+echo
+
+xmds2 --reconfigure $XMDS_CONFIGURE_STRING
+
+# Build the HTML documentation
+cd $XMDS2_install_directory"/admin/userdoc-source"
+make html
+
+# Fedora uses an OpenMPI library that assumes infiniband support. This 
+# results in warnings when MPI-enabled scripts are run. Inform the user
+# that these warnings can be killed if they really don't have the hardware
+if [ $RPM_INSTALL -eq 1 ]; then
+  # If the user doesn't have at least 2 processors they're not going to use MPI
+  if [ $NUM_CPUS -gt 1 ]; then
+    cd $XMDS2_install_directory"/examples"
+    xmds2 diffusion_mpi.xmds > /dev/null 2>&1
+    mpirun -np 2 diffusion_mpi > mpi_test_log 2>&1
+    if [ `grep "unable to find any relevant network interfaces" mpi_test_log | wc -l` -gt 0 ]; then
+      OMPI_CONF_FILE=`sudo find /etc -name openmpi-mca-params.conf | head --lines=1`
+      COMPLETION_MESSAGE=$COMPLETION_MESSAGE"Your machine appears to lack Infiniband hardware, which means if you run\n"
+      COMPLETION_MESSAGE=$COMPLETION_MESSAGE"MPI-enabled XMDS2 scripts you will get warnings that the hardware can't be\n"
+      COMPLETION_MESSAGE=$COMPLETION_MESSAGE"found. If you know your machine doesn't have such hardware, it is safe to\n"
+      COMPLETION_MESSAGE=$COMPLETION_MESSAGE"disable these warnings now by entering\n"
+      COMPLETION_MESSAGE=$COMPLETION_MESSAGE"sudo sh -c \"echo 'btl = ^openib' >> "$OMPI_CONF_FILE"\"\n"
+    fi
+    rm mpi_test_log
+  fi
+fi
+
+
+echo
+echo "If no errors are displayed above, XMDS $XMDS_VERSION is installed!"
+echo
+echo "To see the HTML documentation, point your browser at" $XMDS2_install_directory"/documentation/index.html"
+echo "or go to www.xmds.org"
+echo
+echo "Release notes and instructions can be found in" $XMDS2_install_directory
+echo
+echo "You can always update to the latest version of XMDS at any time by running \"make update\" "
+echo "in the top level xmds-$XMDS_VERSION/ directory."
+echo
+echo "NOTES ON YOUR PARTICULAR INSTALL:"
+echo
+echo -e ${COMPLETION_MESSAGE}
+
diff --git a/admin/releaseInstructions.txt b/admin/releaseInstructions.txt
new file mode 100644
index 0000000..7019648
--- /dev/null
+++ b/admin/releaseInstructions.txt
@@ -0,0 +1,31 @@
+svn log --xml --verbose | xsltproc admin/svn2cl.xsl - > ChangeLog
+
+We'll eventually need to replace such structures in new version.  
+I already found myself wanting to scan log messages, so I copied the above over from xmds.
+
+Release Instructions:
+*********************
+
+0. Change version in the following files:
+    xpdeint/Preferences.py
+    setup.py
+    admin/linux_installer.sh
+    admin/userdoc-source/installation.rst
+    admin/userdoc-source/conf.py.  
+    
+    ChangeLog is an optional change.
+
+1. Make sure everything works with a clean install.  
+    (Check out a clean copy and do tests) 
+    "svn checkout https://svn.code.sf.net/p/xmds/code/trunk/xpdeint xmds2"
+
+2. Change the "last known good" choices in the linux and mac installers, and check them.
+
+3. Go into the admin directory, and run "./create_release_version.sh".
+
+4. Follow that script's instructions for putting the documentation and tarball on sourceforge
+
+5. Update the mac installer file.
+
+6. Announce!
+
diff --git a/admin/svn2cl.xsl b/admin/svn2cl.xsl
new file mode 100644
index 0000000..f4b734e
--- /dev/null
+++ b/admin/svn2cl.xsl
@@ -0,0 +1,442 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+
+   svn2cl.xsl - xslt stylesheet for converting svn log to a normal
+                changelog
+
+   version 0.8
+
+   Usage (replace ++ with two minus signs which aren't allowed
+   inside xml comments):
+     svn ++verbose ++xml log | \
+       xsltproc ++stringparam strip-prefix `basename $(pwd)` \
+                ++stringparam linelen 75 \
+                ++stringparam groupbyday yes \
+                ++stringparam separate-daylogs yes \
+                ++stringparam include-rev yes \
+                ++stringparam breakbeforemsg yes/2 \
+                ++stringparam reparagraph yes \
+                ++stringparam authorsfile FILE \
+                svn2cl.xsl - > ChangeLog
+
+   This file is based on several implementations of this conversion
+   that I was not completely happy with and some other common
+   xslt constructs found on the web.
+
+   Copyright (C) 2004, 2005, 2006 Arthur de Jong.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+   3. The name of the author may not be used to endorse or promote
+      products derived from this software without specific prior
+      written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+   IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+   IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-->
+
+<!DOCTYPE xsl:stylesheet [
+ <!ENTITY tab "	">
+ <!ENTITY newl "
">
+ <!ENTITY space " ">
+]>
+
+<xsl:stylesheet
+  version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+ <xsl:output
+   method="text"
+   encoding="utf-8"
+   media-type="text/plain"
+   omit-xml-declaration="yes"
+   standalone="yes"
+   indent="no" />
+
+ <xsl:strip-space elements="*" />
+
+ <!-- the prefix of pathnames to strip -->
+ <xsl:param name="strip-prefix" select="'/'" />
+
+ <!-- the length of a line to wrap messages at -->
+ <xsl:param name="linelen" select="75" />
+ 
+ <!-- whether entries should be grouped by day -->
+ <xsl:param name="groupbyday" select="'no'" />
+
+ <!-- whether to seperate log messages by empty lines -->
+ <xsl:param name="separate-daylogs" select="'no'" />
+
+ <!-- whether a revision number should be included -->
+ <xsl:param name="include-rev" select="'no'" />
+
+ <!-- whether the log message should start on a new line -->
+ <xsl:param name="breakbeforemsg" select="'no'" />
+
+ <!-- whether the message should be rewrapped within one paragraph -->
+ <xsl:param name="reparagraph" select="'no'" />
+
+ <!-- location of authors file if any -->
+ <xsl:param name="authorsfile" select="''" />
+ <xsl:key name="author-lookup" match="author" use="@uid" />
+ <xsl:variable name="authors-top" select="document($authorsfile)/authors" />
+
+ <!-- add newlines at the end of the changelog -->
+ <xsl:template match="log">
+  <xsl:apply-templates />
+  <xsl:text>&newl;</xsl:text>
+ </xsl:template>
+
+ <!-- format one entry from the log -->
+ <xsl:template match="logentry">
+  <xsl:choose>
+   <!-- if we're grouping we should omit some headers -->
+   <xsl:when test="$groupbyday='yes'">
+    <!-- save log entry number -->
+    <xsl:variable name="pos" select="position()" />
+    <!-- fetch previous entry's date -->
+    <xsl:variable name="prevdate">
+     <xsl:apply-templates select="../logentry[position()=(($pos)-1)]/date" />
+    </xsl:variable>
+    <!-- fetch previous entry's author -->
+    <xsl:variable name="prevauthor">
+     <xsl:value-of select="normalize-space(../logentry[position()=(($pos)-1)]/author)" />
+    </xsl:variable>
+    <!-- fetch this entry's date -->
+    <xsl:variable name="date">
+     <xsl:apply-templates select="date" />
+    </xsl:variable>
+    <!-- fetch this entry's author -->
+    <xsl:variable name="author">
+     <xsl:value-of select="normalize-space(author)" />
+    </xsl:variable>
+    <!-- check if header is changed -->
+    <xsl:if test="($prevdate!=$date) or ($prevauthor!=$author)">
+     <!-- add newline -->
+     <xsl:if test="not(position()=1)">
+      <xsl:text>&newl;</xsl:text>
+     </xsl:if>
+     <!-- date -->
+     <xsl:value-of select="$date" />
+     <!-- two spaces -->
+     <xsl:text>&space;&space;</xsl:text>
+     <!-- author's name -->
+     <xsl:apply-templates select="author" />
+     <!-- two newlines -->
+     <xsl:text>&newl;</xsl:text>
+     <xsl:if test="$separate-daylogs!='yes'"><xsl:text>&newl;</xsl:text></xsl:if>
+    </xsl:if>
+   </xsl:when>
+   <!-- write the log header -->
+   <xsl:otherwise>
+    <!-- add newline -->
+    <xsl:if test="not(position()=1)">
+     <xsl:text>&newl;</xsl:text>
+    </xsl:if>
+    <!-- date -->
+    <xsl:apply-templates select="date" />
+    <!-- two spaces -->
+    <xsl:text>&space;&space;</xsl:text>
+    <!-- author's name -->
+    <xsl:apply-templates select="author" />
+    <!-- two newlines -->
+    <xsl:text>&newl;&newl;</xsl:text>
+   </xsl:otherwise>
+  </xsl:choose>
+  <!-- get paths string -->
+  <xsl:variable name="paths">
+   <xsl:apply-templates select="paths" />
+   <xsl:text>:&space;</xsl:text>
+  </xsl:variable>
+  <!-- get revision number -->
+  <xsl:variable name="rev">
+   <xsl:if test="$include-rev='yes'">
+    <xsl:text>[r</xsl:text>
+    <xsl:value-of select="@revision" />
+    <xsl:text>]&space;</xsl:text>
+   </xsl:if>
+  </xsl:variable>
+  <!-- trim trailing newlines -->
+  <xsl:variable name="msg">
+   <!-- add a line break before the log message -->
+   <xsl:choose>
+    <xsl:when test="$breakbeforemsg='yes'">
+     <xsl:text>&newl;</xsl:text>
+    </xsl:when>
+    <xsl:when test="number($breakbeforemsg)>0">
+     <xsl:call-template name="newlines">
+      <xsl:with-param name="count" select="number($breakbeforemsg)" />
+     </xsl:call-template>
+    </xsl:when>
+   </xsl:choose>
+   <xsl:call-template name="trim-newln">
+    <xsl:with-param name="txt" select="msg" />
+   </xsl:call-template>
+  </xsl:variable>
+  <!-- add newline here if separate-daylogs is in effect -->
+  <xsl:if test="$groupbyday='yes' and $separate-daylogs='yes'"><xsl:text>&newl;</xsl:text></xsl:if>
+  <!-- first line is indented (other indents are done in wrap template) -->
+  <xsl:text>&tab;*&space;</xsl:text>
+  <!-- print the paths and message nicely wrapped -->
+  <xsl:call-template name="wrap">
+   <xsl:with-param name="txt" select="concat($rev,$paths,$msg)" />
+  </xsl:call-template>
+ </xsl:template>
+
+ <!-- format date -->
+ <xsl:template match="date">
+  <xsl:variable name="date" select="normalize-space(.)" />
+  <!-- output date part -->
+  <xsl:value-of select="substring($date,1,10)" />
+  <!-- output time part -->
+  <xsl:if test="$groupbyday!='yes'">
+   <xsl:text>&space;</xsl:text>
+   <xsl:value-of select="substring($date,12,5)" />
+  </xsl:if>
+ </xsl:template>
+
+ <!-- format author -->
+ <xsl:template match="author">
+  <xsl:variable name="uid" select="normalize-space(.)" />
+  <!-- try to lookup author in authorsfile -->
+  <xsl:choose>
+   <xsl:when test="$authorsfile!=''">
+    <xsl:for-each select="$authors-top">
+     <xsl:variable name="author" select="key('author-lookup',$uid)" />
+     <!-- present result -->
+     <xsl:choose>
+      <xsl:when test="string($author/.)">
+       <xsl:apply-templates select="$author/node()" mode="copy" />
+      </xsl:when>
+      <xsl:otherwise>
+       <xsl:value-of select="$uid" />
+      </xsl:otherwise>
+     </xsl:choose>
+    </xsl:for-each>
+   </xsl:when>
+   <xsl:otherwise>
+    <xsl:value-of select="$uid" />
+   </xsl:otherwise>
+  </xsl:choose>
+ </xsl:template>
+
+ <!-- copy but normalize text -->
+ <xsl:template match="text()" mode="copy">
+  <xsl:value-of select="normalize-space(.)" />
+ </xsl:template>
+
+ <!-- simple copy template -->
+ <xsl:template match="@*|node()" mode="copy">
+  <xsl:copy>
+   <xsl:apply-templates select="@*|node()" mode="copy" />
+  </xsl:copy>
+ </xsl:template>
+
+ <!-- present a list of paths names -->
+ <xsl:template match="paths">
+  <xsl:for-each select="path">
+   <xsl:sort select="normalize-space(.)" data-type="text" />
+   <!-- unless we are the first entry, add a comma -->
+   <xsl:if test="not(position()=1)">
+    <xsl:text>,&space;</xsl:text>
+   </xsl:if>
+   <!-- print the path name -->
+   <xsl:apply-templates select="." />
+  </xsl:for-each>
+ </xsl:template>
+
+ <!-- transform path to something printable -->
+ <xsl:template match="path">
+  <!-- fetch the pathname -->
+  <xsl:variable name="p1" select="normalize-space(.)" />
+  <!-- strip leading slash -->
+  <xsl:variable name="p2">
+   <xsl:choose>
+    <xsl:when test="starts-with($p1,'/')">
+     <xsl:value-of select="substring($p1,2)" />
+    </xsl:when>
+    <xsl:otherwise>
+     <xsl:value-of select="$p1" />
+    </xsl:otherwise>
+   </xsl:choose>
+  </xsl:variable>
+  <!-- strip trailing slash from strip-prefix -->
+  <xsl:variable name="sp">
+   <xsl:choose>
+    <xsl:when test="substring($strip-prefix,string-length($strip-prefix),1)='/'">
+     <xsl:value-of select="substring($strip-prefix,1,string-length($strip-prefix)-1)" />
+    </xsl:when>
+    <xsl:otherwise>
+     <xsl:value-of select="$strip-prefix" />
+    </xsl:otherwise>
+   </xsl:choose>
+  </xsl:variable>
+  <!-- strip strip-prefix -->
+  <xsl:variable name="p3">
+   <xsl:choose>
+    <xsl:when test="starts-with($p2,$sp)">
+     <xsl:value-of select="substring($p2,1+string-length($sp))" />
+    </xsl:when>
+    <xsl:otherwise>
+     <!-- TODO: do not print strings that do not begin with strip-prefix -->
+     <xsl:value-of select="$p2" />
+    </xsl:otherwise>
+   </xsl:choose>
+  </xsl:variable>
+  <!-- strip another slash -->
+  <xsl:variable name="p4">
+   <xsl:choose>
+    <xsl:when test="starts-with($p3,'/')">
+     <xsl:value-of select="substring($p3,2)" />
+    </xsl:when>
+    <xsl:otherwise>
+     <xsl:value-of select="$p3" />
+    </xsl:otherwise>
+   </xsl:choose>
+  </xsl:variable>
+  <!-- translate empty string to dot -->
+  <xsl:choose>
+   <xsl:when test="$p4 = ''">
+    <xsl:text>.</xsl:text>
+   </xsl:when>
+   <xsl:otherwise>
+    <xsl:value-of select="$p4" />
+   </xsl:otherwise>
+  </xsl:choose>
+ </xsl:template>
+
+ <!-- string-wrapping template -->
+ <xsl:template name="wrap">
+  <xsl:param name="txt" />
+  <xsl:variable name="normtxt" select="normalize-space($txt)" />
+  <xsl:choose>
+   <xsl:when test="contains($txt,'&newl;')">
+     <!-- text contains newlines, do the first line -->
+     <xsl:call-template name="wrap">
+      <xsl:with-param name="txt" select="substring-before($txt,'&newl;')" />
+     </xsl:call-template>
+     <!-- print tab -->
+     <xsl:text>&tab;&space;&space;</xsl:text>
+     <!-- wrap the rest of the text -->
+     <xsl:call-template name="wrap">
+      <xsl:with-param name="txt" select="substring-after($txt,'&newl;')" />
+     </xsl:call-template>
+   </xsl:when>
+   <xsl:when test="(string-length($normtxt) < (($linelen)-9)) or not(contains($normtxt,' '))">
+    <!-- this is easy, nothing to do -->
+    <xsl:value-of select="$normtxt" />
+    <!-- add newline -->
+    <xsl:text>&newl;</xsl:text>
+   </xsl:when>
+   <xsl:otherwise>
+    <!-- find the first line -->
+    <xsl:variable name="tmp" select="substring($normtxt,1,(($linelen)-9))" />
+    <xsl:variable name="line">
+     <xsl:choose>
+      <!-- if our attempt contains spaces wrap on that -->
+      <xsl:when test="contains($tmp,' ')">
+       <xsl:call-template name="find-line">
+        <xsl:with-param name="txt" select="$tmp" />
+       </xsl:call-template>
+      </xsl:when>
+      <!-- otherwise use the first non-space characters from the text -->
+      <xsl:otherwise>
+       <xsl:value-of select="substring-before($normtxt,' ')" />
+      </xsl:otherwise>
+     </xsl:choose>
+    </xsl:variable>
+    <!-- print line -->
+    <xsl:value-of select="$line" />
+    <!-- print newline and tab -->
+    <xsl:text>&newl;&tab;&space;&space;</xsl:text>
+    <!-- wrap the rest of the text -->
+    <xsl:call-template name="wrap">
+     <xsl:with-param name="txt" select="normalize-space(substring($normtxt,string-length($line)+1))" />
+    </xsl:call-template>
+   </xsl:otherwise>
+  </xsl:choose>
+ </xsl:template>
+
+ <!-- template to trim line to contain space as last char -->
+ <xsl:template name="find-line">
+  <xsl:param name="txt" />
+  <xsl:choose>
+   <xsl:when test="substring($txt,string-length($txt),1)=' '">
+    <xsl:value-of select="substring($txt,1,string-length($txt)-1)" />
+   </xsl:when>
+   <xsl:otherwise>
+    <xsl:call-template name="find-line">
+     <xsl:with-param name="txt" select="substring($txt,1,string-length($txt)-1)" />
+    </xsl:call-template>
+   </xsl:otherwise>
+  </xsl:choose>
+ </xsl:template>
+
+ <!-- template to trim trailing and starting newlines -->
+ <xsl:template name="trim-newln">
+  <xsl:param name="txt" />
+  <xsl:choose>
+   <!-- find starting newlines -->
+   <xsl:when test="substring($txt,1,1) = '&newl;'">
+    <xsl:call-template name="trim-newln">
+     <xsl:with-param name="txt" select="substring($txt,2)" />
+    </xsl:call-template>
+   </xsl:when>
+   <!-- find trailing newlines -->
+   <xsl:when test="substring($txt,string-length($txt),1) = '&newl;'">
+    <xsl:call-template name="trim-newln">
+     <xsl:with-param name="txt" select="substring($txt,1,string-length($txt)-1)" />
+    </xsl:call-template>
+   </xsl:when>
+   <!-- if the message has paragrapgs, find the first one -->
+   <xsl:when test="$reparagraph='yes' and contains($txt,'&newl;&newl;')">
+     <!-- remove newlines from first paragraph -->
+     <xsl:value-of select="normalize-space(substring-before($txt,'&newl;&newl;'))" />
+     <!-- paragraph separator -->
+     <xsl:text>&newl;&newl;</xsl:text>
+     <!-- do the rest of the text -->
+     <xsl:call-template name="trim-newln">
+      <xsl:with-param name="txt" select="substring-after($txt,'&newl;&newl;')" />
+     </xsl:call-template>
+   </xsl:when>
+   <!-- remove more single newlines -->
+   <xsl:when test="$reparagraph='yes'">
+    <xsl:value-of select="normalize-space($txt)" />
+   </xsl:when>
+   <!-- no newlines found, we're done -->
+   <xsl:otherwise>
+    <xsl:value-of select="$txt" />
+   </xsl:otherwise>
+  </xsl:choose>
+ </xsl:template>
+
+ <!-- insert a number of newlines -->
+ <xsl:template name="newlines">
+  <xsl:param name="count" />
+  <xsl:text>&newl;</xsl:text>
+  <xsl:if test="$count>1">
+   <xsl:call-template name="newlines">
+    <xsl:with-param name="count" select="($count)-1" />
+   </xsl:call-template>
+  </xsl:if>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/admin/userdoc-source/Makefile b/admin/userdoc-source/Makefile
new file mode 100644
index 0000000..ffe2d43
--- /dev/null
+++ b/admin/userdoc-source/Makefile
@@ -0,0 +1,70 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         = a4
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d ../../documentation/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html web pickle htmlhelp latex changes linkcheck
+
+help:
+	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  html      to make standalone HTML files"
+	@echo "  pickle    to make pickle files (usable by e.g. sphinx-web)"
+	@echo "  htmlhelp  to make HTML files and a HTML help project"
+	@echo "  latex     to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@echo "  changes   to make an overview over all changed/added/deprecated items"
+	@echo "  linkcheck to check all external links for integrity"
+
+clean:
+	-rm -rf ../../documentation
+
+html:
+	mkdir -p ../../documentation ../../documentation/doctrees
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) ../../documentation
+	@echo
+	@echo "Build finished. The HTML pages are in ../../documentation."
+
+pickle:
+	mkdir -p ../../documentation/pickle ../../documentation/doctrees
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) ../../documentation/pickle
+	@echo
+	@echo "Build finished; now you can process the pickle files or run"
+	@echo "  sphinx-web ../../documentation/pickle"
+	@echo "to start the sphinx-web server."
+
+web: pickle
+
+htmlhelp:
+	mkdir -p ../../documentation ../../documentation/doctrees
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) ../../documentation
+	@echo
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
+	      ".hhp project file in ../../documentation."
+
+latex:
+	mkdir -p ../../documentation/latex ../../documentation/doctrees
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) ../../documentation/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in ../../documentation/latex."
+	@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
+	      "run these through (pdf)latex."
+
+changes:
+	mkdir -p ../../documentation/changes ../../documentation/doctrees
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) ../../documentation/changes
+	@echo
+	@echo "The overview file is in ../../documentation/changes."
+
+linkcheck:
+	mkdir -p ../../documentation/linkcheck ../../documentation/doctrees
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) ../../documentation/linkcheck
+	@echo
+	@echo "Link check complete; look for any errors in the above output " \
+	      "or in ../../documentation/linkcheck/output.txt."
diff --git a/admin/userdoc-source/_static/mathjax-use-tex-fonts.js b/admin/userdoc-source/_static/mathjax-use-tex-fonts.js
new file mode 100644
index 0000000..ae31c3a
--- /dev/null
+++ b/admin/userdoc-source/_static/mathjax-use-tex-fonts.js
@@ -0,0 +1,9 @@
+MathJax.Hub.Config({
+  showProcessingMessages: false,
+  messageStyle: "none",
+  "HTML-CSS": {
+    availableFonts: ["TeX"], 
+  },
+});
+
+MathJax.Ajax.loadComplete("http://www.xmds.org/_static/mathjax-use-tex-fonts.js");
diff --git a/admin/userdoc-source/advanced_topics.rst b/admin/userdoc-source/advanced_topics.rst
new file mode 100644
index 0000000..aaa51fb
--- /dev/null
+++ b/admin/userdoc-source/advanced_topics.rst
@@ -0,0 +1,276 @@
+.. _AdvancedTopics:
+
+Advanced Topics
+===============
+
+This section has further details on some important topics.
+
+:ref:`Importing` (importing data into XMDS2, and data formats used in the export)
+
+:ref:`Convolutions` (extra information on the Fourier transforms used in XMDS2, and applications to defining convolutions)
+
+:ref:`DimensionAliases` (dimensions which are declared to be identical, useful for correlation functions)
+
+.. _Importing:
+
+Importing data
+--------------
+
+There are many cases where it is advantageous to import previously acquired data into XMDS2. For example, the differential equation you wish to solve may depend on a complicated functional form, which is more easily obtained via an analytical package such as Mathematica or Maple. Furthermore, importing data from another source can be quicker than needlessly performing calculations in XMDS2. In this tutorial, we shall consider an example of importing into XMDS2 a function generated in Mat [...]
+
+Suppose we want to import the following function into XMDS2:
+
+.. math::
+    f(x) = x^2
+
+The first step is to create an hdf5 file, from XMDS2, which specifies the dimensions of the grid for the x dimension. Create and save a new XMDS2 file. For the purposes of this tutorial we shall call it "grid_specifier.xmds" with name "grid_specifier". Within this file, enter the following "dummy" vector - which we shall call "gen_dummy" - which depends on the x dimension:
+
+.. code-block:: xpdeint
+
+    <vector type="real" name="gen_dummy" dimensions="x">
+      <components>dummy</components>
+      <initialisation>
+      <![CDATA[ 
+        dummy = x;
+          ]]>
+      </initialisation>
+    </vector>
+
+What "dummy" is is not actually important. It is only necessary that it is a function of :math:`x`. However, it is important that the domain and lattice for the :math:`x` dimension are identical to those in the XMDS2 you plan to import the function into. We output the following xsil file (in hdf5 format) by placing a breakpoint in the sequence block as follows:
+
+.. code-block:: xpdeint
+
+    <sequence>
+      <breakpoint filename="grid.xsil" format="hdf5">
+          <dependencies>
+            gen_dummy
+          </dependencies>
+      </breakpoint>
+
+In terminal, compile the file "grid_specifier.xmds" in XMDS2 and run the c code as usual. This creates two files - "grid.xsil" and "grid.h5". The file "grid.h5" contains the list of points which make up the grids for the x dimensions. This data can now be used to ensure that the function :math:`f(x)` which we will import into XMDS2 is compatible with the the specified grid in your primary XMDS2 file.
+
+In order to read the "grid.h5" data into Mathematica version 6.0, type the following command into terminal:.. code-block::
+
+    xsil2graphics2 -e grid.xsil
+    
+This creates the Mathematica notebook "grid.nb". Open this notebook in Mathematica and evaluate the first set of cells. This has loaded the grid information into Mathematica. For example, suppose you have specified that the :math:`x` dimension has a lattice of 128 points and a domain of (-32, 32). Then calling "x1" in Mathematica should return the following list:
+
+.. code-block:: none
+ 
+  {-32., -31.5, -31., -30.5, -30., -29.5, -29., -28.5, -28., -27.5, 
+  -27., -26.5, -26., -25.5, -25., -24.5, -24., -23.5, -23., -22.5, 
+  -22., -21.5, -21., -20.5, -20., -19.5, -19., -18.5, -18., -17.5, 
+  -17., -16.5, -16., -15.5, -15., -14.5, -14., -13.5, -13., -12.5, 
+  -12., -11.5, -11., -10.5, -10., -9.5, -9., -8.5, -8., -7.5, -7., 
+  -6.5, -6., -5.5, -5., -4.5, -4., -3.5, -3., -2.5, -2., -1.5, -1., 
+  -0.5, 0., 0.5, 1., 1.5, 2., 2.5, 3., 3.5, 4., 4.5, 5., 5.5, 6., 6.5, 
+  7., 7.5, 8., 8.5, 9., 9.5, 10., 10.5, 11., 11.5, 12., 12.5, 13., 
+  13.5, 14., 14.5, 15., 15.5, 16., 16.5, 17., 17.5, 18., 18.5, 19., 
+  19.5, 20., 20.5, 21., 21.5, 22., 22.5, 23., 23.5, 24., 24.5, 25., 
+  25.5, 26., 26.5, 27., 27.5, 28., 28.5, 29., 29.5, 30., 30.5, 31., 
+  31.5}
+
+This is, of course, the list of points which define our grid.
+
+We are now in a position to define the function :math:`f(x)` in Mathematica. Type the following command into a cell in the Mathematica notebook "grid.nb":
+
+.. code-block:: none
+
+  f[x_]:= x^2
+
+At this stage this is an abstract mathematical function as defined in Mathematica. What we need is a list of values for :math:`f(x)` corresponding to the specified grid points. We will call this list "func". This achieved by simply acting the function on the list of grid points "x1":
+
+.. code-block:: none
+
+  func := f[x1]
+
+For the example grid mentioned above, calling "func" gives the following list:
+
+.. code-block:: none
+
+  {1024., 992.25, 961., 930.25, 900., 870.25, 841., 812.25, 784.,
+  756.25, 729., 702.25, 676., 650.25, 625., 600.25, 576., 552.25, 529., 
+  506.25, 484., 462.25, 441., 420.25, 400., 380.25, 361., 342.25, 324., 
+  306.25, 289., 272.25, 256., 240.25, 225., 210.25, 196., 182.25, 169., 
+  156.25, 144., 132.25, 121., 110.25, 100., 90.25, 81., 72.25, 64., 
+  56.25, 49., 42.25, 36., 30.25, 25., 20.25, 16., 12.25, 9., 6.25, 4., 
+  2.25, 1., 0.25, 0., 0.25, 1., 2.25, 4., 6.25, 9., 12.25, 16., 20.25, 
+  25., 30.25, 36., 42.25, 49., 56.25, 64., 72.25, 81., 90.25, 100., 
+  110.25, 121., 132.25, 144., 156.25, 169., 182.25, 196., 210.25, 225., 
+  240.25, 256., 272.25, 289., 306.25, 324., 342.25, 361., 380.25, 400., 
+  420.25, 441., 462.25, 484., 506.25, 529., 552.25, 576., 600.25, 625., 
+  650.25, 676., 702.25, 729., 756.25, 784., 812.25, 841., 870.25, 900., 
+  930.25, 961., 992.25}
+  
+  
+The next step is to export the list "func" as an h5 file that XMDS2 can read. This is done by typing the following command into a Mathematica cell:
+  
+.. code-block:: none
+  
+   SetDirectory[NotebookDirectory[]];
+   Export["func.h5", {func, x1}, {"Datasets", { "function_x", "x"}}]
+   
+In the directory containing the notebook "grid.nb" you should now see the file "func.h5". This file essentially contains the list ``{func, x1}``. However, the hdf5 format stores func and x1 as separate entities called "Datasets". For importation into XMDS2 it is necessary that these datasets are named. This is precisely what the segment ``{"Datasets", { "function_x", "x"}}`` in the above Mathematica command does. The dataset corresponding to the grid x1 needs to be given the name of the  [...]
+
+The final step is to import the file "func.h5" into your primary XMDS2 file. This data will be stored as a vector called "gen_function_x", in component "function_x".
+
+.. code-block:: xpdeint
+
+  <vector type="real" name="gen_function_x" dimensions="x">
+    <components>function_x</components> 
+    <initialisation kind="hdf5">
+      <filename> function_x.h5 </filename>
+    </initialisation>
+  </vector>
+  
+You're now done. Anytime you want to use :math:`f(x)` you can simply refer to "function_x" in the vector "gen_function_x".
+
+The situation is slightly more complicated if the function you wish to import depends on more than one dimension. For example, consider
+
+.. math::
+    g(x,y) = x \sin(y)
+
+As for the single dimensional case, we need to export an hdf5 file from XMDS2 which specifies the dimensions of the grid. As in the one dimensional case, this is done by creating a dummy vector which depends on all the relevant dimensions:
+
+.. code-block:: xpdeint
+
+    <vector type="real" name="gen_dummy" dimensions="x y">
+      <components>dummy</components>
+      <initialisation>
+      <![CDATA[ 
+        dummy = x;
+          ]]>
+      </initialisation>
+    </vector>
+    
+and exporting it as shown above.
+
+After importing the grid data into Mathematica, define the multi-dimensional function which you wish to import into XMDS2:
+
+.. code-block:: none
+
+  g[x_,y_]:= x*Sin[y]
+  
+We need to create a 2x2 array of data which depends upon the imported lists x1 and y1. This can be done by using the Table function:
+
+.. code-block:: none
+
+  func := Table[g[x, p], {x, x1}, {p, p1}]
+  
+This function can be exported as an h5 file,
+
+.. code-block:: none
+  
+  SetDirectory[NotebookDirectory[]];
+  Export["func.h5", {func, x1, y1}, {"Datasets", { "function_x", "x", "y"}}]
+
+and imported into XMDS2 as outlined above.
+
+.. _Convolutions:
+
+Convolutions and Fourier transforms
+-----------------------------------
+
+When evaluating a numerical Fourier transform, XMDS2 doesn't behave as expected. While many simulations have ranges in their spatial coordinate (here assumed to be x) that range from some negative value :math:`x_\text{min}` to some positive value :math:`x_\text{max}`, the Fourier transform used in XMDS2 treats all spatial coordinates as starting at zero. The result of this is that a phase factor of the form :math:`e^{-i x_\text{min} k}` is applied to the Fourier space functions after all [...]
+
+The standard Fourier transform is
+
+.. math::
+
+	\mathcal{F}\left[f(x)\right](k) = \frac{1}{\sqrt{2\pi}}\int_{x_\text{min}}^{x_\text{max}} f(x) e^{-i x k} dx
+
+The XMDS2 Fourier transform is
+
+.. math::
+	\tilde{\mathcal{F}}\left[f(x)\right](k) &= \frac{1}{\sqrt{2\pi}}\int_{x_\text{min}}^{x_\text{max}} f(x) e^{-i (x+ x_\text{min}) k} dx \\
+	&= e^{-i x_\text{min} k} \mathcal{F}\left[f(x)\right](k)
+
+When the number of forward Fourier transforms and backwards Fourier transforms are unequal a phase factor is required. Some examples of using Fourier transforms in XMDS2 are shown below.
+
+Example 1
+^^^^^^^^^
+
+.. image:: images/FourierTransformEx1.*
+    :align: center
+
+When data is input in Fourier space and output in real space there is one backwards Fourier transform is required. Therefore the Fourier space data must be multiplied by a phase factor before the backwards Fourier transform is applied.
+
+.. math::
+
+	\mathcal{F}^{-1}[F(k)](x) = \tilde{\mathcal{F}}[e^{i x_\text{min} k} F(k)](x)
+
+Example 2
+^^^^^^^^^
+.. image:: images/FourierTransformEx2.*
+    :align: center
+    
+Functions of the form :math:`h(x) = \int f(x') g(x-x') dx'` can be evaluated using the convolution theorem:
+
+.. math::
+
+	\mathcal{F}[h(x)](k) = \mathcal{F}[f(x)](k) \times \mathcal{F}[g(x)](k)
+
+This requires two forward Fourier transforms to get the two functions f and g into Fourier space, and one backwards Fourier transform to get the resulting product back into real space. Thus in Fourier space the product needs to be multiplied by a phase factor :math:`e^{-i x_\text{min} k}`
+
+
+Example 3
+^^^^^^^^^
+.. image:: images/FourierTransformEx3.*
+    :align: center
+    
+Sometimes when the convolution theorem is used one of the forward Fourier transforms is calculated analytically and input in Fourier space. In this case only one forward numerical Fourier transform and one backward numerical Fourier transform is used. The number of forward and backward transforms are equal, so no phase factor is required.
+
+.. _LooseGeometryMatchingMode:
+
+'Loose' ``geometry_matching_mode``
+----------------------------------
+
+.. _DimensionAliases:
+
+Dimension aliases
+-----------------
+
+Dimension aliases specify that two or more dimensions have exactly the same ``lattice``, ``domain`` and ``transform``.  This can be useful in situations where the problem enforces this, for example when computing correlation functions or representing square matrices.  
+
+Dimension aliases are not just a short-hand for defining an additional dimension, they also permit dimensions to be accessed :ref:`non-locally <ReferencingNonlocal>`, which is essential when computing spatial correlation functions.
+
+Here is how to compute a spatial correlation function :math:`g^{(1)}(x, x') = \psi^*(x) \psi(x')` of the quantity ``psi``:
+
+.. code-block:: xpdeint
+
+  <simulation xmds-version="2">
+    
+    <!-- name, features block -->
+        
+    <geometry>
+      <propagation_dimension> t </propagation_dimension>
+      <transverse_dimensions>
+        <dimension name="x" lattice="1024" domain="(-1.0, 1.0)" aliases="xp" />
+      </transverse_dimensions>
+    </geometry>
+    
+    <vector name="wavefunction" type="complex" >
+      <components> psi </components>
+      <initialisation>
+        <!-- initialisation code -->
+      </initialisation>
+    </vector>
+    
+    <computed_vector name="correlation" dimensions="x xp" type="complex" >
+      <components> g1 </components>
+      <evaluation>
+        <dependencies> wavefunction </dependencies>
+        <![CDATA[
+          g1 = conj(psi(x => x)) * psi(x => xp);
+        ]]>
+      </evaluation>
+    </computed_vector>
+    
+    <!-- integration and sampling code -->
+    
+  </simulation>
+
+In this simulation note that the vector ``wavefunction`` defaults to only having the dimension "x" even though "xp" is also a dimension (implicitly declared through the ``aliases`` attribute).  ``vector``'s without an explicit ``dimensions`` attribute will only have the dimensions that are explicitly listed in the ``transverse_dimensions`` block, i.e. this will not include aliases.
+
+See the example ``groundstate_gaussian.xmds`` for a complete example.
+      
\ No newline at end of file
diff --git a/admin/userdoc-source/conf.py b/admin/userdoc-source/conf.py
new file mode 100644
index 0000000..712fb4a
--- /dev/null
+++ b/admin/userdoc-source/conf.py
@@ -0,0 +1,188 @@
+# -*- coding: utf-8 -*-
+#
+# XMDS2 documentation build configuration file, created by
+# sphinx-quickstart on Tue Nov 18 15:10:03 2008.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# The contents of this file are pickled, so don't put values in the namespace
+# that aren't pickleable (module imports are okay, they're removed automatically).
+#
+# All configuration values have a default value; values that are commented out
+# serve to show the default value.
+
+import sys, os
+
+# If your extensions are in another directory, add it here. If the directory
+# is relative to the documentation root, use os.path.abspath to make it
+# absolute, like shown here.
+#sys.path.append(os.path.abspath('some/directory'))
+
+# General configuration
+# ---------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.mathjax']
+
+if os.path.exists('_static/MathJax/MathJax.js'):
+    mathjax_path = 'MathJax/MathJax.js?config=TeX-AMS_HTML,mathjax-xmds'
+else:
+    mathjax_path = 'http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js'
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['.templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General substitutions.
+project = u'XMDS2'
+copyright = u'2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson'
+
+# The default replacements for |version| and |release|, also used in various
+# other places throughout the built documents.
+#
+# The short X.Y version.
+version = '2.1'
+# The full version, including alpha/beta/rc tags.
+release = '2.1.4'
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# List of directories, relative to source directories, that shouldn't be searched
+# for source files.
+exclude_trees = []
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+# pygments_style = 'sphinx'
+pygments_style = 'friendly_plus'
+
+highlight_language='xmds2'
+
+# Options for HTML output
+# -----------------------
+
+# The style sheet to use for HTML and HTML Help pages. A file of that name
+# must exist either in Sphinx' static/ path, or in one of the custom paths
+# given in html_static_path.
+html_style = 'default.css'
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+html_logo = 'images/xmds_logo.png'
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+html_favicon = 'images/xmds_favicon.ico'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+#html_sidebars = {'**': ['globaltoc.html', 'localtoc.html','searchbox.html']}
+html_sidebars = {'**': ['localtoc.html','searchbox.html']}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_use_modindex = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, the reST sources are included in the HTML build as _sources/<name>.
+#html_copy_source = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = ''
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'xpdeintdoc'
+
+
+# Options for LaTeX output
+# ------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, document class [howto/manual]).
+latex_documents = [
+  ('documentation_toc', 'xmds2.tex', u'XMDS2 Documentation',
+   u'Graham Dennis, Joe Hope and Mattias Johnsson', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+latex_logo = 'images/xmds_logo.pdf'
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_use_modindex = True
diff --git a/admin/userdoc-source/developer.rst b/admin/userdoc-source/developer.rst
new file mode 100644
index 0000000..2e77a43
--- /dev/null
+++ b/admin/userdoc-source/developer.rst
@@ -0,0 +1,121 @@
+Developer Documentation
+=======================
+
+Developers need to know more than users.  For example, they need to know about the test suite, and writing test cases.  They need to know how to perform a developer installation.  They need to know how to edit and compile this documentation.  They need a step-by-step release process.
+
+.. _TestScripts:
+
+Test scripts
+------------
+
+Every time you add a new feature and/or fix a new and exciting bug, it is a great idea to make sure that the new feature works and/or the bug stays fixed.  Fortunately, it is pleasantly easy to add a test case to the testing suite.
+
+1. Write normal XMDS script that behaves as you expect.
+2. Add a ``<testing>`` element to your script.  You can read the description of this element and its contents below, and have a look at other testcases for examples, but the basic structure is simple:.
+
+.. parsed-literal::
+
+      <:ref:`testing <TestingElement>`> 
+        <:ref:`command_line <CommandLineElement>`> <:ref:`/command_line <CommandLineElement>`>
+        <:ref:`arguments <ArgumentsElement>`>
+          <:ref:`argument <ArgumentElement>` />
+          <:ref:`argument <ArgumentElement>` />
+          ...
+        <:ref:`/arguments <ArgumentsElement>`>
+        <:ref:`input_xsil_file <InputXSILFileElement>` />
+        <:ref:`xsil_file <XSILFileElement>`>
+          <:ref:`moment_group <MomentGroupElement>` />
+          <:ref:`moment_group <MomentGroupElement>` />
+          ...
+        <:ref:`/xsil_file <XSILFileElement>`>
+      <:ref:`/testing <TestingElement>`>
+      
+3. Put into the appropriate ``testsuite/`` directory.
+4. run ``./run_tests.py`` This will automatically generate your ``_expected`` files.
+5. Commit the ``.xmds``, ``*_expected.xsil`` file and any ``*_expected*`` data files.
+  
+.. _TestingElement:
+
+Testing element
+~~~~~~~~~~~~~~~
+
+
+
+.. _CommandLineElement:
+
+command_line element
+~~~~~~~~~~~~~~~~~~~~
+
+
+.. _InputXSILFileElement:
+
+input_xsil_file element
+~~~~~~~~~~~~~~~~~~~~~~~
+
+
+.. _XSILFileElement:
+
+xsil_file element
+~~~~~~~~~~~~~~~~~
+
+
+.. _MomentGroupElement:
+
+moment_group element
+~~~~~~~~~~~~~~~~~~~~
+
+
+
+Steps to update ``XMDS`` script validator (XML schema)
+------------------------------------------------------
+
+1. Modify ``xpdeint/support/xpdeint.rnc``. This is a RelaxNG compact file, which specifies the XML schema which is only used for issuing warnings to users about missing or extraneous XML tags / attributes.
+2. Run ``make`` in ``xpdeint/support/`` to update ``xpdeint/support/xpdeint.rng``. This is the file which is actually used, which is in RelaxNG format, but RelaxNG compact is easier to read and edit.
+3. Commit both ``xpdeint/support/xpdeint.rnc`` and ``xpdeint/support/xpdeint.rng``.
+
+
+Directory layout
+----------------
+
+XMDS2's code and templates
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+All ``.tmpl`` files are Cheetah template files.  These are used to generate C++ code.  These templates are compiled as part of the XMDS2 build process to ``.py`` files of the same name.  Do not edit the generated ``.py`` files, always edit the ``.tmpl`` files and regenerate the corresponding ``.py`` files with ``make``.
+
+* ``xpdeint/``: 
+	* ``Features/``: Code for all ``<feature>`` elements, such as ``<globals>`` and ``<auto_vectorise>``
+		* ``Transforms/``: Code for the Fourier and matrix-based transforms (including MPI variants).
+	* ``Geometry/``: Code for describing the geometry of simulation dimensions and domains.  Includes code for ``Geometry``, ``Field`` and all ``DimensionRepresentations``.
+	* ``Operators/``: Code for all ``<operator>`` elements, including ``IP``, ``EX`` and the temporal derivative operator ``DeltaA``.
+	* ``Segments/``: Code for all elements that can appear in a ``<segments>`` tag.  This includes ``<integrate>``, ``<filter>``, and ``<breakpoint>``.
+		* ``Integrators``: Code for fixed and adaptive integration schemes, and all steppers (e.g. ``RK4``, ``RK45``, ``RK9``, etc.)
+	* ``Stochastic/``: Code for all random number generators and the random variables derived from them.
+		* ``Generators/``: Code for random number generators, includes ``dSFMT``, ``POSIX``, ``Solirte``.
+		* ``RandomVariables/``: Code for the random variables derived from the random number generators.  These are the gaussian, poissonian and uniform random variables.
+	* ``SimulationDrivers/``: Code for all ``<driver>`` elements.  In particular, this is where the location of MPI and multi-path code.
+	* ``Vectors/``: Code for all ``<vector>`` elements, and their initialisation.  This includes normal ``<vector>`` elements as well as ``<computed_vector>`` and ``<noise_vector>`` elements.
+	* ``includes/``: C++ header and sources files used by the generated simulations.
+	* ``support/``: Support files
+		* ``wscript``: ``waf`` build script for configuring and compiling generated simulations
+		* ``xpdeint.rnc``: Compact RelaxNG XML validation for XMDS scripts.  This is the source file for the XML RelaxNG file ``xpdeint.rng``
+		* ``xpdeint.rng``: RelaxNG XML validation for XMDS scripts.  To regenerate this file from ``xpdeint.rnc``, just run ``make`` in this directory.
+	* ``waf/``: Our included version of the Python configuration and build tool ``waf``.
+	* ``waf_extensions/``: ``waf`` tool for compiling Cheetah templates.
+	* ``xsil2graphics2/``: Templates for the output formats supported by ``xsil2graphics2``.
+	* ``wscript``: ``waf`` build script for XMDS2 itself.
+	* ``CodeParser.py``: Minimally parses included C++ code for handling nonlocal dimension access, IP/EX operators and IP operator validation.
+	* ``Configuration.py``: Manages configuration and building of generated simulations.
+	* ``FriendlyPlusStyle.py``: Sphinx plug-in to improve formatting of XMDS scripts in user documentation.
+	* This directory also contains code for the input script parser, code blocks, code indentation, and the root ``_ScriptElement`` class.
+
+
+Support files
+~~~~~~~~~~~~~
+
+* ``admin/``: Documentation source, Linux installer and release scripts.
+	* ``developer-doc-source/``: source for epydoc python class documentation (generated from python code).
+	* ``userdoc-source/``: source for the user documentation (results visible at www.xmds.org and xmds2.readthedocs.org).
+	* ``xpdeint.tmbundle/``: TextMate support bundle for Cheetah templates and XMDS scripts
+* ``bin/``: Executable scripts to be installed as part of XMDS2 (includes ``xmds2`` and ``xsil2graphics2``).
+* ``examples/``: Example XMDS2 input scripts demonstrating most of XMDS2's features.
+* ``testsuite/``: Testsuite of XMDS2 scripts.  Run the testsuite by executing ``./run_tests.py``
\ No newline at end of file
diff --git a/admin/userdoc-source/documentation_toc.rst b/admin/userdoc-source/documentation_toc.rst
new file mode 100644
index 0000000..bfb1f30
--- /dev/null
+++ b/admin/userdoc-source/documentation_toc.rst
@@ -0,0 +1,33 @@
+.. _Documentation:
+
+Welcome to the documentation for XMDS2!
+=======================================
+
+.. toctree::
+   :maxdepth: 2
+   
+   introduction
+   
+   installation
+
+   tutorial
+   
+   worked_examples
+
+   reference_index
+   
+   advanced_topics
+   
+   faq
+   
+   upgrade
+   
+   optimisation_hints
+   
+   xsil2graphics2
+
+   developer
+
+   licensing
+   
+   news
diff --git a/admin/userdoc-source/faq.rst b/admin/userdoc-source/faq.rst
new file mode 100644
index 0000000..5ab1d77
--- /dev/null
+++ b/admin/userdoc-source/faq.rst
@@ -0,0 +1,64 @@
+.. _FAQ:
+
+Frequently Asked Questions
+==========================
+
+XMDS scripts look complicated! How do I start?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you're unfamiliar with XMDS2, writing a script from scratch might seem difficult. In most cases, however, the best approach is to take an existing script and modify it for your needs. At the most basic level, you can simply take a script from the /examples directory that is similar to what you want to do, change the name of the integration variable(s) and replace the line describing the differential equation to use your DE instead. That's all you need to do, and will ensure all the sy [...]
+
+You can then incrementally change things such as the number of output points, what quantities get output, number of grid points, and so on. Many XMDS2 users have never written a script from scratch, and just use their previous scripts and example scripts as a scaffold when they create a script for a new problem.
+
+
+Where can I get help?
+~~~~~~~~~~~~~~~~~~~~~
+
+The documentation on this website is currently incomplete, but it still covers a fair bit and is worth reading. Similarly, the example scripts in the /examples directory cover most of the functionality of XMDS2, so it's worth looking looking through them to see if any of them do something similar to what you're trying to do.
+
+You should also feel free to email questions to the XMDS users' mailing list at xmds-users at lists.sourceforge.net, where the developers and other users can assist you. You can join the mailing list by going to http://sourceforge.net/projects/xmds/ and clicking on "mailing lists." Also, if you look through the mailing list archives, your particular problem may already have been discussed.
+
+
+How should I cite XMDS2?
+~~~~~~~~~~~~~~~~~~~~~~~~
+If you publish work that has involved XMDS2, please cite it as: `Comput. Phys. Commun. 184, 201-208 (2013) <http://dx.doi.org/10.1016/j.cpc.2012.08.016>`_.
+
+
+I think I found a bug! Where should I report it?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Please report bugs to the developer mailing list at xmds-devel at lists.sourceforge.net. In your email, please include a description of the problem and attach the XMDS2 script that triggers the bug.
+
+
+How do I put time dependence into my vectors?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Standard vectors can't have time dependence (or, more accurately, depend on the ``propagation_dimension`` variable), but computed vectors can. So, for example, if you have set your ``propagation_dimension`` as "t", you can simply use the variable "t" in your computed vector and it will work. 
+
+Alternatively, you can explicitly use the ``propagation_dimension`` variable in your differential equation inside the ``<operators>`` block.  
+
+
+Can I specify the range of my domain and number of grid points at run-time?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Yes, you can. In your script, specify the domain and number of grid points as arguments to be passed in at run-time, use those variables in your ``<geometry>`` block rather than explicitly specifying them, and use the ``<validation kind="run-time" />`` feature. See the :ref:`Validation <Validation>` entry in the Reference section for an example.
+
+While the domain can always be specified in this way, specifying the lattice size at run-time is currently only allowed with the following transforms: 'dct', 'dst', 'dft' and 'none' (see :ref:`Transforms <Validation>` in the Reference section).
+
+Also note that for some multi-dimensional spaces using different transforms, XMDS2 will sometimes optimise the code it generates based on the relative sizes of the dimensions. If one or more of the lattices are specified at run-time it is unable to do this and will have to make guesses. In some situations this may result in slightly slower code.
+
+
+When can I use IP operators (and why should I) and when must I use EX operators?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+An :ref:`<operator><OperatorNamesElement>` that specifies named operators to be used in integration equations can have the ``kind="IP"`` or ``kind="EX"`` attribute, standing for 'interaction picture' and 'explicit' operators respectively.  Explicit operators can be used in all situations, and simply construct and calculate a new vector of the form in the square brackets.  IP operators use less memory and can improve speed by allowing larger timesteps, but have two important restrictions. [...]
+
+Some explanation is in order.  The IP algorithm applies the operator separately to the rest of the evolution.  The reason this can be so effective is that the separate evolution can be performed exactly.  The solution of the equation :math:`\frac{d \psi}{dt} = L \psi` is :math:`\psi(t+\Delta t) = exp(L \Delta t) \psi(t)` for arbitrarily large timestep :math:`\Delta t`.  For a diagonal linear ``L``, the matrix exponential is straightforward.  Also, when it is constant, then the exponentia [...]
+
+Therefore, the limitations of IP operators themselves means that they can only be applied to to named components of one of the integration vectors, and not functions of those components.  Furthermore, an IP operator acting on a component must only be used in the derivative for that particular component.  Secondly, due to the implementation of IP operators in XMDS2, it is not safe to use them in comments, or in conjunction with declared variables.  It is also not safe to multiply or divid [...]
+
+
+Visual Editors
+~~~~~~~~~~~~~~
+
+In this section goes stuff about how to set up TextMate (or other editors to highlight xpdeint scripts).
diff --git a/admin/userdoc-source/images/FourierTransformEx1.pdf b/admin/userdoc-source/images/FourierTransformEx1.pdf
new file mode 100644
index 0000000..840f843
Binary files /dev/null and b/admin/userdoc-source/images/FourierTransformEx1.pdf differ
diff --git a/admin/userdoc-source/images/FourierTransformEx1.png b/admin/userdoc-source/images/FourierTransformEx1.png
new file mode 100644
index 0000000..792c790
Binary files /dev/null and b/admin/userdoc-source/images/FourierTransformEx1.png differ
diff --git a/admin/userdoc-source/images/FourierTransformEx2.pdf b/admin/userdoc-source/images/FourierTransformEx2.pdf
new file mode 100644
index 0000000..1c31b06
Binary files /dev/null and b/admin/userdoc-source/images/FourierTransformEx2.pdf differ
diff --git a/admin/userdoc-source/images/FourierTransformEx2.png b/admin/userdoc-source/images/FourierTransformEx2.png
new file mode 100644
index 0000000..970db9a
Binary files /dev/null and b/admin/userdoc-source/images/FourierTransformEx2.png differ
diff --git a/admin/userdoc-source/images/FourierTransformEx3.pdf b/admin/userdoc-source/images/FourierTransformEx3.pdf
new file mode 100644
index 0000000..b9b49c8
Binary files /dev/null and b/admin/userdoc-source/images/FourierTransformEx3.pdf differ
diff --git a/admin/userdoc-source/images/FourierTransformEx3.png b/admin/userdoc-source/images/FourierTransformEx3.png
new file mode 100644
index 0000000..70ef606
Binary files /dev/null and b/admin/userdoc-source/images/FourierTransformEx3.png differ
diff --git a/admin/userdoc-source/images/fibre1024.pdf b/admin/userdoc-source/images/fibre1024.pdf
new file mode 100644
index 0000000..c17abb1
Binary files /dev/null and b/admin/userdoc-source/images/fibre1024.pdf differ
diff --git a/admin/userdoc-source/images/fibre1024.png b/admin/userdoc-source/images/fibre1024.png
new file mode 100644
index 0000000..b8a2b64
Binary files /dev/null and b/admin/userdoc-source/images/fibre1024.png differ
diff --git a/admin/userdoc-source/images/fibreSingle.pdf b/admin/userdoc-source/images/fibreSingle.pdf
new file mode 100644
index 0000000..e0e689c
Binary files /dev/null and b/admin/userdoc-source/images/fibreSingle.pdf differ
diff --git a/admin/userdoc-source/images/fibreSingle.png b/admin/userdoc-source/images/fibreSingle.png
new file mode 100644
index 0000000..5e756ec
Binary files /dev/null and b/admin/userdoc-source/images/fibreSingle.png differ
diff --git a/admin/userdoc-source/images/groundstateU2.pdf b/admin/userdoc-source/images/groundstateU2.pdf
new file mode 100644
index 0000000..bb4a54c
Binary files /dev/null and b/admin/userdoc-source/images/groundstateU2.pdf differ
diff --git a/admin/userdoc-source/images/groundstateU2.png b/admin/userdoc-source/images/groundstateU2.png
new file mode 100644
index 0000000..9a46c04
Binary files /dev/null and b/admin/userdoc-source/images/groundstateU2.png differ
diff --git a/admin/userdoc-source/images/groundstateU20.pdf b/admin/userdoc-source/images/groundstateU20.pdf
new file mode 100644
index 0000000..c322493
Binary files /dev/null and b/admin/userdoc-source/images/groundstateU20.pdf differ
diff --git a/admin/userdoc-source/images/groundstateU20.png b/admin/userdoc-source/images/groundstateU20.png
new file mode 100644
index 0000000..4b6e5d2
Binary files /dev/null and b/admin/userdoc-source/images/groundstateU20.png differ
diff --git a/admin/userdoc-source/images/kubo10000.pdf b/admin/userdoc-source/images/kubo10000.pdf
new file mode 100644
index 0000000..6ccd468
Binary files /dev/null and b/admin/userdoc-source/images/kubo10000.pdf differ
diff --git a/admin/userdoc-source/images/kubo10000.png b/admin/userdoc-source/images/kubo10000.png
new file mode 100644
index 0000000..6672c34
Binary files /dev/null and b/admin/userdoc-source/images/kubo10000.png differ
diff --git a/admin/userdoc-source/images/kuboSingle.pdf b/admin/userdoc-source/images/kuboSingle.pdf
new file mode 100644
index 0000000..2193e21
Binary files /dev/null and b/admin/userdoc-source/images/kuboSingle.pdf differ
diff --git a/admin/userdoc-source/images/kuboSingle.png b/admin/userdoc-source/images/kuboSingle.png
new file mode 100644
index 0000000..8426c0c
Binary files /dev/null and b/admin/userdoc-source/images/kuboSingle.png differ
diff --git a/admin/userdoc-source/images/lorenz.pdf b/admin/userdoc-source/images/lorenz.pdf
new file mode 100644
index 0000000..aa528d1
Binary files /dev/null and b/admin/userdoc-source/images/lorenz.pdf differ
diff --git a/admin/userdoc-source/images/lorenz.png b/admin/userdoc-source/images/lorenz.png
new file mode 100644
index 0000000..03083fa
Binary files /dev/null and b/admin/userdoc-source/images/lorenz.png differ
diff --git a/admin/userdoc-source/images/xmds_favicon.ico b/admin/userdoc-source/images/xmds_favicon.ico
new file mode 100644
index 0000000..4e53c4a
Binary files /dev/null and b/admin/userdoc-source/images/xmds_favicon.ico differ
diff --git a/admin/userdoc-source/images/xmds_favicon.png b/admin/userdoc-source/images/xmds_favicon.png
new file mode 100644
index 0000000..f4a807e
Binary files /dev/null and b/admin/userdoc-source/images/xmds_favicon.png differ
diff --git a/admin/userdoc-source/images/xmds_logo.pdf b/admin/userdoc-source/images/xmds_logo.pdf
new file mode 100644
index 0000000..465ba25
Binary files /dev/null and b/admin/userdoc-source/images/xmds_logo.pdf differ
diff --git a/admin/userdoc-source/images/xmds_logo.png b/admin/userdoc-source/images/xmds_logo.png
new file mode 100644
index 0000000..cfd7f0a
Binary files /dev/null and b/admin/userdoc-source/images/xmds_logo.png differ
diff --git a/admin/userdoc-source/index.rst b/admin/userdoc-source/index.rst
new file mode 100644
index 0000000..23f0b57
--- /dev/null
+++ b/admin/userdoc-source/index.rst
@@ -0,0 +1,17 @@
+.. xpdeint documentation master file, created by sphinx-quickstart on Tue Nov 18 15:10:03 2008.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+Welcome to XMDS2!
+=================
+
+This website provides the documentation for XMDS2 (an all-new version of :ref:`XMDS<XMDSHistory>`), a software package that allows the fast and easy solution of sets of ordinary, partial and stochastic differential equations, using a variety of efficient numerical algorithms.
+
+If you publish work that has involved XMDS2, please cite it as `Comput. Phys. Commun. 184, 201-208 (2013) <http://dx.doi.org/10.1016/j.cpc.2012.08.016>`_.
+
+Getting Started
+---------------
+
+To get a flavour of what XMDS2 can do, take a look at our :ref:`Quickstart Tutorial<QuickstartTutorial>`, then take a look at our comprehensive  :ref:`documentation<Documentation>`.  Automated installers are available for Linux and Mac OS X, refer to our :ref:`installation instructions<Installation>` for details.
+
+.. include:: news.rst 
\ No newline at end of file
diff --git a/admin/userdoc-source/installation.rst b/admin/userdoc-source/installation.rst
new file mode 100644
index 0000000..5555cdf
--- /dev/null
+++ b/admin/userdoc-source/installation.rst
@@ -0,0 +1,251 @@
+.. _Installation:
+
+************
+Installation
+************
+
+**XMDS2** can be installed on any unix-like system including Linux, Tru64, and Mac OS X.  It requires a C++ compiler, python, and several installed packages.  Many of these packages are optional, but a good idea to obtain full functionality.  
+
+Installers
+==========
+
+The easiest way to get started is with an installer.  If we don't have an installer for your system, follow the :ref:`manual installation <ManualInstallation>` instructions.
+
+.. tabularcolumns:: |c|c|c|
+
+.. list-table::
+    :widths: 15, 5, 5
+    :header-rows: 0
+
+    * - Linux (Ubuntu/Debian/Fedora/RedHat)
+
+      - `Download Linux Installer <http://svn.code.sf.net/p/xmds/code/trunk/xpdeint/admin/linux_installer.sh>`_
+
+      - :ref:`Learn more <linux_installation>`
+
+    * - OS X 10.6/10.7
+
+      - `Download OS X Installer <http://sourceforge.net/projects/xmds/files>`_
+
+      - :ref:`Learn more <mac_installation>`
+        
+    * - Other systems
+
+      - :ref:`Install from source <ManualInstallation>`
+      
+      -
+
+If you have one of the supported operating systems listed above, but you find the installer doesn't work for you, please let us know by emailing xmds-devel <at> lists.sourceforge.net. If you'd like to tweak the linux installer to work on a distribution we haven't tested, we'd love you to do that and let us know!
+
+.. _linux_installation:
+
+Linux installer instructions
+============================
+
+The linux installer has currently only been tested with Ubuntu, Debian, Fedora, and Red Hat. Download the installer here: http://svn.code.sf.net/p/xmds/code/trunk/xpdeint/admin/linux_installer.sh
+
+Once you have downloaded it, make the installer executable and run it by typing the following into a terminal::
+
+  chmod u+x linux_installer.sh
+  ./linux_installer.sh
+
+Alternatively, if you wish to download and run the installer in a single step, you can use the following command::
+
+  /bin/bash -c "$(wget -qO - http://svn.code.sf.net/p/xmds/code/trunk/xpdeint/admin/linux_installer.sh)"
+
+The linux installer installs all XMDS2 dependencies from your native package manager where possible (``apt-get`` for Ubuntu/Debian, ``yum`` for Fedora/Red Hat) but will download and compile the source code for libraries not available through the package manager. This means you'll need to be connected to the internet when running the installer. The installer should not be run with administrative privileges; it will ask you to enter your admin password at the appropriate point. 
+
+For instructions on how to install XMDS2 on systems where you lack administrative rights, see :ref:`ManualInstallation`.
+
+By default, this installer will install a known stable version of XMDS, which can be updated at any time by navigating to the XMDS directory and typing 'make update'. To install the latest developer version at the beginning, simply run the installer with the ``--develop`` option.
+
+Once XMDS2 has been installed, you can run it from the terminal by typing ``xmds2``. See the :ref:`QuickStartTutorial` for next steps.
+
+
+.. _mac_installation:
+
+Mac OS X Installation
+=====================
+
+Download
+--------
+
+Mac OS X 10.6 (Snow Leopard) or later XMDS 2 installer: http://sourceforge.net/projects/xmds/files/
+
+
+
+Using the Mac OS X Installer
+----------------------------
+
+A self-contained installer for Mac OS X 10.6 (Snow Leopard) and later is available from the link above. This installer is only compatible with Intel Macs.  This means that the older PowerPC architecture is *not supported*.  Xcode (Apple's developer tools) is required to use this installer. Xcode is available for free from the Mac App Store for 10.7 or later, and is available on the install disk of earlier Macs as an optional install.  For users of earlier operating systems (10.6.8 or ear [...]
+
+Once you have downloaded the XMDS installer, installation is as simple as dragging it to your Applications folder or any other location.  Click the XMDS application to launch it, and press the "Launch XMDS Terminal" button to open a Terminal window customised to work with XMDS.  The first time you do this, the application will complete the installation process.  This process can take a few minutes, but is only performed once.
+
+The terminal window launched by the XMDS application has environment variables set for using this installation of XMDS.  You can run XMDS in this terminal by typing ``xmds2``.  See the :ref:`QuickStartTutorial` for next steps.
+
+To uninstall XMDS, drag the XMDS application to the trash. XMDS places some files in the directory ``~/Library/XMDS``. Remove this directory to completely remove XMDS from your system.
+
+This package includes binaries for `OpenMPI <http://www.open-mpi.org>`_, `FFTW <http://www.fftw.org>`_, `HDF5 <http://www.hdfgroup.org/HDF5>`_ and `GSL <http://www.gnu.org/software/gsl>`_. These binaries are self-contained and do not overwrite any existing installations.
+
+.. _ManualInstallation:
+
+Manual installation from source
+===============================
+
+This installation guide will take you through a typical full install step by step. A large part of this procedure is obtaining and installing other libraries that XMDS2 requires, before installing XMDS2 itself. 
+
+While the instructions below detail these packages individually, if you have administrative privileges (or can request packages from your administrator) and if you are using an Ubuntu, Debian, Fedora or Red Hat linux distribution, you can install all required and optional dependencies (but not XMDS2 itself) via
+
+Ubuntu / Debian::
+
+  sudo apt-get install build-essential subversion libopenmpi-dev openmpi-bin python-dev python-setuptools python-cheetah python-numpy python-pyparsing python-lxml python-mpmath libhdf5-serial-dev libgsl0-dev python-sphinx python-h5py libatlas-base-dev
+
+Fedora / Red Hat::
+
+  sudo yum install gcc gcc-c++ make automake subversion openmpi-devel python-devel python-setuptools python-cheetah numpy gsl-devel python-sphinx libxml2-devel libxslt-devel atlas-devel hdf5-devel pyparsing pyparsing python-lxml python-mpmath h5py
+
+You will still have to download and build FFTW 3.3 from source (see below) since prebuilt packages with MPI and AVX support are not currently available in the repositories.
+
+Also note that this guide adds extra notes for users wishing to install XMDS2 using the SVN repository.  This requires a few extra steps, but allows you to edit your copy, and/or update your copy very efficiently (with all the usual advantages and disadvantages of using unreleased material).
+
+0. You will need a copy of XMDS2.  
+    The current release can be found at `Sourceforge <http://sourceforge.net/projects/xmds/>`_, and downloaded as a single file.
+    Download this file, and expand it in a directory where you want to keep the program files.
+    
+    * Developer-only instructions: You can instead check out a working copy of the source using SVN. 
+      In a directory where you want to check out the repository, run:
+      ``svn checkout https://svn.code.sf.net/p/xmds/code/trunk/xpdeint .``
+
+      (Only do this once.  To update your copy, type ``svn up`` or ``make update`` in the same directory, and then repeat any developer-only instructions below).
+    
+#. You will need a working C++ compiler.  
+    For Mac OS X, this means that the developer tools (XCode) should be installed.
+    One common free compiler is `gcc <http://gcc.gnu.org/>`_.  It can be downloaded using your favourite package manager.
+    XMDS2 can also use Intel's C++ compiler if you have it. 
+    Intel's compiler typically generates faster code than gcc, but it isn't free.
+
+#. You will need a `python distribution <http://www.python.org/>`_.  
+
+   * Mac OS X: It is pre-installed on Mac OS X 10.5 or later.
+   * Linux: It should be pre-installed. If not, install using your favourite package manager.
+   
+    We require python 2.4 or greater. XMDS2 does not support Python 3.
+   
+
+#. Install setuptools.
+    If you have root (sudo) access, the easy way to install this is by executing
+    ez_setup.py from the repository. Simply type ``sudo python ez_setup.py``
+
+       If you want to install into your home directory without root access, this is more complex:
+       
+       a) First create the path ~/lib/python2.5/site-packages (assuming you installed python version 2.5) and ~/bin
+          Add "export PYTHONPATH=~/lib/python2.5/site-packages:$PYTHONPATH" and "export PATH=~/bin:$PATH" (if necessary)
+          to your .bashrc file (and run ". ~/.bashrc")
+       
+       b) If necessary install setuptools, by executing ez_setup.py from the repository.
+          ``python ez_setup.py --prefix=~``
+          
+    If you use Mac OS X 10.5 or later, or installed the Enthought Python Distribution on Windows, then setuptools is already installed.
+    Though if the next step fails, you may need to upgrade setuptools.  To do that, type ``sudo easy_install -U setuptools``
+
+#. Install HDF5 and FFTW3 (and optionally MPI).
+    .. _hdf5_Installation:
+    
+    #. **HDF5** is a library for reading and writing the `Hierarchical Data Format <http://www.hdfgroup.org/HDF5/>`_.
+         This is a standardised data format which it is suggested that people use in preference to the older 'binary' output (which is 
+         compatible with xmds-1). The advantage of HDF5 is that this data format is understood by a variety of other tools. xsil2graphics2
+         provides support for loading data created in this format into Mathematica and Matlab.
+         
+         XMDS2 only requires the single process version of HDF5, so there is no need to install the MPI version.
+       
+         \* Sidebar: Installing HDF5 from source follows a common pattern, which you may find yourself repeating later:  
+         
+            #. After extracting the source directory, type ``configure`` and then add possible options.
+            
+                (For HDF5, install with the ``--prefix=/usr/local/`` option if you want XMDS2 to find the library automatically.  This is rarely needed for other packages.)
+                
+            #. Once that is finished, type ``make``.  Then wait for that to finish, which will often be longer than you think.
+            
+            #. Finally, type ``sudo make install`` to install it into the appropriate directory.
+        
+    #. **FFTW** is the library XMDS2 uses for Fourier transforms. 
+         This is the transform most people will use in their simulations. If you need
+         support for MPI distributed simulations, you must configure FFTW to use MPI.
+  
+         FFTW is available for free at the `FFTW website <http://www.fftw.org/>`_.
+         To configure and compile it, follow the steps described in the HDF5 sidebar above.  
+         You may wish to add the ``--enable-mpi --disable-fortran`` options to the ``configure`` command.
+
+    #. **MPI** is an API for doing parallel processing.
+         XMDS2 can use MPI to parallelise simulations on multi-processor/multi-core computers, or clusters of computers.
+         Many supercomputing systems come with MPI libraries pre-installed.
+         The `Open MPI <http://www.open-mpi.org/>`_ project has free distributions of this library available.
+		 
+	 If you intend to take advantage of XMDS2's multi-processing features, you must install MPI, and configure FFTW3 to use it.
+
+
+
+#. There are a range of optional installs.  We recommend that you install them all if possible:
+
+    #. A Matrix library like `ATLAS <http://math-atlas.sourceforge.net/>`_, Intel's `MKL <http://software.intel.com/en-us/intel-mkl/>`_ or the `GNU Scientific library (GSL) <http://www.gnu.org/software/gsl/>`_ 
+         These libraries allow efficient implementation of transform spaces other than Fourier space.
+         Mac OS X comes with its own (fast) matrix library.
+    
+    #. **numpy** is a tool that XMDS2 uses for automated testing.
+         It can be installed with ``sudo easy_install numpy``. 
+         
+         Mac OS X 10.5 and later come with numpy.
+         
+    #. **lxml** is used to validate the syntax of scripts passed to XMDS2. 
+         If you have root access, this can be installed with the command ``sudo easy_install lxml``
+
+         You will need to have 'libxml2' and 'libxslt' installed (via your choice of package manager) to install lxml.  
+         Sufficient versions are preinstalled on Mac OS X 10.6.
+
+         If you don't have root access or want to install into your home directory, use:
+            ``easy_install --prefix=~ lxml``
+
+    #. **h5py** is needed for checking the results of XMDS2 tests that generate HDF5 output.
+           h5py requires numpy version 1.0.3 or later. 
+           
+           Upgrading `h5py <http://h5py.alfven.org/>`_ on Mac OS X is best done with the source of the package, as the easy_install option can get confused with multiple numpy versions.
+           (Mac OS X Snow Leopard comes with version 1.2.1). 
+           After downloading the source, execute ``python ./setup.py build`` in the source directory, and then ``python ./setup.py install`` to install it.  
+
+#. Install XMDS2 into your python path by running (in the xmds-2.1.4/ directory):
+    ``sudo ./setup.py develop``
+
+    If you want to install it into your home directory, type ``./setup.py develop --prefix=~``
+    
+    This step requires access to the net, as it downloads any dependent packages.  If you are behind a firewall, you may need to set your HTTP_PROXY environment variable in order to do this.
+
+    * Developer only instructions: 
+        The Cheetah templates (\*.tmpl) must be compiled into python.
+        To do this, run ``make`` in the xmds-2.1.4/ directory.
+
+    * Developer-only instructions: 
+        If you have 'numpy' installed, test XMDS2 by typing ``./run_tests.py`` in the xmds-2.1.4/ directory.
+        The package 'numpy' is one of the optional packages, with installation instructions below.
+       
+    * Developer-only instructions: 
+        To build the user documentation, you first need to install sphinx, either via your package manager or:
+        ``sudo easy_install Sphinx``
+
+        Then, to build the documentation, in the xmds-2.1.4/admin/userdoc-source/ directory run: ``make html``
+
+        If this results in an error, you may need to run ``sudo ./setup.py develop``
+
+        The generated html documentation will then be found at xmds-2.1.4/documentation/index.html
+		
+#. Configure XMDS2 by typing ``xmds2 --reconfigure``.  If XMDS2 is unable to find a library, you can tell XMDS2 where these libraries are located by adding ``include`` and ``lib`` search paths using the ``--include-path`` and ``--lib-path`` options.  For example, if FFTW3 is installed in ``/apps/fftw3`` with headers in ``/apps/fftw3/include/`` and the libraries in ``/apps/fftw3/lib``, (re)configure XMDS2 by typing:
+
+	* ``xmds2 --reconfigure --include-path /apps/fftw3/include --lib-path /apps/fftw3/lib``.
+	
+	If you need to use additional compiler or link flags for XMDS2 to use certain libraries, set the ``CXXFLAGS`` or ``LINKFLAGS`` environment variables before calling ``xmds2 --reconfigure``.  For example, to pass the compiler flag ``-pedantic`` and the link flag ``-lm``, use:
+	
+	* ``CXXFLAGS="-pedantic" LINKFLAGS="-lm" xmds2 --reconfigure``.
+
+**Congratulations!** You should now have a fully operational copy of xmds2 and xsil2graphics2.  You can test your copy using examples from the "xmds-2.1.4/examples" directory, and follow the worked examples in the :ref:`QuickStartTutorial` and :ref:`WorkedExamples`.
+
+
+
diff --git a/admin/userdoc-source/introduction.rst b/admin/userdoc-source/introduction.rst
new file mode 100644
index 0000000..d1a3169
--- /dev/null
+++ b/admin/userdoc-source/introduction.rst
@@ -0,0 +1,31 @@
+Introduction
+============
+
+Welcome to **XMDS2** (codenamed `xpdeint`), which is an all-new version of :ref:`XMDS<XMDSHistory>`.  Prepare for fast, easily-extended simulations with minimal code error.
+
+**Description:**   The purpose of XMDS2 is to simplify the process of creating simulations that solve systems of initial-value first-order partial and ordinary differential equations. Instead of going through the error-prone process of writing by hand thousands of lines of code, XMDS2 enables many problems to be described in a simple XML format. From this XML description XMDS2 writes a C++ simulation that solves the problem using fast algorithms. Anecdotally, the code generated by XMDS2  [...]
+
+XMDS2 can be used to simulate almost any set of (coupled) (partial) (stochastic) differential equations in any number of dimensions.  It can input and output data in a range of data formats, produce programs that can take command-line arguments, and produce parallelised code suitable for either modern computer architectures or distributed clusters.
+
+If this is your first time with XMDS, then an ideal place to start is the :ref:`QuickStartTutorial`, where we will show you how to write a basic simulation.  :ref:`Installation` instructions should get you up and running and able to start playing with the large library of examples provided. The impatient will probably have good luck browsing the examples library included with the source, and the :ref:`WorkedExamples` in this documentation for something that looks like their intended simulation.
+
+If you are upgrading from **XMDS version 1.x**, then after following the installation instructions (:ref:`Installation`), you might want to have a quick read of the note for upgraders (:ref:`UpgradeFromXMDS1`).  The syntax of the XML scripts has changed, but hopefully you will find the new scripts very intuitive.
+
+Detailed advice on input/output issues, and ways to code more complicated simulations can be found in :ref:`AdvancedTopics`.
+
+XMDS2 should be cited as `Comput. Phys. Commun. 184, 201-208 (2013) <http://dx.doi.org/10.1016/j.cpc.2012.08.016>`_.
+
+.. _XMDSHistory:
+
+**History:**   **XMDS** was created in 1997 by Peter Drummond and Greg Collecutt, who conceived of the idea of using an XML-based code generator to simplify the process of integrating systems of equations with arbitrary dimension [#f1]_.  The first version was written in C, and featured a very flexible, strongly convergent stochastic algorithm: the :ref:`semi-implicit algorithm<SI>` [#f2]_.  Released under a public licence, it began to receive attention across several research groups.  O [...]
+    
+In 2003, the increased scope of the package prompted a complete rewrite by Greg Collecutt (using C++), which lead to **XMDS 1.0**.  It was placed on sourceforge, and over a dozen developers contributed from 2003-2007 to help XMDS address a wider range of problems with a range of modern algorithms and support for parallel supercomputing.  The documentation and installation method was improved enabling the software to be used in a wider context, and XMDS gained many users from across the w [...]
+    
+In 2008 a second complete rewrite was undertaken, largely by Graham Dennis (using Cheetah templates in python), leading to the current version **XMDS2**.  This restructuring of the internal treatment of XML elements and the generated code allowed a new range of extensions to be explored.  These included possibilities such as integrating multiple fields with different dimensionality, a more general set of differential equations that can be solved efficiently, and multiple choices of trans [...]
+
+
+.. rubric:: Footnotes
+
+.. [#f1] G.R.Collecutt and P.D.Drummond, `Xmds: eXtensible multi-dimensional simulator`, Comput. Phys. Commun. **142**, 219 (2001).
+
+.. [#f2] M.J.Werner and P.D.Drummond, `Robust algorithms for solving stochastic partial differential equations`, J. Comput. Phys. **132**, 312 (1997).
\ No newline at end of file
diff --git a/admin/userdoc-source/licensing.rst b/admin/userdoc-source/licensing.rst
new file mode 100644
index 0000000..5eae5ee
--- /dev/null
+++ b/admin/userdoc-source/licensing.rst
@@ -0,0 +1,10 @@
+.. _Licensing:
+
+Licensing
+=========
+
+XMDS2 is licensed under the GPL version 2 license, which can be found in the COPYING file in the root directory of your XMDS install. You can also find it here: http://www.gnu.org/licenses/
+
+We encourage people to submit patches to us that extend XMDS2's functionality and fix bugs. If you do send us a patch, we do not require copyright assignment, but please include a statement saying you agree to license your code under the GPL v2 license.
+
+
diff --git a/admin/userdoc-source/news.rst b/admin/userdoc-source/news.rst
new file mode 100644
index 0000000..78d9e78
--- /dev/null
+++ b/admin/userdoc-source/news.rst
@@ -0,0 +1,100 @@
+.. _News:
+
+News
+-----
+
+XMDS 2.1.4 "Well if this isn't nice, I don't know what is" (September 27, 2013)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The XMDS 2.1.4 update contains many new improvements and bugfixes:
+
+* *xsil2graphics2* now supports all output formats for MATLAB, Octave and Python.  The scripts generated for MATLAB/Octave are compatible with both.
+* Fix a bug when :ref:`nonlocally<ReferencingNonlocal>` referencing a :ref:`dimension alias<DimensionAliases>` with subsampling in *sampling_group* blocks or in some situations when MPI is used.  This bug caused incorrect elements of the vector to be accessed.
+* Correct the Fourier basis for dimensions using Hermite-Gauss transforms.  Previously 'kx' was effectively behaving as '-kx'.
+* Improve the performance of 'nx' <--> 'kx' Hermite-Gauss transforms.
+* Stochastic error checking with runtime noise generation now works correctly.  Previously different random numbers were generated for the full-step paths and the half-step paths.
+* Documentation updates.
+
+XMDS 2.1.3 "Happy Mollusc" (June 7, 2013)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The XMDS 2.1.3 update is a bugfix release that includes the following improvements:
+
+* XMDS will work when MPI isn't installed (but only for single-process simulations).
+* Support for GCC 4.8
+* The number of paths used by the multi-path driver can now be specified at run-time (using *<validation kind="run-time">*)
+* Other bug fixes
+
+XMDS 2.1.2 "Happy Mollusc" (October 15, 2012)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The XMDS 2.1.2 update has many improvements:
+
+* Named filters.  You can now specify a name for a filter block and call it like a function if you need to execute it conditionally.  See the documentation for the *<filter>* block for more information.
+* New *chunked_output* feature.  XMDS can now output simulation results as it goes, reducing the memory requirement for simulations that generate significant amounts of output.  See the documentation for more details.
+* Improved OpenMP support
+* The EX operator is now faster in the common case (but you should still prefer IP when possible)
+* If seeds are not provided for a *noise_vector*, they are now generated at simulation run-time, so different executions will give different results.  The generated noises can still be found in the output .xsil files enabling results to be reproduced if desired.
+* Advanced feature: Dimensions can be accessed non-locally with the index of the lattice point.  This removes the need in hacks to manually access XMDS's underlying C arrays.  This is an advanced feature and requires a little knowledge of XMDS's internal grid representation.  See the advanced topics documentation for further details.
+* Fixed adaptive integrator order when noises were used in vector initialisation
+* Fix the Spherical Bessel basis.  There were errors in the definition of this basis which made it previously unreliable.
+* Other bug fixes
+
+XMDS 2.1 "Happy Mollusc" (June 14, 2012)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+XMDS 2.1 is a significant upgrade with many improvements and bug fixes since 2.0. We also now have installers for Linux and Mac OS X, so you no longer have to build XMDS from source! See :ref:`here<Installation>` for details about the installers.
+
+Existing users should note that this release introduces a more concise syntax for moment groups.  You can now use::
+
+    <sampling_group initial_sample="yes" basis="x y z">
+        ...
+    </sampling_group>
+
+Instead of::
+
+    <group>
+        <sampling initial_sample="yes" basis="x y z">
+            ...
+        </sampling>
+    </group>
+
+Another syntax change is that the initial basis of a vector should be specified with *initial_basis* instead of *initial_space*.
+
+In both cases, although the old syntax is not described in the documentation, it is still supported, so existing scripts will work without any changes.
+
+
+Other changes in XMDS 2.1 include:
+
+* The *lattice* attribute for dimensions can now be specified at run-time.  Previously only the minimum and maximum values of the domain could be specified at run-time.  See :ref:`here<Validation>` for details.
+* *noise_vectors* can now be used in non-uniform dimensions (e.g. dimensions using the Bessel transform for cylindrical symmetry).
+* "loose" *geometry_matching_mode* for HDF5 vector initialisation.  This enables extending the simulation grid from one simulation to the next, or coarsening or refining a grid when importing.
+* *vectors* can now be initialised by integrating over dimensions of other vectors.  *computed_vectors* always supported this, now *vectors* do too.
+* Update to latest version of waf, which is used for compiling simulations and detecting FFTW, HDF5, etc. This should lead to fewer waf-related problems.
+* Bug fixes.
+
+
+XMDS 2.0 "Shiny!" (September 13, 2010)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+XMDS 2.0 is a major upgrade which has been rewritten from the ground up to make it easier for us to apply new features. And there are many. XMDS 2.0 is faster and far more versatile than previous versions, allowing the efficient integration of almost any initial value problem on regular domains.
+
+The feature list includes:
+
+* Quantities of different dimensionalities. So you can have a 1D potential and a 3D wavefunction.
+* Integrate more than one vector (in more than one geometry), so you can now simultaneously integrate a PDE and a coupled ODE (or coupled PDEs of different dimensions).
+* Non-Fourier transformations including the Bessel basis, Spherical Bessel basis and the Hermite-Gauss (harmonic oscillator) basis.
+* The ability to have more than one kind of noise (gaussian, poissonian, etc) in a simulation.
+* Integer-valued dimensions with non-local access. You can have an array of variables and access different elements of that array.
+* Significantly better error reporting. When errors are found when compiling the script they will almost always be reported with the corresponding line of your script, instead of the generated source.
+* *IP*/*EX* operators are separate from the integration algorithm, so you can have both *IP* and *EX* operators in a single integrate block. Also, *EX* operators can act on arbitrary code, not just vector components. (e.g. *L[phi*phi]*).
+* Cross propagation in the increasing direction of a given dimension or in the decreasing dimension. And you can have more than one cross-propagator in a given integrator (going in different directions or dimensions).
+* Faster Gaussian noises.
+* The ability to calculate spatial correlation functions.
+* OpenMP support.
+* MPI support.
+* Output moment groups use less memory when there isn't a *post_processing* element.
+* Generated source is indented correctly.
+* An *xmds1*-like script file format.
+* *xmds1*-like generated source.
+* All of the integrators from *xmds1* (*SI*, *RK4*, *ARK45*, *RK9*, *ARK89*).
diff --git a/admin/userdoc-source/optimisation_hints.rst b/admin/userdoc-source/optimisation_hints.rst
new file mode 100644
index 0000000..912214d
--- /dev/null
+++ b/admin/userdoc-source/optimisation_hints.rst
@@ -0,0 +1,171 @@
+Optimisation Hints
+===================
+
+There are a variety of things you can do to make your simulations run faster.
+
+Geometry and transform-based tricks
+-----------------------------------
+
+Simpler simulation geometries
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Consider symmetry, can you use ``dct`` transforms or ``bessel`` transforms? Do you really need that many points? How big does your grid need to be? Could absorbing boundary conditions help?
+
+Tricks for Bessel and Hermite-Gauss transforms
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Dimensions using matrix transforms should be first for performance reasons.  Unless you're using MPI, in which case XMDS can work it out for the first two dimensions.  Ideally, XMDS would sort it out in all cases, but it's not that smart yet.
+
+Reduce code complexity
+----------------------
+Avoid transcendental functions like :math:`\sin(x)` or :math:`\exp(x)` in inner loops. Not all operations are made equal, use multiplication over division.
+
+Use the Interaction Picture (IP) operator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Just do it. Only use the EX operator when you have to. If you must use the EX operator, consider making it ``constant="no"``. It uses less memory.
+When you use the IP operator, make sure you know what it's doing.  Do not pre- or post-multiply that term in your equations.
+
+When using the IP operator, check if your operator is purely real or purely imaginary.  If real, (e.g. ``L = -0.5*kx * kx;``), then add the attribute ``type="real"`` to the ``<operator kind="ip">`` tag.  If purely imaginary, use ``type="imaginary"``.  This optimisation saves performing the part of the complex exponential that is unnecessary.
+
+Consider writing the evolution in spectral basis
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Evolution equations do not need to be written in the position basis.  If your equations are diagonal in the spectral basis, then it makes more sense to compute the time derivative terms in that basis.  For example, if you have the system
+
+.. math::
+    \frac{d\psi_1(x)}{dt} &= i \frac{\hbar}{2M} \frac{d^2\psi_1(x)}{dx^2} - i \Omega \psi_2(x)\\
+    \frac{d\psi_2(x)}{dt} &= i \frac{\hbar}{2M} \frac{d^2\psi_2(x)}{dx^2} - i \Omega \psi_1(x)
+
+then this is diagonal in the Fourier basis where it takes the form
+
+.. math::
+    \frac{d\psi_1(k_x)}{dt} &= -i \frac{\hbar k_x^2}{2M} \psi_1(k_x) - i \Omega \psi_2(k_x)\\
+    \frac{d\psi_2(k_x)}{dt} &= -i \frac{\hbar k_x^2}{2M} \psi_2(k_x) - i \Omega \psi_1(k_x)
+
+
+The first term in each evolution equation can be solved exactly with an IP operator, and the second term is diagonal in Fourier space.  This can be written in XMDS as:
+
+.. code-block:: xpdeint
+
+    <operators>
+      <integration_vectors basis="kx">wavefunction</integration_vectors>
+      <operator kind="ip" type="imaginary" >
+        <operator_names>Lxx</operator_names>
+        <![CDATA[
+          Lxx = -i*0.5*hbar_M*(kx*kx);
+        ]]>
+      </operator>
+      <![CDATA[
+
+        dpsi0_dt = Lxx[psi0] - i*Omega*psi1;
+        dpsi1_dt = Lxx[psi1] - i*Omega*psi0;
+          
+      ]]>
+    </operators>
+
+Although the ``dpsi0_dt`` code reads the same in position and Fourier space, it is the ``basis=kx`` attribute on ``<integration_vectors>`` that causes the evolution code to be executed in Fourier space.  
+
+A final optimisation is to cause the integration code itself to operate in Fourier space.  By default, all time stepping (i.e. :math:`f(t + \Delta t) = f(t) + f'(t) \Delta t` for forward-Euler integration) occurs in the position space.  As the derivative terms can be computed in Fourier space, it is faster to also to the time stepping in Fourier space too.  This then means that no Fourier transforms will be needed at all during this integrate block (except as needed by sampling).  To cau [...]
+
+The fully optimised code then reads:
+
+.. code-block:: xpdeint
+
+    <integrate algorithm="ARK45" interval="1" tolerance="1e-6" home_space="k">
+      <samples> 10 </samples>
+      <operators>
+        <integration_vectors basis="kx">wavefunction</integration_vectors>
+        <operator kind="ip" type="imaginary" >
+          <operator_names>Lxx</operator_names>
+          <![CDATA[
+            Lxx = -i*0.5*hbar_M*(kx*kx);
+          ]]>
+        </operator>
+        <![CDATA[
+
+          dpsi0_dt = Lxx[psi0] - i*Omega*psi1;
+          dpsi1_dt = Lxx[psi1] - i*Omega*psi0;
+          
+        ]]>
+      </operators>
+    </integrate>
+
+This code will not use any Fourier transforms during an ordinary time-stepping, and will be much faster than if the code were written without the ``home_space`` and ``basis`` attributes.
+
+Don't recalculate things you don't have to
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Use ``computed_vectors`` appropriately.
+
+
+Compiler and library tricks
+---------------------------
+
+Faster compiler
+^^^^^^^^^^^^^^^
+If you're using an Intel CPU, then you should consider using their compiler, icc. They made the silicon, and they also made a compiler that understands how their chips work significantly better than the more-portable GCC.
+
+Faster libraries
+^^^^^^^^^^^^^^^^
+Intel MKL is faster than ATLAS, which is faster than GSL CBLAS. If you have a Mac, then Apple's vecLib is plenty fast.
+
+Auto-vectorisation
+^^^^^^^^^^^^^^^^^^
+Auto-vectorisation is a compiler feature that makes compilers generate more efficient code that can execute the same operation on multiple pieces of data simultaneously. To use this feature, you need to add the following to the ``<features>`` block at the start of your simulation:
+
+.. code-block:: xpdeint
+    
+    <auto_vectorise />
+
+This will make xpdeint generate code that is more friendly to compiler's auto-vectorisation features so that more code can be vectorised. It will also add the appropriate compiler options to turn on your compiler's auto-vectorisation features. For auto-vectorisation to increase the speed of your simulations, you will need a compiler that supports it such as gcc 4.2 or later, or Intel's C compiler, ``icc``.
+
+OpenMP
+^^^^^^
+`OpenMP <http://openmp.org>`_ is a set of compiler directives to make it easier to use threads (different execution contexts) in programs. Using threads in your simulation does occur some overhead, so for the speedup to outweigh the overhead, you must have a reasonably large simulation grid. To add these compiler directives to the generated simulations, add the tag ``<openmp />`` in the ``<features>`` block. This can be used in combination with the auto-vectorisation feature above. Note  [...]
+
+If you are using the OpenMP feature and are using `FFTW <http://www.fftw.org>`_-based transforms (Discrete Fourier/Cosine/Sine Transforms), you should consider using threads with your FFT's by adding the following to the ``<features>`` block at the start of your simulation:
+
+.. code-block:: xpdeint
+    
+    <fftw threads="2" />
+
+Replace the number of threads in the above code by the number of threads that you want to use.
+
+Parallelisation with MPI
+^^^^^^^^^^^^^^^^^^^^^^^^
+Some simulations are so large or take so much time that it is not reasonable to run them on a single CPU on a single machine. Fortunately, the `Message Passing Interface <http://www.mpi-forum.org/>`_ was developed to enable different computers working on the same program to exchange data. You will need a MPI package installed to be abel to use this feature with your simulations. One popular implementation of MPI is `OpenMPI <http://www.open-mpi.org>`_.
+
+
+Atom-optics-specific hints
+--------------------------
+
+Separate out imaginary-time calculation code
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When doing simulations that require the calculation of the groundstate (typically via the imaginary time algorithm), typically the groundstate itself does not need to be changed frequently as it is usually the dynamics of the simulation that have the interesting physics. In this case, you can save having to re-calculate groundstate every time by having one script (call it ``groundstate.xmds``) that saves the calculated groundstate to a file using a breakpoint, and a second simulation tha [...]
+
+The file format used in this example is `HDF5 <http://www.hdfgroup.org/HDF5/>`_, and you will need the HDF5 libraries installed to use this example. The alternative is to use the deprecated ``binary`` format, however to load ``binary`` format data ``xmds``, the predecessor to ``xpdeint`` must be installed. Anyone who has done this before will tell you that installing it isn't a pleasant experience, and so HDF5 is the recommended file format.
+
+If your wavefunction vector is called ``'wavefunction'``, then to save the groundstate to the file ``groundstate_break.h5`` in the HDF5 format, put the following code immediately after the integrate block that calculates your groundstate:
+
+.. code-block:: xpdeint
+
+    <breakpoint filename="groundstate_break" format="hdf5">
+      <dependencies>wavefunction</dependencies>
+    </breakpoint>
+
+In addition to the ``groundstate_break.h5`` file, an XSIL wrapper ``groundstate_break.xsil`` will also be created for use with :ref:`xsil2graphics2`.
+
+To load this groundstate into your evolution script, the declaration of your ``'wavefunction'`` vector in your evolution script should look something like
+
+.. code-block:: xpdeint
+
+    <vector name="wavefunction">
+      <components>phi1 phi2</components>
+      <initialisation kind="hdf5">
+        <filename>groundstate_break.h5</filename>
+      </initialisation>
+    </vector>
+
+Note that the groundstate-finder doesn't need to have all of the components that the evolution script needs. For example, if you are considering the evolution of a two-component BEC where only one component has a population in the groundstate, then your groundstate script can contain only the ``phi1`` component, while your evolution script can contain both the ``phi1`` component and the ``phi2`` component. Note that the geometry of the script generating the groundstate and the evolution  [...]
+
+Use an energy or momentum offset
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This is just the interaction picture with a constant term in the Hamiltonian. If your state is going to rotate like :math:`e^{i(\omega + \delta\omega)t}`, then transform your equations to remove the :math:`e^{i \omega t}` term. Likewise for spatial rotations, if one mode will be moving on average with momentum :math:`\hbar k`, then transform your equations to remove that term. This way, you may be able to reduce the density of points you need in that dimension. Warning: don't forget to c [...]
diff --git a/admin/userdoc-source/reference_elements.rst b/admin/userdoc-source/reference_elements.rst
new file mode 100644
index 0000000..056d2a5
--- /dev/null
+++ b/admin/userdoc-source/reference_elements.rst
@@ -0,0 +1,1339 @@
+.. raw:: html
+
+  <style> .attributes-code {color:#0000BB; font-family:'monospace'; font-style:italic} </style>
+
+.. raw:: html
+
+  <style> .attributes-standard {color:#0000BB; font-family:'monospace'; font-style:italic; font-size:smaller} </style>
+
+.. raw:: html
+
+  <style> .smaller-font {font-size:smaller} </style>
+
+.. role:: attributes-code
+.. role:: attributes-standard
+.. role:: smaller-font
+
+.. _ReferenceElements:
+
+*********************
+XMDS2 script elements
+*********************
+
+This section outlines all the elements and options available in an XMDS2 script.  This is very much a **work in progress**, beginning with placeholders in most cases, as we have prioritised the tutorials for new users.  One of the most productive ways that non-developer veterans can contribute to the project is to help develop this documentation.
+
+
+
+
+.. _SimulationElement:
+
+Simulation element
+==================
+
+The ``<simulation>`` element is the single top level element in an XMDS2 simulation, and contains all the other elements.  All XMDS scripts must contain exactly one simulation element, and it must have the ``xmds-version="2"`` attribute defined.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <!-- Rest of simulation goes here -->
+    </simulation>
+
+
+
+
+.. _NameElement:
+
+Name element
+============
+
+The name of your simulation. This element is optional, but recommended. If it is set, it will be the name of the executable file generated from this script. It will also be the name of the output file (with an appropriate extension) if the ``filename`` attribute is not given a value in the ``<output>`` element.
+
+Example syntax::
+
+    <name> funky_solver </name>
+
+
+.. _AuthorElement:
+
+Author element
+==============
+
+The author(s) of this script. This element is optional, but can be useful if you need to find the person who has written an incomprehensible script and thinks comments are for the weak.
+
+Example syntax::
+
+    <author> Ima Mollusc </author>
+
+
+.. _DescriptionElement:
+
+Description element
+===================
+
+A description of what the simulation does. Optional, but recommended, in case you (or someone else) has to revist the script at some distant point in the future.
+
+Example syntax::
+
+    <description>
+      Calculate the 3D ground state of a Rubidium BEC in a harmonic magnetic trap assuming
+      cylindrical symmetry about the z axis and reflection symmetry about z=0.
+      This permits us to use the cylindrical Bessel functions to expand the solution transverse
+      to z and a cosine series to expand the solution along z.
+    </description>
+
+
+
+.. _FeaturesElement:
+
+Features Elements
+=================
+
+
+Features elements are where simulation-wide options are specified. The ``<features>`` element wraps one or more elements describing features. There are many possible feature elements. Currently, a full list of the features supported is:
+
+    * :ref:`arguments <ArgumentsElement>`
+    * :ref:`auto_vectorise <Autovectorise>`
+    * :ref:`benchmark <Benchmark>`
+    * :ref:`bing <Bing>`
+    * :ref:`cflags <CFlags>`
+    * :ref:`chunked_output <ChunkedOutput>`
+    * :ref:`diagnostics <Diagnostics>`
+    * :ref:`error_check <ErrorCheck>`
+    * :ref:`halt_non_finite <HaltNonFinite>`
+    * :ref:`fftw <FFTW>`
+    * :ref:`globals <Globals>`
+    * :ref:`OpenMP <OpenMP>`
+    * :ref:`precision <Precision>`
+    * :ref:`validation <Validation>`
+
+Example syntax::
+
+    <simulation xmds-version="2">
+      <features>
+        <bing />
+        <precision> double </precision>
+        ...
+      </features>
+    </simulation>
+
+
+.. _ArgumentsElement:
+
+Arguments Element
+-----------------
+
+The ``<arguments>`` element is optional, and allows defining variables that can be passed to the simulation at run time. These variables are then globally accessible throughout the simulation script. Each of the variables must be defined in an ``<argument>`` element (see below). The variables can then be passed to the simulation executable as options on the command line. For example, one could define the variables ``size``, ``number``, and ``pulse_shape`` ::
+
+    <name> arguments_test </name>
+    <features>
+      <arguments>
+        <argument name="size" type="real" default_value="20.0"/>
+        <argument name="number" type="integer" default_value="7"/>
+        <argument name="pulse_shape" type="string" default_value="gaussian"/>
+      </arguments>
+    </features>
+
+When ``XMDS2`` is run on this script the executable ``arguments_test`` is created. The values of ``size``, ``number``, and ``pulse_shape`` can then be set to whatever is desired at runtime via
+
+::
+
+  ./arguments_test --size=1.3 --number=2 --pulse_shape=lorentzian
+
+It is also possible to include an optional ``CDATA`` block inside the ``<arguments>`` block. This code will run after the arguments have been initialised with the values passed from the command line. This code block could be used, for example, to sanity check the parameters passed in, or for assigning values to global variables based on those parameters.  Any references to variables defined in an ``<argument>`` element should be made here rather than in the :ref:`Globals<globals>` elemen [...]
+
+    <features>
+      <globals>
+        <![CDATA[
+          real atom_kick;
+        ]]>
+      <globals>
+      <arguments>
+        <argument name="bragg_order" type="integer" default_value="2"/>
+        <![CDATA[
+          atom_kick = bragg_order * 2*M_PI / 780e-9;
+        ]]>
+      </arguments>
+    </features>
+
+.. _ArgumentElement:
+
+Argument element
+~~~~~~~~~~~~~~~~
+
+
+Each ``<argument>`` element describes one variable that can be passed to the simulation at runtime via the command line. There are three mandatory attributes: ``name``, ``type``, and ``default_value``. ``name`` is the name by which you can refer to that variable later in the script, as well as the name of the command line parameter. ``type`` defines the data type of the variable, and ``default_value`` is the value to which the variable is set if it is not given a value on the command line.
+
+
+.. _AutoVectorise:
+
+Auto_vectorise element
+----------------------
+
+The ``<auto_vectorise />`` feature attempts to activate automatic vectorisation for large loops, if it is available in the compiler.  This should make some simulations go faster.
+
+
+.. _Benchmark:
+
+Benchmark
+---------
+
+The ``<benchmark />`` feature includes a timing routine in the generated code, so that it is possible to see how long the simulations take to run.
+
+
+.. _Bing:
+
+Bing
+----
+
+The ``<bing />`` feature causes the simulation to make an invigorating sound when the simulation finishes executing.
+
+
+.. _CFlags:
+
+C Flags
+-------
+
+The ``<cflags>`` feature allows extra flags to be passed to the compiler.  This can be useful for optimisation, and also using specific external libraries.  The extra options to be passed are defined with a 'CDATA' block.  The compile options can be made visible by running XMDS2 either with the "-v" (verbose) option, or the "-g" (debug) option.
+
+Example syntax::
+
+    <cflags>
+        <![CDATA[
+            -O4
+        ]]>
+    </cflags>
+
+
+.. _ChunkedOutput:
+
+Chunked Output
+--------------
+
+By default, XMDS2 keeps the contents of all output moment groups in memory until the end of the simulation when they are written to the output file.  This can be a problem if your simulation creates a very large amount of output.  ``<chunked_output />`` causes the simulation to save the output data in chunks as the simulation progresses.  For some simulations this can significantly reduce the amount of memory required.  The amount of data in a chunk can be specified with the ``size`` att [...]
+
+Limitations (XMDS will give you an error if you violate any of these):
+
+* This feature cannot be used with the ASCII output file format due to limitations in the file format.
+* This feature cannot be used with the ``multi-path`` drivers because all sampling data is required to compute the mean and standard error statistics.
+* Neither is this feature compatible with the ``error_check`` feature as that relies on all sampling data being available to compute the error.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <features>
+            <chunked_output size="5MB" />
+        </features>
+    </simulation>
+
+.. _Diagnostics:
+
+Diagnostics
+-----------
+
+The ``<diagnostics />`` feature causes a simulation to output more information as it executes.  This should be useful when a simulation is dying / giving bad results to help diagnose the cause.  Currently, it largely outputs step error information.
+
+
+
+.. _ErrorCheck:
+
+Error Check
+-----------
+
+
+It's often important to know whether you've got errors.  This feature runs each integration twice: once with the specified error tolerance or defined lattice spacing in the propagation dimension, and then again with half the lattice spacing, or an equivalently lower error tolerance.  Each component of the output then shows the difference between these two integrations as an estimate of the error.  This feature is particularly useful when integrating stochastic equations, as it treats the [...]
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <features>
+            <error_check />
+        </features>
+    </simulation>
+
+
+.. _HaltNonFinite:
+
+Halt_Non_Finite
+---------------
+
+The ``<halt_non_finite />`` feature is used to stop computations from continuing to run after the vectors stop having numerical values.  This can occur when a number is too large to represent numerically, or when an illegal operation occurs.  Processing variables with non-numerical values is usually much slower than normal processing, and the results are meaningless.  Of course, there is a small cost to introducing a run-time check, so this feature is optional.
+
+
+.. _FFTW:
+
+fftw element
+------------
+
+The ``<fftw \>`` feature can be used to pass options to the `Fast Fourier Transform library <http://fftw.org>`_ used by XMDS.  This library tests algorithms on each architecture to determine the fastest method of solving each problem.  Typically this costs very little overhead, as the results of all previous tests are stored in the directory "~/.xmds/wisdom".  The level of detail for the search can be specified using the ``plan`` attribute, which can take values of ``"estimate"``, ``"mea [...]
+
+Example syntax::
+
+    <fftw plan="patient" threads="3" />
+
+
+.. _Globals:
+
+Globals
+-------
+
+The globals feature places the contents of a 'CDATA' block near the top of the generated program.  Amongst other things, this is useful for defining variables that are then accessible throughout the entire program.
+
+Example syntax::
+
+    <globals>
+      <![CDATA[
+        const real omegaz = 2*M_PI*20;
+        long Nparticles = 50000;
+
+        /* offset constants */
+        real frequency = omegaz/2/M_PI;
+      ]]>
+    </globals>
+
+
+.. _OpenMP:
+
+OpenMP
+------
+
+The ``<openmp />`` feature instructs compatible compilers to parallelise key loops using the `OpenMP API <http://www.openmp.org>`_ standard.  By default the simulation will use all available CPUs.  The number of threads used can be restricted by specifying the number of threads in the script with ``<openmp threads="2"/>``, or by setting the ``OMP_NUM_THREADS`` environment variable at run-time like so::
+
+	OMP_NUM_THREADS=2 ./simulation_name
+
+
+.. _Precision:
+
+Precision
+-----------
+
+This specifies the precision of the XMDS2 ``real`` and ``complex`` datatypes, as well as the precision used when computing transforms. Currently two values are accepted: ``single`` and ``double``. If this feature isn't specified, XMDS2 defaults to using double precision for its variables and internal calculations.
+
+Single precision has approximately 7.2 decimal digits of accuracy, with a minimum value of 1.4×10\ :superscript:`-45` and a maximum of 3.8×10\ :superscript:`34`. Double precision has approximately 16 decimal digits of accuracy, a minimum value of 4.9×10\ :superscript:`-324` and a maximum value of 1.8×10\ :superscript:`308`.
+
+Using single precision can be attractive, as it can be more than twice as fast, depending on whether a simulation is CPU bound, memory bandwidth bound, MPI bound or bottlenecked elsewhere, although in some situations you may see no speed-up at all. Caution should be exercised, however. Keep in mind how many timesteps your simulation requires, and take note of the tolerance you have set per step, to see if the result will lie within your acceptable total error - seven digit precision isn' [...]
+
+Also note that when using an adaptive step integrator, setting a tolerance close to limits of the precision can lead to very slow performance.
+
+A further limitation is that not all the combinations of random number generators and probability distributions that are supported in double precision are supported in single precision. For example, the ``solirte`` generator does not support single precision gaussian distributions. ``dsfmt``, however, is one of the fastest generators, and does support single precision.
+
+WARNING: Single precision mode has not been tested anywhere near as thoroughly as the default double precision mode, and there is a higher chance you will run into bugs.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <features>
+            <precision> single </precision>
+        </features>
+    </simulation>
+
+
+.. _Validation:
+
+Validation
+----------
+
+XMDS2 makes a large number of checks in the code generation process to verify that the values for all parameters are safe choices.  Sometimes we wish to allow these parameters to be specified by variables.  This opens up many possibilities, but requires that any safety checks for parameters be performed during the execution of the program itself.  The ``<validation>`` feature activates that option, with allowable attributes being "run-time", "compile-time" and "none".
+
+As an example, one may wish to define the number of grid points and the range of the grid at run-time rather than explicitly define them in the XMDS2 script. To accomplish this, one could do the following::
+
+    <name> validation_test </name>
+    <features>
+      <validation kind="run-time" />
+      <arguments>
+        <argument name="xmin" type="real" default_value="-1.0"/>
+        <argument name="xmax" type="real" default_value="1.0"/>
+        <argument name="numGridPoints" type="integer" default_value="128"/>
+      </arguments>
+    </features>
+
+    <geometry>
+      <propagation_dimension> t </propagation_dimension>
+      <transverse_dimensions>
+        <dimension name="x" lattice="numGridPoints"  domain="(xmin, xmax)" />
+      </transverse_dimensions>
+   </geometry>
+
+and then run the resulting executable with::
+
+  ./validation_test --xmin=-2.0 --xmax=2.0 --numGridPoints=64
+
+This approach means that when XMDS2 is parsing the script it is unable to tell, for example, if the number of sampling points requested is less than or equal to the lattice size. Consequently it will create an executable with "numGridPoints" as an internal variable, and make the check at run-time, when it knows the value of "numGridPoints" rather than at compile time, when it doesn't.
+
+.. _DriverElement:
+
+Driver Element
+==============
+
+The driver element controls the overall management of the simulation, including how many paths of a stochastic simulation are to be averaged, and whether or not it is to be run using distributed memory parallelisation.  If it is not included, then the simulation is performed once without using MPI parallelisation.  If it is included, it must have a ``name`` attribute.
+
+The ``name`` attribute can have values of "none" (which is equivalent to the default option of not specifying a driver), "distributed-mpi", "multi-path" or "mpi-multi-path".
+
+Choosing the ``name="distributed-mpi"`` option allows a single integration over multiple processors.  The resulting executable can then be run according to your particular implementation of MPI.  The FFTW library only allows MPI processing of multidimensional vectors, as otherwise shared memory parallel processing requires too much inter-process communication to be efficient.  Maximally efficient parallelisation occurs where evolution is entirely local in one transverse dimension (see :r [...]
+
+The ``name="multi-path"`` option is used for stochastic simulations, which are typically run multiple times and averaged.  It requires a ``paths`` attribute with the number of iterations of the integration to be averaged.  The output will report the averages of the desired samples, and the standard error in those averages.  
+The ``name="mpi-multi-path"`` option integrates separate paths on different processors, which is typically a highly efficient process.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <driver name="distributed-mpi" />
+            <!-- or -->
+        <driver name="multi-path" paths="10" />
+            <!-- or -->
+        <driver name="mpi-multi-path" paths="1000" />
+    </simulation>
+
+.. _GeometryElement:
+
+Geometry Element
+================
+
+.. _PropagationDimensionElement:
+
+The ``<geometry>`` element describes the dimensions used in your simulation, and is required.  The only required element inside is the ``<propagation_dimension>`` element, which defines the name of the dimension along which your simulation will integrate.  Nothing else about this dimension is specified, as requirements for the lattice along the integration dimension is specified by the ``<integrate>`` blocks themselves, as described in section :ref:`IntegrateElement`.
+
+.. _TransverseDimensionsElement:
+
+.. _DimensionElement:
+
+If there are other dimensions in your problem, they are called "transverse dimensions", and are described in the ``<transverse_dimensions>`` element.  Each dimension is then described in its own ``<dimension>`` element.  A transverse dimension must have a unique name defined by a ``name`` attribute.  If it is not specified, the type of dimension will default to "real", otherwise it can be specified with the ``type`` attribute.  Allowable types (other than "real") are "long", "int", and " [...]
+
+Each transverse dimension must specify how many points or modes it requires, and the range over which it is defined.  This is done by the ``lattice`` and ``domain`` attributes respectively.  The ``lattice`` attribute is an integer, and is optional for integer dimensions, where it can be defined implicitly by the domain.  The ``domain`` attribute is specified as a pair of numbers (e.g. ``domain="(-17,3)"``) defining the minimum and maximum of the grid.
+
+Any dimension can have a number of aliases.  These act exactly like copies of that dimension, but must be included explicitly in the definition of subsequent vectors (i.e. they are not included in the default list of dimensions for a new vector).  The list of aliases for a dimension are included in an ``aliases`` attribute.  They are useful for non-local reference of variables.  See ``groundstate_gaussian.xmds`` and ``2DMultistateSE.xmds`` as examples.
+
+Integrals over a dimension can be multiplied by a common prefactor, which is specified using the ``volume_prefactor`` attribute.  For example, this allows the automatic inclusion of a factor of two due to a reflection symmetry by adding the attribute ``volume_prefactor="2"``.  In very specific cases, you may wish to refer to volume elements explicitly.  This will lead to grid-dependent behaviour, which is sometimes required in certain stochastic field simulations, for example.  In this c [...]
+    
+If you are using the ``distributed-mpi`` driver to parallelise the simulation, place the dimension you wish to split over multiple processors first.  The most efficient parallelisation would involve distributing a dimension with only local evolution, as the different memory blocks would not need to communicate.  Nonlocal evolution that is local in Fourier space is the second preference, as the Fourier transform can also be successfully parallelised with minimum communication.  
+
+.. _Transforms:
+
+Each transverse dimension can be associated with a transform.  This allows the simulation to manipulate vectors defined on that dimension in the transform space.  The default is Fourier space (with the associated transform being the discrete Fourier transform, or "dft"), but others can be specified with the ``transform`` attribute.  The other options are "none", "dst", "dct", "bessel", "spherical-bessel" and "hermite-gauss".  Using the right transform can dramatically improve the speed o [...]
+
+An advanced feature discussed further in :ref:`DimensionAliases` are dimension aliases, which are specified by the ``aliases`` attribute.  This feature is useful for example, when calculating correlation functions.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <!-- A real-valued dimension from -1.5 to 1.5 -->
+                <dimension name="x" lattice="128" domain="(-1.5, 1.5)" />
+                
+                <!-- An integer-valued dimension with the 6 values -2, -1, 0, 1, 2, 3 -->
+                <dimension name="j"               domain="(-2,3)" type="integer" />
+                
+                <!-- A real-valued dimension using the bessel transform for a radial coordinate -->
+                <dimension name="r" lattice="64" domain="(0, 5)"  transform="bessel" volume_prefactor="2.0*M_PI" />
+            </transverse_dimensions>
+        </geometry>
+    </simulation>
+
+
+.. _dft_Transform:
+
+The "dft" transform
+-------------------
+
+The "dft" transform is performed using the the normal discrete Fourier transform, which means that it enforces periodic boundary conditions on vectors defined on that dimension.  Another implication is that it can only be used with complex-valued vectors.  The discrete Fourier transform is almost exactly the same as a standard Fourier transform.  The standard Fourier transform is
+
+.. math::
+
+    \mathcal{F}\left[f(x)\right](k) = \frac{1}{\sqrt{2\pi}}\int_{x_\text{min}}^{x_\text{max}} f(x) e^{-i k x} dx
+
+The discrete Fourier transform has no information about the domain of the lattice, so the XMDS2 transform is equivalent to
+
+.. math::
+    \tilde{\mathcal{F}}\left[f(x)\right](k) &= \frac{1}{\sqrt{2\pi}}\int_{x_\text{min}}^{x_\text{max}} f(x) e^{-i k (x+ x_\text{min})} dx \\
+    &= e^{-i x_\text{min} k} \mathcal{F}\left[f(x)\right](k)
+
+The standard usage in an XMDS simulation involves moving to Fourier space, applying a transformation, and then moving back.  For this purpose, the two transformations are entirely equivalent as the extra phase factor cancels.  However, when fields are explicitly defined in Fourier space, care must be taken to include this phase factor explicitly.  See section :ref:`Convolutions` in the Advanced Topics section.
+
+When a dimension uses the "dft" transform, then the Fourier space variable is defined as the name of the dimension prefixed with a "k".  For example, the dimensions "x", "y", "z" and "tau" will be referenced in Fourier space as "kx","ky", "kz" and "ktau".  
+
+Fourier transforms allow easy calculation of derivatives, as the n\ :sup:`th` derivative of a field is proportional to the n\ :sup:`th` moment of the field in Fourier space:
+
+.. math::
+    \mathcal{F}\left[\frac{\partial^n f(x)}{\partial x^n}\right](k_x) = \left(i \;k_x\right)^n \mathcal{F}\left[f(x)\right](k_x)
+
+This identity can be used to write the differential operator :math:`\mathcal{L} = \frac{\partial}{\partial x}` as an ``IP`` or ``EX`` operator as ``L = i*kx;`` (see :ref:`OperatorsElement` for more details).
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <!-- transform="dft" is the default, omitting it wouldn't change anything -->
+                <dimension name="x" lattice="128" domain="(-1.5, 1.5)" transform="dft" />
+            </transverse_dimensions>
+        </geometry>
+    </simulation>
+
+
+The "dct" transform
+-------------------
+
+The "dct" (discrete cosine transform) is a Fourier-based transform that implies different boundary conditions for associated vectors.  XMDS uses the type-II DCT, often called "the DCT", and its inverse, which is also called the type-III DCT.  This transform assumes that any vector using this dimension is both periodic, and also even around a specific point within each period.  The grid is therefore only defined across a half period in order to sample each unique point once, and can there [...]
+
+As the DCT transform can be defined on real data rather only complex data, it can also be superior to DFT-based spectral methods for simulations of real-valued fields where boundary conditions are artificial.
+
+XMDS labels the cosine transform space variables the same as for :ref:`Fourier transforms<dft_Transform>` and all the even derivatives can be calculated the same way.  Odd moments of the cosine-space variables are in fact *not* related to the corresponding odd derivatives by an inverse cosine transform.
+
+Discrete cosine transforms allow easy calculation of even-order derivatives, as the 2n\ :sup:`th` derivative of a field is proportional to the 2n\ :sup:`th` moment of the field in DCT-space:
+
+.. math::
+    \mathcal{F}_\text{DCT}\left[\frac{\partial^{2n} f(x)}{\partial x^{2n}}\right](k_x) = (-k_x^2)^{n}\; \mathcal{F}_\text{DCT}\left[f(x)\right](k_x)
+
+This identity can be used to write the differential operator :math:`\mathcal{L} = \frac{\partial^2}{\partial x^2}` as an ``IP`` or ``EX`` operator as ``L = -kx*kx;`` (see :ref:`OperatorsElement` for more details).
+
+For problems where you are defining the simulation domain over only half of the physical domain to take advantage of reflection symmetry, consider using ``volume_prefactor="2.0"`` so that all volume integrals are over the entire physical domain, not just the simulation domain. i.e. integrals would be over -1 to 1 instead of 0 to 1 if the domain was specified as ``domain="(0,1)"``.
+
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <dimension name="x" lattice="128" domain="(-1.5, 1.5)" transform="dct" />
+                    <!-- Or to cause volume integrals to be multiplied by 2 -->
+                <dimension name="y" lattice="128" domain="(0, 1)" transform="dct" volume_prefactor="2.0" />
+            </transverse_dimensions>
+        </geometry>
+    </simulation>
+
+
+The "dst" transform
+-------------------
+
+The "dst" (discrete sine transform) is a counterpart to the DCT transform.  XMDS uses the type-II DST and its inverse, which is also called the type-III DST.  This transform assumes that fields are periodic in this dimension, but also that they are also odd around a specific point within each period.  The grid is therefore only defined across a half period in order to sample each unique point once, and can therefore be of any shape where all the even derivatives are zero at each boundary.  
+
+The DST transform can be defined on real-valued vectors.  As odd-valued functions are zero at the boundaries, this is a natural transform to use when implementing zero Dirichlet boundary conditions.
+
+XMDS labels the sine transform space variables the same as for :ref:`Fourier transforms<dft_Transform>` and all the even derivatives can be calculated the same way.  Odd moments of the sine-space variables are in fact *not* related to the corresponding odd derivatives by an inverse sine transform.
+
+Discrete sine transforms allow easy calculation of even-order derivatives, as the 2n\ :sup:`th` derivative of a field is proportional to the 2n\ :sup:`th` moment of the field in DST-space:
+
+.. math::
+    \mathcal{F}_\text{DST}\left[\frac{\partial^{2n} f(x)}{\partial x^{2n}}\right](k_x) = (-k_x^2)^{n}\; \mathcal{F}_\text{DST}\left[f(x)\right](k_x)
+
+This identity can be used to write the differential operator :math:`\mathcal{L} = \frac{\partial^2}{\partial x^2}` as an ``IP`` or ``EX`` operator as ``L = -kx*kx;`` (see :ref:`OperatorsElement` for more details).
+
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <dimension name="x" lattice="128" domain="(0, 1.5)" transform="dst" />
+            </transverse_dimensions>
+        </geometry>
+    </simulation>
+
+
+.. _BesselTransform:
+
+The "bessel" transform
+----------------------
+
+Just as the Fourier basis is useful for finding derivatives in Euclidean geometry, the basis of Bessel functions is useful for finding certain common operators in cylindrical co-ordinates.  In particular, we use the Bessel functions of the first kind, :math:`J_m(u)`.  The relevant transform is the Hankel transform:
+
+.. math::
+    F_m(k) = \mathcal{H}_m \left[f\right](k) = \int_0^\infty r f(r) J_m(k r) dr
+    
+which has the inverse transform:
+
+.. math::
+    f(r) = \mathcal{H}^{-1}_m \left[F_m\right](r) = \int_0^\infty k F_m(k) J_m(k r) dk
+    
+This transform pair has the useful property that the Laplacian in cylindrical co-ordinates is diagonal in this basis:
+
+.. math::
+    \nabla^2 \left(f(r) e^{i m \theta}\right) &= \left(\frac{\partial^2 f}{\partial r^2} +\frac{1}{r}\frac{\partial f}{\partial r} -\frac{m^2}{r^2} f \right) e^{i m \theta} = \left\{\mathcal{H}^{-1}_m \left[(-k^2) F_m(k)\right](r) \right\} e^{i m \theta}
+    
+XMDS labels the variables in the transformed space with a prefix of 'k', just as for :ref:`Fourier transforms<dft_Transform>`.  The order :math:`m` of the transform is defined by the ``order`` attribute in the ``<dimension>`` element, which must be assigned as a non-negative integer.  If the order is not specified, it defaults to zero which corresponds to the solution being independent of the angular coordinate :math:`\theta`.  
+
+It can often be useful to have a different sampling in normal space and Hankel space.  Reducing the number of modes in either space dramatically speeds simulations.  To set the number of lattice points in Hankel space to be different to the number of lattice points for the field in its original space, use the attribute ``spectral_lattice``.  The Bessel space lattice is chosen such that the boundary condition at the edge of the domain is zero.  This ensures that all of the Bessel modes ar [...]
+
+Hankel transforms allow easy calculation of the Laplacian of fields with cylindrical symmetry.  Applying the operator ``L = -kr*kr`` in Hankel space is therefore equivalent to applying the operator
+
+.. math::
+    \mathcal{L} = \left(\frac{\partial^2}{\partial r^2} +\frac{1}{r}\frac{\partial}{\partial r} -\frac{m^2}{r^2} \right)
+    
+in coordinate space.
+
+In non-Euclidean co-ordinates, integrals have non-unit volume elements.  For example, in cylindrical co-ordinates with a radial co-ordinate 'r', integrals over this dimension have a volume element :math:`r dr`.  When performing integrals along a dimension specified by the "bessel" transform, the factor of the radius is included implicitly.  If you are using a geometry with some symmetry, it is common to have prefactors in your integration.  For example, for a two-dimensional volume in cy [...]
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <dimension name="r" lattice="128" domain="(0, 3)" transform="bessel" volume_prefactor="2*M_PI" />
+            </transverse_dimensions>
+        </geometry>
+    </simulation>
+
+
+
+The "spherical-bessel" transform
+--------------------------------
+
+When working in spherical coordinates, it is often useful to use the spherical Bessel functions :math:`j_l(x)=\sqrt{\frac{\pi}{2x}}J_{l+\frac{1}{2}}(x)` as a basis.  These are eigenfunctions of the radial component of Laplace's equation in spherical coordinates:
+
+.. math::
+    \nabla^2 \left[j_l(k r)\; Y^m_l(\theta, \phi)\right] &= \left[\frac{\partial^2 }{\partial r^2} +\frac{2}{r}\frac{\partial }{\partial r} -\frac{l(l+1)}{r^2}\right] j_l(k r) \; Y^m_l(\theta, \phi) = -k^2 j_l(k r)\; Y^m_l(\theta, \phi)
+
+Just as the Bessel basis above, the transformed dimensions are prefixed with a 'k', and it is possible (and usually wise) to use the ``spectral_lattice`` attribute to specify a different lattice size in the transformed space.  Also, the spacing of these lattices are again chosen in a non-uniform manner to Gaussian quadrature methods for spectrally accurate transforms.  Finally, the ``order`` attribute can be used to specify the order :math:`l` of the spherical Bessel functions used.  
+
+If we denote the transformation to and from this basis by :math:`\mathcal{SH}`, then we can write the useful property:
+
+.. math::
+    \frac{\partial^2 f}{\partial r^2} +\frac{2}{r}\frac{\partial f}{\partial r} -\frac{l (l+1)}{r^2} = \mathcal{SH}^{-1}_l \left[(-k^2) F_l(k)\right](r)
+
+Spherical Bessel transforms allow easy calculation of the Laplacian of fields with spherical symmetry. Applying the operator ``L = -kr*kr`` in Spherical Bessel space is therefore equivalent to applying the operator
+
+.. math::
+    \mathcal{L} = \left( \frac{\partial^2}{\partial r^2} +\frac{2}{r}\frac{\partial}{\partial r} -\frac{l (l+1)}{r^2} \right)
+    
+in coordinate space.  
+
+In non-Euclidean co-ordinates, integrals have non-unit volume elements.  For example, in spherical co-ordinates with a radial co-ordinate 'r', integrals over this dimension have a volume element :math:`r^2 dr`.  When performing integrals along a dimension specified by the "spherical-bessel" transform, the factor of the square of the radius is included implicitly.  If you are using a geometry with some symmetry, it is common to have prefactors in your integration.  For example, for a thre [...]
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <dimension name="r" lattice="128" domain="(0, 3)" transform="spherical-bessel" volume_prefactor="4*M_PI" />
+            </transverse_dimensions>
+        </geometry>
+    </simulation>
+
+
+
+The "hermite-gauss" transform
+-----------------------------
+
+The "hermite-gauss" transform allows transformations to and from the basis of Hermite functions :math:`\psi_n(x)`:
+
+.. math::
+    \psi_n(x) = \left(2^n n! \sigma \sqrt{\pi}\right)^{-1/2} e^{-x^2/2\sigma^2} H_n(\sigma x)
+    
+where the functions :math:`H_n(x)` are the Hermite polynomials:
+
+.. math::
+    H_n(x) &= (-1)^n e^{x^2} \frac{d^n}{dx^n} \left(e^{-x^2}\right)
+    
+which are eigenfunctions of the Schroedinger equation for a harmonic oscillator:
+
+.. math::
+    - \frac{\hbar^2}{2 m} \frac{\partial^2 \psi_n}{\partial x^2} + \frac{1}{2} m \omega^2 x^2 \psi_n(x) = \hbar \omega\left(n+\frac{1}{2}\right) \psi_n(x),
+
+with :math:`\sigma = \sqrt{\frac{\hbar}{m \omega}}`.
+    
+This transform is different to the others in that it requires a ``length_scale`` attribute rather than a ``domain`` attribute, as the range of the lattice will depend on the number of basis functions used. The ``length_scale`` attribute defines the scale of the domain as the standard deviation :math:`\sigma` of the lowest order Hermite function :math:`\psi_0(x)`:
+
+.. math::
+    \psi_0(x) = (\sigma^2 \pi)^{-1/4} e^{-x^2/2 \sigma^2}
+
+When a dimension uses the "hermite-gauss" transform, then the variable indexing the basis functions is defined as the name of the dimension prefixed with an "n".  For example, when referencing the basis function indices for the dimensions "x", "y", "z" and "tau", use the variable "nx", "ny", "nz" and "ntau".  
+
+Applying the operator ``L = nx + 0.5`` in Hermite space is therefore equivalent to applying the operator
+
+.. math::
+   \mathcal{L} = \left(- \frac{\sigma^2}{2}\frac{\partial^2}{\partial x^2} + \frac{1}{2 \sigma^2} x^2 \right)
+    
+in coordinate space.  
+
+The Hermite-Gauss transform permits one to work in energy-space for the harmonic oscillator.  The normal Fourier transform of "hermite-gauss" dimensions can also be referenced using the dimension name prefixed with a "k".  See the examples ``hermitegauss_transform.xmds`` and ``hermitegauss_groundstate.xmds`` for examples.
+
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <dimension name="r" lattice="128" length_scale="1.0" transform="hermite-gauss" />
+            </transverse_dimensions>
+        </geometry>
+    </simulation>
+
+
+
+
+.. _VectorElement:
+
+Vector Element
+==============
+
+Vectors are arrays of data, defined over any subset of the transverse dimensions defined in your :ref:`GeometryElement`.  These dimensions are listed in the attribute ``dimensions``, which can be an empty string if you wish the vector to not be defined on any dimensions.  If you do not include a ``dimensions`` attribute then the vector defaults to being a function of all transverse dimensions, not including any aliases.  Vectors are used to store static or dynamic variables, but you do n [...]
+
+Each ``<vector>`` element has a unique name, defined by a ``name`` attribute.  It is either complex-valued (the default) or real-valued, which can be specified using the ``type="real"`` attribute.
+
+.. _ComponentsElement:
+
+A vector contains a list of variables, each defined by name in the ``<components>`` element.  The name of each component is the name used to reference it later in the simulation.
+
+Vectors are initialised at the beginning of a simulation, either from code or from an input file.  The basis choice for this initialisation defaults to the normal space as defined in the ``<geometry>`` element, but any transverse dimension can be initialised in their transform basis by specifying them in an ``initial_basis`` attribute.  The ``initial_basis`` attribute lists dimensions either by their name as defined by the ``<geometry>`` element, or by their transformed name.  For exampl [...]
+
+.. _InitialisationElement:
+
+When initialising the vector within the XMDS script, the appropriate code is placed in a 'CDATA' block inside an ``<initialisation>`` element.  This code is in standard C-syntax, and should reference the components of the vector by name.  XMDS defines a few useful :ref:`shorthand macros<XMDSCSyntax>` for this C-code.  If you wish to initialise all the components of the vector as zeros, then it suffices simply to add the attribute ``kind="zero"`` or to omit the ``<initialisation>`` elemen [...]
+    
+.. _ReferencingNonlocal:
+
+While the default XMDS behaviour is to reference all variables locally, any vector can be referenced non-locally.  The notation for referencing the value of a vector 'phi' with a dimension 'j' at a value of 'j=jk' is ``phi(j => jk)``.  Multiple non-local dimensions are addressed by adding the references in a list, e.g. ``phi(j => jk, x => y)``.  See ``2DMultistateSE.xmds`` for an example.
+
+Dimensions can only be accessed non-locally if one of the following conditions is true:
+
+* The dimension is an ``integer`` dimension,
+* The dimension is accessed with an :ref:`alias <DimensionAliases>` of that dimension. For example, ``phi(x => y)`` if the dimension ``x`` has ``y`` as an alias, or vice-versa.
+* The dimension is a Fourier transform dimension (``dft``), used in the spectral basis (i.e. ``kx`` for an ``x`` dimension) and it is accessed with the negative of that dimension.  For example ``phi(kx => -kx)``.
+* The dimension is uniformly spaced (i.e. corresponds to the spatial basis of a dimension with a transform of ``dft``, ``dct``, ``dst`` or ``none``), the dimension is symmetric about zero and it is accessed with the negative of the dimension name.  For example ``phi(x => -x)`` for a dimension with domain of ``(-1.2, 1.2)``.
+* The dimension is uniformly spaced (i.e. corresponds to the spatial basis of a dimension with a transform of ``dft``, ``dct``, ``dst`` or ``none``), and it is accessed with the lower limit of that dimension.  For example, ``phi(x => -1.2)`` for a dimension with a domain of ``(-1.2, 1.2)``.  Note that the dimension must be accessed with the exact characters used in the definition of the domain.  For the previous example ``phi(x => -1.20)`` does not satisfy this condition.
+* **Advanced behaviour**: The value of a variable at an arbitrary point can be accessed via the integer index for that dimension. For example ``phi(x_index => 3)`` accesses the value of ``phi`` at the grid point with index 3.  As ``x_index`` is zero-based, this will be the *fourth* grid point.  It is highly recommended that the :ref:`diagnostics <Diagnostics>` feature be used when writing simulations using this feature.  Once the simulation has been tested, ``<diagnostics>`` can be turne [...]
+
+
+Note that a dimension cannot be accessed non-locally in ``distributed-mpi`` simulations if the simulation is distributed across that dimension.
+
+.. _FilenameElement:
+
+If you wish to initialise from a file, then you can choose to initialise from an hdf5 file using ``kind="hdf5"`` in the ``<initialisation>`` element, and then supply the name of the input file with the ``filename`` element.  This is a standard data format which can be generated from XMDS, or from another program.  An example for generating a file in another program for input into XMDS is detailed in the Advanced topic: :ref:`Importing`.
+
+When initialising from a file, the default is to require the lattice of the transverse dimensions to exactly match the lattice defined by XMDS.  There is an option to import data defined on a subset or superset of the lattice points.  Obviously, the dimensionality of the imported field still has to be correct.  This option is activated by defining the attribute ``geometry_matching_mode="loose"``.  The default option is defined as ``geometry_matching_mode="strict"``.  A requirement of the [...]
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <dimension name="x" lattice="128" domain="(-1, 1)" />
+            </transverse_dimensions>
+        </geometry>
+    
+        <!-- A one-dimensional vector with dimension 'x' -->
+        <vector name="wavefunction" initial_basis="x" type="complex">
+            <components> phi </components>
+            <initialisation>
+                <![CDATA[
+                    // 'cis(x)' is cos(x) + i * sin(x)
+                    phi = exp(-0.5 * x * x) * cis(40 * x);
+                ]]>
+            </initialisation>
+        </vector>
+        
+        <!-- A zero-dimensional real vector with components u and v -->
+        <vector name="zero_dim" dimensions="" type="real">
+            <components>
+                u v
+            </components>
+            <initialisation kind="hdf5">
+                <filename>data.h5</filename>
+            </initialisation>
+        </vector>
+    </simulation>
+
+
+
+.. _Dependencies:
+
+The dependencies element
+------------------------
+
+Often a vector, computed vector, filter, integration operator or output group will reference the values in one or more other vectors, computed vectors or noise vectors.  These dependencies are defined via a ``<dependencies>`` element, which lists the names of the vectors.  The components of those vectors will then be available for use in the 'CDATA' block, and can be referenced by their name.  
+
+For a vector, the basis of the dependent vectors, and therefore the basis of the dimensions available in the 'CDATA' block, are defined by the ``initial_basis`` of the vector.  For a ``<computed_vector>``, ``<filter>`` ``<integration_vector>``, or moment group vector, the basis of the dependencies can be specified by a ``basis`` attribute in the ``<dependencies>`` element.  For example, ``basis="x ny kz"``.
+
+Any transverse dimensions that appear in the ``<dependencies>`` element that do not appear in the ``dimensions`` attribute of the vector are integrated out.  For integer dimensions, this is simply an implicit sum over the dimension.  For real-valued dimensions, this is an implicit integral over the range of that dimension.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <dimension name="x" lattice="128" domain="(-1, 1)" />
+                <dimension name="y" lattice="10" domain="(-3, 2)" transform="dct" />
+            </transverse_dimensions>
+        </geometry>
+    
+        <!-- A one-dimensional vector with dimension 'x' -->
+        <vector name="wavefunction" dimensions="x" initial_basis="x" type="complex">
+            <components> phi </components>
+            <initialisation>
+                <!-- 
+                    The initialisation of the vector 'wavefunction' depends on information
+                    in the 'two_dim' vector.  The vector two_dim is DCT-transformed into the
+                    (x, ky) basis, and the ky dimension is implicitly integrated over in the
+                    following initialisation code
+                  -->
+                <dependencies basis="x ky">two_dim</dependencies>
+                <![CDATA[
+                    // 'cis(x)' is cos(x) + i * sin(x)
+                    phi = exp(-0.5 * x * x + v) * cis(u * x);
+                ]]>
+            </initialisation>
+        </vector>
+        
+        <!-- A two-dimensional real vector with components u and v -->
+        <vector name="two_dim" type="real">
+            <components>
+                u v
+            </components>
+            <initialisation kind="hdf5">
+                <filename>data.h5</filename>
+            </initialisation>
+        </vector>
+    </simulation>
+
+
+
+.. _ComputedVectorElement:
+
+Computed Vector Element
+=======================
+
+.. _EvaluationElement:
+
+Computed vectors are arrays of data much like normal ``<vector>`` elements, but they are always calculated as they are referenced, so they cannot be initialised from file.  It is defined with a ``<computed_vector>`` element, which has a ``name`` attribute, optional ``dimensions`` and ``type`` attributes, and a ``<components>`` element, just like a ``<vector>`` element.  Instead of an <:ref:`initialisation<InitialisationElement>`> element, it has an ``<evaluation>`` element that serves th [...]
+
+As it is not being stored, a ``<computed_vector>`` does not have or require an ``initial_basis`` attribute, as it will be transformed into an appropriate basis for the element that references it.  The basis for its evaluation will be determined entirely by the ``basis`` attribute of the ``<dependencies>`` element.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <dimension name="x" lattice="128" domain="(-1, 1)" />
+            </transverse_dimensions>
+        </geometry>
+    
+        <!-- A one-dimensional vector with dimension 'x' -->
+        <vector name="wavefunction" type="complex">
+            <components> phi </components>
+            <initialisation>
+                <![CDATA[
+                    // 'cis(x)' is cos(x) + i * sin(x)
+                    phi = exp(-0.5 * x * x) * cis(40 * x);
+                ]]>
+            </initialisation>
+        </vector>
+        
+        <!-- A zero-dimensional real computed vector with components Ncalc -->
+        <computed_vector name="zero_dim" dimensions="" type="real">
+            <components>
+                Ncalc
+            </components>
+            <evaluation>
+                <dependencies>wavefunction</dependencies>
+                <![CDATA[
+                    // Implicitly integrating over the dimension 'x'
+                    Ncalc = mod2(phi);
+                ]]>
+            </evaluation>
+        </computed_vector>
+    </simulation>
+
+
+
+.. _NoiseVectorElement:
+
+Noise Vector Element
+====================
+
+Noise vectors are used like computed vectors, but when they are evaluated they generate arrays of random numbers of various kinds.  They do not depend on other vectors, and are not initialised by code.  They are defined by a ``<noise_vector>`` element, which has a ``name`` attribute, and optional ``dimensions``, ``initial_basis`` and ``type`` attributes, which work identically as for normal vectors.  
+
+The choice of pseudo-random number generator (RNG) can be specified with the ``method`` attribute, which has options "posix" (the default), "mkl", "solirte" and "dsfmt".  It is only possible to use any particular method if that library is available.  Although "posix" is the default, it is also the slowest, and produces the lowest quality random numbers (although this is typically not a problem).  "mkl" refers to the Intel Math Kernel Library, and is only available if installed.  "solirte [...]
+
+The random number generators can be provided with a seed using the ``seed`` attribute, which should typically consist of a list of three integers.  All RNGs require positive integers as seeds.  It is possible to use the :ref:`<validation kind="run-time"/><Validation>` feature to use passed variables as seeds.  It is advantageous to use fixed seeds rather than timer-based seeds, as the :ref:`<error_check><ErrorCheck>` element can test for strong convergence if the same seeds are used for  [...]
+
+The different types of noise vectors are defined by a mandatory ``kind`` attribute, which must take the value of 'gauss', 'gaussian', 'wiener', 'poissonian','jump' or 'uniform'.  
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <dimension name="x" lattice="128" domain="(-1, 1)" />
+            </transverse_dimensions>
+        </geometry>
+    
+        <!-- 
+            A one-dimensional complex wiener noise vector.
+            This noise is appropriate for using in the complex
+            random-walk equation of motion:
+                dz_dt = eta;
+        -->
+        <noise_vector name="noise" kind="wiener">
+            <components>
+                eta
+            </components>
+        </vector>
+    </simulation>
+
+
+.. _uniformNoise:
+
+Uniform noise
+-------------
+
+Uniform noises defined over any transverse dimensions are simply uniformly distributed random numbers between zero and one.  This noise is an example of a "static" noise, i.e. one suitable for initial conditions of a field.  If it were included in the equations of motion for a field, then the effect of the noise would depend on the lattice spacing of the propagation dimension.  XMDS therefore does not allow this noise type to be used in integration elements.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <noise_vector name="drivingNoise" dimensions="x" kind="uniform" type="complex" method="dsfmt" seed="314 159 276">
+          <components>Eta</components>
+        </noise_vector>
+    </simulation>
+
+
+.. _gaussianNoise:
+
+Gaussian noise
+--------------
+
+Noise generated with the "gaussian" method is gaussian distributed with zero mean.  For a real-valued noise vector, the variance at each point is the inverse of the volume element of the transverse dimensions in the vector.  This volume element for a single transverse dimension is that used to perform integrals over that dimension.  For example, it would include a factor of :math:`r^2` for a dimension "r" defined with a ``spherical-bessel`` transform.  It can be non-uniform for dimension [...]
+
+This lattice-dependent variance is typical in most applications of partial differential equations with stochastic initial conditions, as the physical quantity is the variance of the field over some finite volume, which does not change if the variance at each lattice site varies as described above.
+
+For complex-valued noise vector, the real and imaginary parts of the noise are independent, and each have half the variance of a real-valued noise.  This means that the modulus squared of a complex-valued noise vector has the same variance as a real-valued noise vector at each point.
+
+Gaussian noise vectors are an example of a "static" noise, i.e. one suitable for initial conditions of a field.  If they were included in the equations of motion for a field, then the effect of the noise would depend on the lattice spacing of the propagation dimension.  XMDS therefore does not allow this noise type to be used in integration elements.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <noise_vector name="initialNoise" dimensions="x" kind="gauss" type="real" method="posix" seed="314 159 276">
+          <components>fuzz</components>
+        </noise_vector>
+    </simulation>
+
+
+.. _wienerNoise:
+
+Wiener noise
+------------
+
+Noise generated with the "wiener" method is gaussian distributed with zero mean and the same variance as the static "gaussian" noise defined above, multiplied by a factor of the lattice step in the propagation dimension.  This means that these noise vectors can be used to define Wiener noises for standard stochastic ordinary or partial differential equations.  Most integrators in XMDS effectively interpret these noises as Stratonovich increments.
+
+As a dynamic noise, a Wiener process is not well-defined except in an ``integrate`` element.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <noise_vector name="diffusion" dimensions="x" kind="wiener" type="real" method="solirte" seed="314 159 276">
+          <components>dW</components>
+        </noise_vector>
+    </simulation>
+
+
+.. _poissionianNoise:
+
+Poissonian noise
+----------------
+
+A noise vector using the "poissonian" method generates a random variable from a Poissonian distribution.  While the the Poisson distribution is integer-valued, the variable will be cast as a real number.  The rate of the Poissonian distribution is defined by the ``mean`` or ``mean-density`` attributes.  These are are synonyms, and must be defined as positive real numbers.  For Poissonian noises defined over real-valued transverse dimensions, the rate is given by the product of this ``mea [...]
+
+Poissonian noise vectors are an example of a "static" noise, i.e. one suitable for initial conditions of a field.  If they were included in the equations of motion for a field, then the effect of the noise would depend on the lattice spacing of the propagation dimension.  XMDS therefore does not allow this noise type to be used in integration elements.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <noise_vector name="initialDistribution" dimensions="x" kind="poissonian" type="real" mean-density="2.7" method="solirte" seed="314 159 276">
+          <components>Pdist</components>
+        </noise_vector>
+    </simulation>
+
+
+.. _jumpNoise:
+
+Jump noise
+----------
+
+A noise vector using the "jump" method is the dynamic version of the poissonian noise method, and must have the ``mean-rate`` attribute specified as a positive real number.  The variable at each point is chosen from a Poissonian distribution with a mean equal to the product of three variables: the ``mean-rate`` attribute; the volume of the element as defined by its transverse dimensions (including their ``volume_prefactor`` attributes); and the step size in the propagation dimension.  No [...]
+
+It is common to wish to vary the mean rate of a jump process, which means that the ``mean-rate`` attribute must be a variable or a piece of code.  These cannot be verified to be a positive real number at compile time, so they must be used with the :ref:`<validation><Validation>` feature with either the ``kind="none"`` or ``kind="run-time"`` attributes.
+
+As a dynamic noise, a jump process is not well-defined except in an ``integrate`` element.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <noise_vector name="initialDistribution" dimensions="" kind="jump" type="real" mean-rate="2.7" method="solirte" seed="314 159 276">
+          <components>dN</components>
+        </noise_vector>
+    </simulation>
+
+
+
+.. _SequenceElement:
+
+Sequence Element
+================
+
+All processing of vectors happens in sequence elements.  Each simulation must have exactly one main sequence element, but it can then contain any number of nested sequence elements.  A sequence element can contain any number of ``<sequence>``, :ref:`<filter><FilterElement>`, :ref:`<integrate><IntegrateElement>` and/or :ref:`<breakpoint><BreakpointElement>` elements, which are executed in the order they are written.  A sequence can be repeated a number of times by using the ``cycles`` att [...]
+    
+Example syntax::
+
+    <simulation xmds-version="2">
+        <sequence cycles="2">
+            <sequence>  ... </sequence>
+            <filter> ... </filter>
+            <integrate> ...</integrate>
+        </sequence>
+    </simulation>    
+
+.. _FilterElement:
+
+Filter element
+==============
+
+A ``<filter>`` element can be placed inside a ``<sequence>`` element or an :ref:`<integrate><IntegrateElement>` element.  It contains a 'CDATA' block and an optional :ref:`<dependencies><Dependencies>` element, which may give access to variables in other ``<vector>``, ``<computed_vector>`` or ``<noise_vector>`` elements.  The code inside the 'CDATA' block is executed over the combined tensor product space of the dependencies, or simply once if there is no dependencies element.  This elem [...]
+    
+Sometimes it is desirable to apply a filter conditionally.  The most efficient way of doing this is to call the function from the piece of code that contains the conditional statement (likely another ``<filter>`` element) rather than embed the conditional function in the filter itself, as the latter method can involve the conditional statement being evaluated multiple times over the transverse dimensions.  For this reason, it is possible to give a filter a ``name`` attribute, and the fil [...]
+    
+One of the common uses of a filter element is to apply discontinuous changes to the vectors and variables of the simulation.
+
+Example syntax::
+
+    <sequence>
+        <filter>
+          <![CDATA[
+            printf("Hello world from the first filter segment!  This filter rather wastefully calls the second one.\n");
+            fname();
+          ]]>
+        </filter>
+
+        <filter name="fname">
+           <dependencies>normalisation wavefunction</dependencies>
+           <![CDATA[
+             phi *= sqrt(Nparticles/Ncalc);
+           ]]>
+        </filter>
+    </sequence>
+
+
+.. _IntegrateElement:
+
+Integrate element
+=================
+
+The ``<integrate>`` element is at the heart of most XMDS simulations.  It is used to integrate a set of (potentially stochastic) first-order differential equations for one or more of the vectors defined using the ``<vector>`` element along the propagation dimension.  At the beginning of the simulation, the value of the propagation dimension is set to zero, and the vectors are initialised as defined in the :ref:`<vector><VectorElement>` element.  As successive sequence elements change the [...]
+    
+The length of the integration is defined by the ``interval`` attribute, which must be a positive real number.  An ``<integrate>`` element must have an ``algorithm`` attribute defined, which defines the integration method.  Current methods include :ref:`SI <SI>`, :ref:`SIC <SI>`, :ref:`RK4 <RK4>`, :ref:`RK9 <RK4>`, :ref:`ARK45 <ARK45>`, and :ref:`ARK89 <ARK45>`.  Fixed step algorithms require a ``steps`` attribute, which must be a positive integer that defines the number of (evenly spaced [...]
+
+.. _SamplesElement:
+
+The optional ``<samples>`` element is used to track the evolution of one or more vectors or variables during an integration.  This element must contain a non-negative integer for each :ref:`<sampling_group><SamplingGroupElement>` element defined in the simulation's :ref:`<output><OutputElement>` element.  The list of integers then defines the number of times that the moments defined in those groups will be sampled.  For a fixed step algorithm, each non-zero number of samples must be a fa [...]
+    
+The vectors to be integrated and the form of the differential equations are defined in the :ref:`<operators><OperatorsElement>` element (or elements).  Filters to be applied each step can be defined with optional :ref:`<filters><FiltersElement>` elements.  
+    
+Computed vectors can be defined with the ``<computed_vector>`` element.  These act exactly like a globally defined :ref:`ComputedVectorElement`, but are only available within the single ``<integrate>`` element.
+
+Example syntax::
+
+    <integrate algorithm="ARK89" interval="1e-4" steps="10000" tolerance="1e-8">
+      <samples>20</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            phi *= sqrt(Nparticles/Ncalc);   // Correct normalisation of the wavefunction
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*hbar/M*ky*ky;
+          ]]>
+        </operator>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] - (V1 + Uint/hbar*mod2(phi))*phi;
+        ]]>
+        <integration_vectors>wavefunction</integration_vectors>
+      </operators>
+    </integrate>
+
+.. _OperatorsElement:
+
+Operators and operator elements
+-------------------------------
+
+An :ref:`<integrate><IntegrateElement>` element must contain one or more ``<operators>`` elements, which define both which vectors are to be integrated, and their derivative in the propagation dimension.  When all vectors to be integrated have the same dimensionality, they can all be defined within a single ``<operators>`` element, and when vectors with different dimension are to be integrated, each set of vectors with the same dimensionality should be placed in separate ``<operators>``  [...]
+    
+.. _IntegrationVectorsElement:
+
+Within each ``<operators>`` element, the vectors that are to be integrated are listed by name in the ``<integration_vectors>`` element, and the differential equations are written in a 'CDATA' block.   The derivative of each component of the integration vectors must be defined along the propagation dimension.  For example, if the integration vectors have components 'phi' and 'beta', and the propagation dimension is labelled 'tau', then the 'CDATA' block must define the variables 'dphi_dta [...]
+    
+When noise vectors are referenced, equations with Wiener noises should be written as though the equations are in differential form, as described in the worked examples :ref:`Kubo` and :ref:`Fibre`.  Jump-based Poisson noises will also be written in an equivalent form, as modelled by the example ``photodetector.xmds``.
+    
+By default, the name of each component references the local value of the vector, but :ref:`nonlocal variables<ReferencingNonlocal>` can be accessed using the standard syntax.  However, typically the most common (and most efficient) method of referencing nonlocal variables is to reference variables that are local in the :ref:`transformed space<Transforms>` for a given transverse dimension.  This is done using ``<operator>`` elements.
+    
+.. _OperatorElement:
+
+There are three kinds of ``<operator>`` elements.  The first is denoted with a ``kind="functions"`` attribute, and contains a 'CDATA' block that will be executed in the order that it is defined.  This is useful when you wish to calculate functions that do not depend on the transverse dimensions.  Defining these along with the main equations of motion causes them to be recalculated separately for each point.  The second kind of ``<operator>`` element is used to define an operation in a tr [...]
+
+Example syntax::
+
+    <operator kind="functions">
+      <![CDATA[
+      f = cos(t);
+      ]]>
+    </operator>
+    
+.. _OperatorNamesElement:
+
+The second kind of operator element defines a list of operators in an ``<operator_names>`` element.  The basis of these operators defaults to the transform space unless a different basis is specified using the ``basis`` attribute.  These operators must then be defined in a 'CDATA' block, using any :ref:`dependencies<Dependencies>` as normal.  If the operators constant across the integration, then the attribute ``constant="yes"`` should be set, otherwise the ``constant="no"`` attribute en [...]
+
+Operators of this second kind have the ``kind="IP"`` or ``kind="EX"`` attribute, standing for 'interaction picture' and 'explicit' operators respectively.  Explicit operators can be used in all situations, and simply construct and calculate a new vector of the form in the square brackets.  IP operators use less memory and can improve speed by allowing larger timesteps, but have two important restrictions.  **Use of IP operators without understanding these restrictions can lead to incorre [...]
+
+Example syntax::
+
+    <operator kind="ex" constant="yes">
+      <operator_names>T</operator_names>
+      <![CDATA[
+        T = -0.5*hbar/M*ky*ky;
+      ]]>
+    </operator>
+
+The third kind of operator element is used to define an integration along a transverse dimension.  This kind of evolution is called "cross-propagation", and is described briefly in the examples 'tla.xmds', 'tla_sic.xmds' and 'sine_cross.xmds'.  This class of equations have a subset of vectors that have an initial condition on one side of a transverse dimension, and a differential equation defined in that dimension, and as such, this kind of operator element has much of the structure of a [...]
+    
+An operator element with the ``kind="cross_propagation"`` attribute must specify the transverse dimension along which the integration would proceed with the ``propagation_dimension`` attribute.  It must also specify its own :ref:`<integration_vectors><IntegrationVectorsElement>` element, its own ``<operators>`` elements (of the second kind), and may define an optional :ref:`<dependencies><Dependencies>` element.  The algorithm to be used for the transverse integration is specified by the [...]
+    
+.. _BoundaryConditionElement:
+
+The boundary conditions are specified by a ``<boundary_conditions>`` element, which requires the ``kind="left"`` or ``kind="right"`` attribute to specify on which side of the grid that the boundary conditions are specified.  The boundary conditions for the ``<integration_vectors>`` are then specified in a 'CDATA' block, which may refer to vectors in an optional :ref:`<dependencies><Dependencies>` element that can be contained in the ``<boundary_conditions>`` element.
+
+Example syntax::
+
+    <operator kind="cross_propagation" algorithm="RK4" propagation_dimension="t">
+      <integration_vectors>cross</integration_vectors>
+      <dependencies>constants</dependencies>
+      <boundary_condition kind="left">
+        <![CDATA[
+          v = 1.0;
+          w = 1.0;
+        ]]>
+      </boundary_condition>
+  
+      <operator kind="ip" constant="yes">
+        <operator_names>L</operator_names>
+        <![CDATA[
+          L = i;
+        ]]>
+      </operator>
+  
+      <![CDATA[
+        dv_dt = i*v;
+        dw_dt = L[w]; 
+      ]]>
+    </operator>
+
+
+.. _Algorithms:
+
+Algorithms
+----------
+
+The stability, efficiency and even convergence of a numerical integration can depend on the method.  Due to the varying properties of different sets of equations, it is impossible to define the best method for all equations, so XMDS provides an option to use different algorithms.  These include fixed step algorithms, which divide the integration region into equal steps, and adaptive stepsize algorithms, which attempt to estimate the error in the simulation in order to choose an appropria [...]
+
+For the purposes of the descriptions below, we will assume that we are considering the following set of coupled differential equations for the vector of variables :math:`\mathbf{x}(t)`:
+
+.. math::
+
+    \frac{d x_j}{dt} = f_j(\mathbf{x}(t),t)
+
+.. _SI:
+
+SI and SIC algorithms
+~~~~~~~~~~~~~~~~~~~~~
+
+The SI algorithm is a semi-implicit fixed-step algorithm that finds the increment of the vector by solving
+
+.. math::
+
+    x_j(t+\Delta t) = x_j(t) + f_j\left(\mathbf{x}(t+\frac{\Delta t}{2}),t+\frac{\Delta t}{2}\right) \;\Delta t
+
+using a simple iteration to find the values of the vector at the midpoint of the step self-consistently.  The number of iterations can be set using the ``iterations`` attribute, and it defaults to ``iterations="3"``.  The choice of ``iterations="1"`` is therefore fully equivalent to the Euler algorithm, where
+
+.. math::
+
+    x_j(t+\Delta t) = x_j(t) + f_j\left(\mathbf{x}(t),t\right) \;\Delta t.
+
+The Euler algorithm is the only safe algorithm for direct integration of :ref:`jump-based Poisson processes<jumpNoise>`.  Efficient numerical solution of those types of equations is best done via a process of triggered filters, which will be described in the :ref:`AdvancedTopics` section.  Integrating using the Euler algorithm computes the Ito integral, as opposed to the Stratonovich integral, which all the other algorithms compute.
+    
+When SI integration is used in conjunction with SI cross-propagation, a slight variant of the SI algorithm can be employed where the integration in both directions is contained within the iteration process.  This is activated by using ``algorithm="SIC"`` rather than ``algorithm="SI"``.
+
+The SI algorithm is correct to second order in the step-size for deterministic equations, and first order in the step-size for Stratonovich stochastic equations with Wiener noises.  This makes it the highest order stochastic algorithm in XMDS, although there are many sets of equations that integrate more efficiently with lower order algorithms.  When called with the ``iterations="1"`` option (the Euler algorithm), it is correct to first order in the step-size for deterministic equations, [...]
+
+
+.. _RK4:
+
+Runge-Kutta algorithms
+~~~~~~~~~~~~~~~~~~~~~~
+
+Runge-Kutta algorithms are the workhorse of numerical integration, and XMDS employs two fixed step versions: ``algorithm="RK4"``, which is correct to fourth-order in the step size, and ``algorithm="RK9"``, which is correct to ninth order in the step size.  It must be strongly noted that a higher order of convergence does not automatically mean a superior algorithm.  RK9 requires several times the memory of the RK4 algorithm, and each step requires significantly more computation.
+
+All Runge-Kutta algorithms are convergent for Stratonovich stochastic equations at the order of the square root of the step-size.  This 'half-order' convergence may seem very weak, but for some classes of stochastic equation this improves up to one half of the deterministic order of convergence.  Also, the convergence of some stochastic equations is limited by the 'deterministic part', which can be improved dramatically by using a higher order Runge-Kutta method.
+
+
+.. _ARK45:
+
+Adaptive Runge-Kutta algorithms
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Fixed step integrators can encounter two issues.  First, as the equations or parameters of a simulation are changed, the minimum number of steps required to integrate it may change.  This means that the convergence must be re-tested multiple times for each set of parameters, as overestimating the number of steps required to perform an integration to a specified error tolerance can be very inefficient. Second, even if the minimum acceptable number of steps required is known for a given si [...]
+algorithms get around this problem by testing the convergence during the integration, and adjusting the step-size until it reaches some target tolerance.
+
+XMDS employs two adaptive step-size algorithms based on 'embedded Runge-Kutta' methods.  These are Runge-Kutta methods that can output multiple variables that have different convergence.  The difference between the higher-order and the lower-order solutions gives an estimate of the error in each step, which can then be used to estimate an appropriate size for the next step.  We use ``algorthim="ARK45"``, which contains fourth and fifth order solutions, and ``algorthim=ARK89``, which cont [...]
+
+All adaptive stepsize algorithms require a ``tolerance`` attribute, which must be a positive real number that defines the allowable error per step.  It is also possible to specify a ``max_iterations`` attribute, which is a positive integer that stops the integrator from trying too many times to find an acceptable stepsize.  The integrator will abort with an error if the number of attempts for a single step exceeds the maximum specified with this attribute.
+
+As all Runge-Kutta solutions have equal order of convergence for stochastic equations, *if the step-size is limited by the stochastic term then the step-size estimation is entirely unreliable*.  Adaptive Runge-Kutta algorithms are therefore not appropriate for stochastic equations.
+
+
+.. _FiltersElement:
+
+Filters element
+---------------
+
+:ref:`Filter elements<FilterElement>` are used inside :ref:`sequence elements<SequenceElement>` to execute arbitrary code, or make discontinuous changes in the vectors.  Sometimes it is desirable to perform a filter element at the beginning or end of each step in an integration.  This can be done by placing ``<filter>`` elements in a ``<filters>`` element within the ``<integrate>`` element.  The ``<filters>`` element specifies whether the filters are to be executed at the end of each ste [...]
+is then executed in the order found in the ``<filters>`` element.
+
+Example syntax::
+
+    <integrate algorithm="ARK45" interval="100000.0" steps="10000000" tolerance="1e-8">
+      <samples>5000 100</samples>
+      <filters where="step end">
+        <filter>
+            <dependencies>vector1 vector2</dependencies>
+            <![CDATA[
+                x = 1;
+                y *= ynorm;
+                ]]>
+        </filter>
+      </filters>
+
+      <operators>
+        <integration_vectors>vector1</integration_vectors>
+        <![CDATA[
+        dx_dt = alpha;
+        dy_dt = beta*y;
+        ]]>
+      </operators>
+    </integrate>
+
+
+.. _BreakpointElement:
+
+Breakpoint element
+==================
+
+The ``<breakpoint>`` element is used to output the full state of one or more vectors.  Unlike sampled output, it executes immediately rather than at the end of a program, and can therefore be used to examine the current state of an ongoing simulation.  The vectors to be output are defined via a :ref:`<dependencies><Dependencies>` element, and the basis is chosen by the ``basis`` attribute supplied to that ``<dependencies>`` element, as usual.  A single ``<breakpoint>`` element must only  [...]
+
+Example syntax::
+
+    <breakpoint filename="groundstate_break.xsil" format="hdf5">
+      <dependencies basis="ky">wavefunction</dependencies>
+    </breakpoint>
+
+.. _OutputElement:
+
+Output element
+==============
+
+The ``<output>`` element describes the output of the program.  It is often inefficient to output the complete state of all vectors at all times during a large simulation, so the purpose of this function is to define subsets of the information required for output.  Each different format of information is described in a different ``<sampling_group>`` element inside the output element.  The ``<output>`` element may contain any number of ``<sampling_group>`` elements.  The format of the outp [...]
+
+The ``<samples>`` inside ``<integrate>`` elements defines a string of integers, with exactly one for each ``<sampling_group>`` element.  During that integration, the variables described in each ``<sampling_group>`` element will be sampled and stored that number of times.  
+
+
+.. _SamplingGroupElement:
+
+Sampling Group Element
+----------------------
+
+A ``<sampling_group>`` element defines a set of variables that we wish to output, typically they are functions of some subset of vectors.  The names of the desired variables are listed in a ``<moments>`` element, just like the ``<components>`` element of a vector.  They are defined with a ':ref:`CDATA<XMDSCSyntax>`' block, accessing any components of vectors and computed vectors that are defined in a :ref:`<dependencies><Dependencies>` element, also just like a vector.  :ref:`Computed ve [...]
+    
+The basis of the output is specified by the ``basis`` attribute.  This overrides any basis specification in the ``<dependencies>`` element.  Because we often wish to calculate these vectors on a finer grid than we wish to output, it is possible to specify that the output on a subset of the points defined for any transverse dimension.  This is done by adding a number in parentheses after that dimension in the basis string, e.g. ``basis="x y(32) kz(64)"``.  If the number is zero, then that [...]
+    
+The ``initial_sample`` attribute, which must be "yes" or "no", determines whether the moment group will be sampled before any integration occurs.
+
+Example syntax::
+
+    <output format="hdf5" filename="SimOutput.xsil">
+      <sampling_group basis="x y" initial_sample="yes">
+        <computed_vector name="filter3" dimensions="" type="complex">
+          <components>sparemomentagain</components>
+          <evaluation>
+            <dependencies basis="kx ky">integrated_u main</dependencies>
+            <![CDATA[
+              sparemomentagain = mod2(u);
+            ]]>
+          </evaluation>
+        </computed_vector>
+        <operator kind="ex" constant="no">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <moments>amp ke</moments>
+        <dependencies>main filter1</dependencies>
+        <![CDATA[
+          amp = mod2(u + moment);
+          ke = mod2(L[u]);
+        ]]>
+      </sampling_group>
+
+      <sampling_group basis="kx(0) ky(64)" initial_sample="yes">
+        <moments>Dens_P </moments>
+        <dependencies>fields </dependencies>
+        <![CDATA[
+          Dens_P = mod2(psi);
+        ]]>
+      </sampling_group>
+    </output>
+
+
+.. _XMDSCSyntax:
+
+XMDS-specific C syntax
+======================
+
+Sampling complex numbers can be written more efficiently using:
+
+.. code-block:: xpdeint
+
+      <![CDATA[
+        _SAMPLE_COMPLEX(W);
+      ]]>
+
+which is short for
+
+.. code-block:: xpdeint
+
+      <![CDATA[
+        WR = W.Re();
+        WI = W.Im();
+      ]]>
+
+Various properties of dimensions are available.  For example, for a dimension called ``x``:
+
+* The number of points is accessible with the variable ``_lattice_x``,
+* The minimum range of that dimension is ``_min_x``,
+* The maximum range of that dimension is ``_max_x``,
+* The step size of a dimension is ``dx``, and if it is constant, also available using ``_dx``, but note that the latter does not include the effect of any ``volumePrefix`` you may have set!
diff --git a/admin/userdoc-source/reference_index.rst b/admin/userdoc-source/reference_index.rst
new file mode 100644
index 0000000..bc1fd43
--- /dev/null
+++ b/admin/userdoc-source/reference_index.rst
@@ -0,0 +1,15 @@
+Reference section
+=================
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+   
+   reference_installation_and_configuration
+ 
+   reference_usefulXMLSyntax
+
+   reference_schema
+
+   reference_elements
diff --git a/admin/userdoc-source/reference_installation_and_configuration.rst b/admin/userdoc-source/reference_installation_and_configuration.rst
new file mode 100644
index 0000000..ad55368
--- /dev/null
+++ b/admin/userdoc-source/reference_installation_and_configuration.rst
@@ -0,0 +1,38 @@
+.. _ReferenceConfigurationInstallationRuntime:
+
+Configuration, installation and runtime options
+===============================================
+
+Running the 'xmds2' program with the option '--help', gives several options that can change its behaviour at runtime.  These include:
+  * '-o' or '--output', which overrides the name of the output file to be generated
+  * '-n' or '--no-compile', which generates the C code for the simulation, but does not try to compile it
+  * '-v' or '--verbose', which gives verbose output about compilation flags.
+  * '-g' or '--debug', which compiles the simulation in debug mode (compilation errors refer to lines in the source, not the .xmds file). This option implies '-v'. This option is mostly useful when debugging XMDS code generation.
+  * '--waf-verbose', which makes ``waf`` be very verbose when configuring XMDS or compiling simulations.  This option is intended for developer use only to aid in diagnosing problems with ``waf``.
+
+It also has commands to configure XMDS2 and recheck the installation.  If your program requires extra paths to compile, you can configure XMDS2 to include those paths by default.  Simply use the command
+
+.. code-block:: bash
+
+    $ xmds2 --configure --include-path /path/to/include --lib-path /path/to/lib 
+
+Alternatively, you can set the ``CXXFLAGS`` or ``LINKFLAGS`` environment variables before calling ``xmds2 --reconfigure``.  For example, to pass the compiler flag ``-pedantic`` and the link flag ``-lm`` using the bash shell, use:
+
+.. code-block:: bash
+
+    $ export CXXFLAGS="-pedantic"
+    $ export LINKFLAGS="-lm" 
+    $ xmds2 --reconfigure``
+    
+This method can also be used to change the default compilers for standard and parallel processing, using the CXX and MPICXX flags respectively.
+
+Running XMDS2 with the '--configure' option also searches for packages that have been installed since you last installed or configured XMDS2.  If you wish to run 'xmds2 --configure' with the same extra options as last time, simply use the command:
+
+.. code-block:: bash
+
+    $ xmds2 --reconfigure
+
+A detailed log of the checks is saved in the file '~/.xmds/waf_configure/config.log'.  This can be used to identify issues with packages that XMDS2 is not recognised, but you think that you have successfully installed on your system.
+
+
+
diff --git a/admin/userdoc-source/reference_schema.rst b/admin/userdoc-source/reference_schema.rst
new file mode 100644
index 0000000..88b3421
--- /dev/null
+++ b/admin/userdoc-source/reference_schema.rst
@@ -0,0 +1,157 @@
+.. _ReferenceSchema:
+
+****************
+XMDS2 XML Schema
+****************
+
+
+There are many, many XML tags that can make up an XMDS2 script. Most of them are optional, or have default values if not specified. It is, however, useful to know which elements are possible, and their position and relationship to other elements in the script. Shown below is the full XML tree for XMDS2, which shows all possible elements and their position in the tree. An ellipsis (...) outside an element indicates the element above can be repeated indefinitely, and an ellipsis inside an  [...]
+
+The syntax <element /> can be used for lowest-level elements that have attributes but no content, and are shorthand for <element> </element>. This shorthand notation can also be used for elements which can only contain the content "yes" or "no"; in this case the presence of <element /> is equivalent to <element> yes </element>, and the absence of such an element is equivalent to <element> no </element>
+
+The possible attributes and attribute values for each element are not shown; see the individual entries in the Reference section for details.
+
+
+.. parsed-literal::
+
+    <?xml version="1.0" encoding="UTF-8"?>
+    <:ref:`simulation <SimulationElement>` xmds-version="2">
+      <:ref:`name <NameElement>`> <:ref:`/name <NameElement>`>
+      <:ref:`author <AuthorElement>`> <:ref:`author <AuthorElement>`>
+      <:ref:`description <DescriptionElement>`> <:ref:`/description <DescriptionElement>`>
+      
+      <:ref:`features <FeaturesElement>`>
+        <:ref:`arguments <ArgumentsElement>`>
+          <:ref:`argument <ArgumentElement>` />
+          <:ref:`argument <ArgumentElement>` />
+          ...
+        <:ref:`/arguments <ArgumentsElement>`>
+        <:ref:`auto_vectorise <AutoVectorise>` />
+        <:ref:`benchmark <Benchmark>` />
+        <:ref:`bing <Bing>` />
+        <:ref:`cflags <CFlags>`> <:ref:`/cflags <CFlags>`>
+        <:ref:`chunked_output <ChunkedOutput>` />
+        <:ref:`diagnostics <Diagnostics>` />
+        <:ref:`error_check <ErrorCheck>` />
+        <:ref:`halt_non_finite <HaltNonFinite>` />
+        <:ref:`fftw <FFTW>` />
+        <:ref:`globals <Globals>`> <:ref:`/globals <Globals>`>
+        <:ref:`openmp <OpenMP>` />
+        <:ref:`precision <Precision>`> <:ref:`/precision <Precision>`>
+        <:ref:`validation <Validation>` />
+      <:ref:`/features <FeaturesElement>`>
+
+      <:ref:`driver <DriverElement>` />
+  
+      <:ref:`geometry <GeometryElement>`>
+        <:ref:`propagation_dimension <PropagationDimensionElement>`> <:ref:`/propagation_dimension <PropagationDimensionElement>`>
+        <:ref:`transverse_dimensions <TransverseDimensionsElement>`>
+          <:ref:`dimension <DimensionElement>` />
+          <:ref:`dimension <DimensionElement>` />
+          ...
+        <:ref:`/transverse_dimensions <TransverseDimensionsElement>`>
+      <:ref:`/geometry <GeometryElement>`>
+  
+      <:ref:`vector <VectorElement>`>
+        <:ref:`components <ComponentsElement>`> <:ref:`/components <ComponentsElement>`>
+        <:ref:`initialisation <InitialisationElement>`>
+          <:ref:`dependencies <Dependencies>`> <:ref:`/dependencies <Dependencies>`>
+          <:ref:`filename <FilenameElement>`>
+          <![:ref:`CDATA <InitialisationElement>` [
+          ]]>
+        <:ref:`/initialisation <InitialisationElement>`>
+      <:ref:`/vector <VectorElement>`>
+
+      <:ref:`vector <VectorElement>`> ... <:ref:`/vector <VectorElement>`>
+      <:ref:`vector <VectorElement>`> ... <:ref:`/vector <VectorElement>`>
+      ...
+
+      <:ref:`computed_vector <ComputedVectorElement>`>
+        <:ref:`components <ComponentsElement>`> <:ref:`/components <ComponentsElement>`>
+        <:ref:`evaluation <EvaluationElement>`>
+          <:ref:`dependencies <Dependencies>`> <:ref:`/dependencies <Dependencies>`>
+          <![:ref:`CDATA <InitialisationElement>` [
+          ]]>
+        <:ref:`/evaluation <EvaluationElement>`>
+      <:ref:`/computed_vector <ComputedVectorElement>`>
+
+      <:ref:`computed_vector <ComputedVectorElement>`> ... <:ref:`/computed_vector <ComputedVectorElement>`>
+      <:ref:`computed_vector <ComputedVectorElement>`> ... <:ref:`/computed_vector <ComputedVectorElement>`>
+      ...
+
+      <:ref:`noise_vector <NoiseVectorElement>`>
+        <:ref:`components <ComponentsElement>`> <:ref:`/components <ComponentsElement>`>
+      <:ref:`/noise_vector <NoiseVectorElement>`>
+
+      <:ref:`noise_vector <NoiseVectorElement>`> ... <:ref:`/noise_vector <NoiseVectorElement>`>
+      <:ref:`noise_vector <NoiseVectorElement>`> ... <:ref:`/noise_vector <NoiseVectorElement>`>
+      ...
+
+      <:ref:`sequence <SequenceElement>`>
+
+        <:ref:`filter <FilterElement>`>
+          <:ref:`dependencies <Dependencies>`> <:ref:`/dependencies <Dependencies>`>
+          <![:ref:`CDATA <XMDSCSyntax>` [
+          ]]>
+        <:ref:`/filter <FilterElement>`>
+
+        <:ref:`integrate <IntegrateElement>`>
+          <:ref:`samples <SamplesElement>`> <:ref:`/samples <SamplesElement>`>
+
+          <:ref:`computed_vector <ComputedVectorElement>`> ... <:ref:`/computed_vector <ComputedVectorElement>`>
+
+          <:ref:`filters <FiltersElement>`>
+            <:ref:`filter <FilterElement>`> ... <:ref:`/filter <FilterElement>`>
+            <:ref:`filter <FilterElement>`> ... <:ref:`/filter <FilterElement>`>
+            ...
+          <:ref:`/filters <FiltersElement>`>
+      
+          <:ref:`operators <OperatorsElement>`>
+
+            <:ref:`operator <OperatorElement>`>
+              <:ref:`boundary_condition <BoundaryConditionElement>`>
+                <:ref:`dependencies <Dependencies>`> <:ref:`/dependencies <Dependencies>`>
+                <![:ref:`CDATA <XMDSCSyntax>` [
+                ]]>
+              <:ref:`/boundary_condition <BoundaryConditionElement>`>
+              <:ref:`operator_names <OperatorNamesElement>`> <:ref:`/operator_names <OperatorNamesElement>`>
+              <:ref:`dependencies <Dependencies>`> <:ref:`/dependencies <Dependencies>`>
+              <![:ref:`CDATA <XMDSCSyntax>` [
+              ]]>
+            <:ref:`/operator <OperatorElement>`>
+
+            <:ref:`operator <OperatorElement>`> ... <:ref:`/operator <OperatorElement>`>
+            <:ref:`operator <OperatorElement>`> ... <:ref:`/operator <OperatorElement>`>
+            ...
+
+            <:ref:`integration_vectors <IntegrationVectorsElement>`> <:ref:`/integration_vectors <IntegrationVectorsElement>`>
+            <:ref:`dependencies <Dependencies>`> <:ref:`/dependencies <Dependencies>`>
+            <![:ref:`CDATA <XMDSCSyntax>` [
+            ]]>
+
+          <:ref:`/operators <OperatorsElement>`>
+
+        <:ref:`/integrate <IntegrateElement>`>
+    
+        <:ref:`breakpoint <BreakpointElement>`>
+          <:ref:`dependencies <Dependencies>`> <:ref:`/dependencies <Dependencies>`>
+        <:ref:`/breakpoint <BreakpointElement>`>
+
+      <:ref:`/sequence <SequenceElement>`>
+  
+      <:ref:`output <OutputElement>`>
+        <:ref:`sampling_group <SamplingGroupElement>`>
+          <:ref:`dependencies <Dependencies>`> <:ref:`/dependencies <Dependencies>`>
+          <:ref:`moments <SamplingGroupElement>`> <:ref:`/moments <SamplingGroupElement>`>
+          <:ref:`operator <OperatorElement>`> ... <:ref:`/operator <OperatorElement>`>       
+          <![:ref:`CDATA <XMDSCSyntax>` [
+          ]]>
+        <:ref:`/sampling_group <SamplingGroupElement>`>
+
+        <:ref:`sampling_group <SamplingGroupElement>`> ... <:ref:`/sampling_group <SamplingGroupElement>`>
+        <:ref:`sampling_group <SamplingGroupElement>`> ... <:ref:`/sampling_group <SamplingGroupElement>`>
+        ...
+
+      <:ref:`/output <OutputElement>`>
+
+    <:ref:`/simulation <SimulationElement>`>
diff --git a/admin/userdoc-source/reference_usefulXMLSyntax.rst b/admin/userdoc-source/reference_usefulXMLSyntax.rst
new file mode 100644
index 0000000..faf663d
--- /dev/null
+++ b/admin/userdoc-source/reference_usefulXMLSyntax.rst
@@ -0,0 +1,24 @@
+.. _ReferenceUsefulXMLSyntax:
+
+Useful XML Syntax
+=================
+
+Standard XML placeholders can be used to simplify some scripts.  For example, the following (abbreviated) code ensures that the limits of a domain are symmetric.
+
+.. code-block:: xmds2
+
+    <?xml version="1.0" encoding="UTF-8"?>
+    <!DOCTYPE simulation [
+    <!ENTITY Npts    "64">
+    <!ENTITY L      "3.0e-5">
+    ]>
+      <simulation xmds-version="2">
+      
+        . . .
+        
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+              <dimension name="x" lattice="&Npts;"  domain="(-&L;, &L;)" />
+            </transverse_dimensions>
+         </geometry>
diff --git a/admin/userdoc-source/support/preview.sty b/admin/userdoc-source/support/preview.sty
new file mode 100644
index 0000000..7a59afa
--- /dev/null
+++ b/admin/userdoc-source/support/preview.sty
@@ -0,0 +1,381 @@
+%%
+%% This is file `preview.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% preview.dtx  (with options: `style')
+%% preview.dtx  (with options: `style,active')
+%% 
+%% IMPORTANT NOTICE:
+%% 
+%% For the copyright see the source file.
+%% 
+%% Any modified versions of this file must be renamed
+%% with new filenames distinct from preview.sty.
+%% 
+%% For distribution of the original source see the terms
+%% for copying and modification in the file preview.dtx preview.dtx.
+%% 
+%% This generated file may be distributed as long as the
+%% original source files, as listed above, are part of the
+%% same distribution. (The sources need not necessarily be
+%% in the same archive or directory.)
+%%    The preview style for extracting previews from LaTeX documents.
+%%    Developed as part of AUCTeX <URL:http://www.gnu.org/software/auctex>.
+\NeedsTeXFormat{LaTeX2e} \def\reserved at a #1#2$#3:
+#4${\xdef#1{\reserved at c #2#4 $}} \def\reserved at c #1 #2${#1}
+\begingroup \catcode`\_=12
+\reserved at a\pr at version $Name: release_11_85 $ \ifx\pr at version\@empty
+\reserved at a\pr at version CVS-$Revision: 1.124 $ \endgroup \else
+  \def\next release_{} \lccode`\_=`.
+  \edef\next{\lowercase{\endgroup
+    \def\noexpand\pr at version{\expandafter\next\pr at version}}} \next \fi
+\reserved at a\next $Date: 2008/02/03 14:53:31 $
+\edef\next{\noexpand\ProvidesPackage{preview}%
+  [\next\space \pr at version\space (AUCTeX/preview-latex)]}
+\next
+\let\ifPreview\iffalse
+\let\preview at delay=\@gobble
+\let\pr at advise=\@gobbletwo
+\long\def\pr at advise@ship#1#2#3{}
+\def\pr at loadcfg#1{\InputIfFileExists{#1.cfg}{}{}}
+\DeclareOption{noconfig}{\let\pr at loadcfg=\@gobble}
+\long\def\pr at addto@front#1#2{%
+  \toks@{#2}\toks@\expandafter{\the\expandafter\toks@#1}%
+  \xdef#1{\the\toks@}}
+\DeclareOption{active}{%
+  \let\ifPreview\iftrue
+  \def\pr at advise#1{%
+    \expandafter\pr at adviseii\csname pr@\string#1\endcsname#1}%
+  \long\def\pr at advise@ship#1#2#3{\pr at advise#1{\pr at protect@ship{#2}{#3}}}%
+  \let\preview at delay\@firstofone}
+\long\def\pr at adviseii#1#2#3{\preview at delay{%
+  \ifx#1\relax \let#1#2\fi
+  \toks@{#3#1}%
+  \ifx\@undefined\protected \else \protected\fi
+  \long\edef#2{\the\toks@}}}
+\DeclareOption{delayed}{%
+  \ifPreview \def\preview at delay{\AtBeginDocument}\fi
+}
+\newif\ifpr at fixbb
+\pr at fixbbfalse
+\DeclareOption{psfixbb}{\ifPreview%
+  \pr at fixbbtrue
+  \newbox\pr at markerbox
+  \setbox\pr at markerbox\hbox{\special{psfile=/dev/null}}\fi
+}
+\let\pr at graphicstype=\z@
+\DeclareOption{dvips}{%
+  \let\pr at graphicstype\@ne
+  \preview at delay{\AtBeginDvi{%
+      \special{!/preview at version(\pr at version)def}
+      \special{!userdict begin/preview-bop-level 0 def%
+      /bop-hook{/preview-bop-level dup load dup 0 le{/isls false def%
+          /vsize 792 def/hsize 612 def}if 1 add store}bind def%
+      /eop-hook{/preview-bop-level dup load dup 0 gt{1 sub}if
+        store}bind def end}}}}
+\DeclareOption{pdftex}{%
+  \let\pr at graphicstype\tw@}
+\begingroup
+\catcode`\*=11
+\@firstofone{\endgroup
+\DeclareOption{displaymath}{%
+  \preview at delay{\toks@{%
+      \pr at startbox{\noindent$$%
+        \aftergroup\pr at endbox\@gobbletwo}{$$}\@firstofone}%
+    \everydisplay\expandafter{\the\expandafter\toks@
+      \expandafter{\the\everydisplay}}}%
+  \pr at advise@ship\equation{\begingroup\aftergroup\pr at endbox
+    \def\dt at ptrue{\m at ne=\m at ne}\noindent}%
+    {\endgroup}%
+  \pr at advise@ship\equation*{\begingroup\aftergroup\pr at endbox
+    \def\dt at ptrue{\m at ne=\m at ne}\noindent}%
+    {\endgroup}%
+  \PreviewOpen[][\def\dt at ptrue{\m at ne=\m at ne}\noindent#1]\[%
+  \PreviewClose\]%
+  \PreviewEnvironment[][\noindent#1]{eqnarray}%
+  \PreviewEnvironment[][\noindent#1]{eqnarray*}%
+  \PreviewEnvironment{displaymath}%
+}}
+\begingroup
+\def\next#1#2{%
+  \endgroup
+  \DeclareOption{textmath}{%
+    \PreviewEnvironment{math}%
+    \preview at delay{\ifx#1\@undefined \let#1=$%$
+      \fi\catcode`\$=\active
+      \ifx\xyreuncatcodes\@undefined\else
+        \edef\next{\catcode`@=\the\catcode`@\relax}%
+        \makeatother\expandafter\xyreuncatcodes\next\fi}%
+    \pr at advise@ship\(\pr at endaftergroup{}% \)
+    \pr at advise@ship#1{\@firstoftwo{\let#1=#2%
+        \futurelet\reserved at a\pr at textmathcheck}}{}}%
+  \def\pr at textmathcheck{\expandafter\pr at endaftergroup
+    \ifx\reserved at a#1{#2#2}\expandafter\@gobbletwo\fi#2}}
+\lccode`\~=`\$
+\lowercase{\expandafter\next\expandafter~}%
+  \csname pr@\string$%$
+  \endcsname
+\DeclareOption{graphics}{%
+  \PreviewMacro[*[[!]{\includegraphics}%]]
+}
+\def\pr at floatfix#1#2{\ifx#1#2%
+  \ifx#1\@undefined\else
+  \PackageWarningNoLine{preview}{%
+Your document class has a bad definition^^J
+of \string#1, most likely^^J
+\string\let\string#1=\string#2^^J
+which has now been changed to^^J
+\string\def\string#1{\string#2}^^J
+because otherwise subsequent changes to \string#2^^J
+(like done by several packages changing float behaviour)^^J
+can't take effect on \string#1.^^J
+Please complain to your document class author}%
+  \def#1{#2}\fi\fi}
+\begingroup
+\def\next#1#2{\endgroup
+  \DeclareOption{floats}{%
+    \pr at floatfix\endfigure\end at float
+    \pr at floatfix\endtable\end at float
+    \pr at floatfix#1\end at dblfloat
+    \pr at floatfix#2\end at dblfloat
+    \PreviewSnarfEnvironment[![]{@float}%]
+    \PreviewSnarfEnvironment[![]{@dblfloat}%]
+  }}
+\expandafter\next\csname endfigure*\expandafter\endcsname
+  \csname endtable*\endcsname
+\DeclareOption{sections}{%
+  \PreviewMacro[!!!!!!*[[!]{\@startsection}%]]
+  \PreviewMacro[*[[!]{\chapter}%]]
+}
+\DeclareOption*
+   {\InputIfFileExists{pr\CurrentOption.def}{}{\OptionNotUsed}}
+\def\PreviewMacro{\@ifstar\pr at starmacro\pr at macro}
+\long\def\pr at domacro#1#2{%
+   \long\def\next##1{#2}%
+   \pr at callafter\next#1]\pr at endparse}
+\newcommand\pr at macro[1][]{%
+   \toks@{\pr at domacro{#1}}%
+   \long\edef\next[##1]##2{%
+    \noexpand\pr at advise@ship{##2}{\the\toks@{##1\noexpand\pr at endbox}}{}}%
+   \@ifnextchar[\next\pr at macroii}
+\def\pr at macroii{\next[##1]}
+\long\def\pr at endmacro#1{#1\pr at endbox}
+\long\def\pr at protect@domacro#1#2{\pr at protect{%
+    \long\def\next##1{#2}%
+    \pr at callafter\next#1]\pr at endparse}}
+\newcommand\pr at starmacro[1][]{\toks@{\pr at protect@domacro{#1}}%
+    \long\edef\next[##1]##2{%
+      \noexpand\pr at advise##2{\the\toks@{##1}}}%
+    \@ifnextchar[\next{\next[]}}
+\def\PreviewOpen{\@ifstar\pr at starmacro\pr at open}
+\newcommand\pr at open[1][]{%
+   \toks@{\pr at domacro{#1}}%
+   \long\edef\next[##1]##2{%
+     \noexpand\pr at advise##2{\begingroup
+     \noexpand\pr at protect@ship
+        {\the\toks@{\begingroup\aftergroup\noexpand\pr at endbox##1}}%
+        {\endgroup}}}%
+   \@ifnextchar[\next\pr at macroii}
+\def\PreviewClose{\@ifstar\pr at starmacro\pr at close}
+\newcommand\pr at close[1][]{%
+  \toks@{\pr at domacro{#1}}%
+  \long\edef\next[##1]##2{%
+   \noexpand\pr at advise{##2}{\the\toks@{##1\endgroup}}}%
+   \@ifnextchar[\next\pr at macroii}
+\def\PreviewEnvironment{\@ifstar\pr at starenv\pr at env}
+\newcommand\pr at starenv[1][]{\toks@{\pr at starmacro[{#1}]}%
+  \long\edef\next##1##2{%
+    \the\toks@[{##2}]##1}%
+  \begingroup\pr at starenvii}
+\newcommand\pr at starenvii[2][]{\endgroup
+  \expandafter\next\csname#2\endcsname{#1}%
+  \expandafter\pr at starmacro\csname end#2\endcsname}
+\newcommand\pr at env[1][]{%
+   \toks@{\pr at domacro{#1}}%
+   \long\edef\next[##1]##2{%
+   \noexpand\expandafter\noexpand\pr at advise@ship
+     \noexpand\csname##2\noexpand\endcsname{\the\toks@
+      {\begingroup\aftergroup\noexpand\pr at endbox##1}}{\endgroup}}%
+   \@ifnextchar[\next\pr at macroii %]
+ }
+\newcommand{\PreviewSnarfEnvironment}[2][]{%
+  \expandafter\pr at advise
+   \csname #2\endcsname{\pr at snarfafter{#1}}%
+ \expandafter\pr at advise
+   \csname end#2\endcsname{\pr at endsnarf}}
+\let\pr at ship@start\@empty
+\let\pr at ship@end\@empty
+\newenvironment{preview}{\ignorespaces}{\ifhmode\unskip\fi}
+\newenvironment{nopreview}{\ignorespaces}{\ifhmode\unskip\fi}
+\ProcessOptions\relax
+\ifPreview\else\expandafter\endinput\fi
+%%    The preview style for extracting previews from LaTeX documents.
+%%    Developed as part of AUCTeX <URL:http://www.gnu.org/software/auctex>.
+\newif\ifpr at outer
+\pr at outertrue
+\newcount\pr at snippet
+\global\pr at snippet=1
+\def\pr at protect{\ifx\protect\@typeset at protect
+  \ifpr at outer \expandafter\expandafter\expandafter
+     \@secondoftwo\fi\fi\@gobble}
+\def\pr at protect@ship{\pr at protect{\@firstoftwo\pr at startbox}%
+   \@gobbletwo}
+\def\pr at insert{\begingroup\afterassignment\pr at insertii\count@}
+\def\pr at insertii{\endgroup\setbox\pr at box\vbox}
+\def\pr at mark{{\afterassignment}\toks@}
+\def\pr at marks{{\aftergroup\pr at mark\afterassignment}\count@}
+\newbox\pr at box
+\long\def\pr at startbox#1#2{%
+  \ifpr at outer
+    \toks@{#2}%
+    \edef\pr at cleanup{\the\toks@}%
+    \setbox\pr at box\vbox\bgroup
+    \break
+    \pr at outerfalse\@arrayparboxrestore
+    \let\insert\pr at insert
+    \let\mark\pr at mark
+    \let\marks\pr at marks
+    \expandafter\expandafter\expandafter
+    \pr at ship@start
+    \expandafter\@firstofone
+  \else
+     \expandafter \@gobble
+  \fi{#1}}
+\def\pr at endbox{%
+   \let\reserved at a\relax
+   \ifvmode \edef\reserved at a{\the\everypar}%
+      \ifx\reserved at a\@empty\else
+            \dimen@\prevdepth
+            \noindent\par
+            \setbox\z@\lastbox\unskip\unpenalty
+            \prevdepth\dimen@
+            \setbox\z@\hbox\bgroup\penalty-\maxdimen\unhbox\z@
+              \ifnum\lastpenalty=-\maxdimen\egroup
+              \else\egroup\box\z@ \fi\fi\fi
+   \ifhmode \par\unskip\setbox\z@\lastbox
+     \nointerlineskip\hbox{\unhbox\z@\/}%
+   \else \unskip\unpenalty\unskip \fi
+   \egroup
+   \setbox\pr at box\vbox{%
+       \baselineskip\z at skip \lineskip\z at skip \lineskiplimit\z@
+       \@begindvi
+       \nointerlineskip
+       \splittopskip\z at skip\setbox\z@\vsplit\pr at box to\z@
+       \unvbox\z@
+       \nointerlineskip
+       %\color at setgroup
+       \box\pr at box
+       %\color at endgroup
+     }%
+   \pr at ship@end
+   {\let\protect\noexpand
+   \voffset=-\ht\pr at box
+   \hoffset=\z@
+   \c at page=\pr at snippet
+   \pr at shipout
+   \ifpr at fixbb\hbox{%
+     \dimen@\wd\pr at box
+     \@tempdima\ht\pr at box
+     \@tempdimb\dp\pr at box
+     \box\pr at box
+     \llap{\raise\@tempdima\copy\pr at markerbox\kern\dimen@}%
+     \lower\@tempdimb\copy\pr at markerbox}%
+   \else \box\pr at box \fi}%
+   \global\advance\pr at snippet\@ne
+   \pr at cleanup
+}
+\let\pr at shipout=\shipout
+\def\shipout{\deadcycles\z@\bgroup\setbox\z@\box\voidb at x
+  \afterassignment\pr at shipoutegroup\setbox\z@}
+\def\pr at shipoutegroup{\ifvoid\z@ \expandafter\aftergroup\fi \egroup}
+\def\pr at parseit#1{\csname pr at parse#1\endcsname}
+\let\pr at endparse=\@percentchar
+\def\next#1{%
+\def\pr at callafter{%
+  \afterassignment\pr at parseit
+  \let#1= }}
+\expandafter\next\csname pr at parse\pr at endparse\endcsname
+\long\expandafter\def\csname pr at parse*\endcsname#1\pr at endparse#2{%
+  \begingroup\toks@{#1\pr at endparse{#2}}%
+  \edef\next##1{\endgroup##1\the\toks@}%
+  \@ifstar{\next{\pr at parse@*}}{\next\pr at parseit}}
+\long\expandafter\def\csname pr at parse[\endcsname#1\pr at endparse#2{%
+  \begingroup\toks@{#1\pr at endparse{#2}}%
+  \edef\next##1{\endgroup##1\the\toks@}%
+  \@ifnextchar[{\next\pr at bracket}{\next\pr at parseit}}
+\long\def\pr at bracket#1\pr at endparse#2[#3]{%
+   \pr at parseit#1\pr at endparse{#2[{#3}]}}
+\expandafter\let\csname pr at parse]\endcsname=\pr at parseit
+\long\def\pr at parse#1\pr at endparse#2#3{%
+  \pr at parseit#1\pr at endparse{#2{#3}}}
+\expandafter\let\csname pr at parse!\endcsname=\pr at parse
+\long\expandafter\def\csname pr at parse?\endcsname#1#2\pr at endparse#3{%
+  \begingroup\toks@{#2\pr at endparse{#3}}%
+  \@ifnextchar#1{\pr at parsecond\@firstoftwo}%
+                {\pr at parsecond\@secondoftwo}}
+\def\pr at parsecond#1{\expandafter\endgroup
+  \expandafter\expandafter\expandafter\pr at parseit
+  \expandafter#1\the\toks@}
+ \long\def\pr at parse@#1#2\pr at endparse#3{%
+   \pr at parseit #2\pr at endparse{#3#1}}
+\long\expandafter\def\csname pr at parse-\endcsname
+  #1\pr at endparse#2{\begingroup
+  \toks@{\endgroup\pr at parseit #1\pr at endparse{#2}}%
+  {\aftergroup\the\aftergroup\toks@ \afterassignment}%
+  \let\next= }
+\long\expandafter\def\csname pr at parse:\endcsname
+  #1#2#3\pr at endparse#4{\begingroup
+    \toks@{\endgroup \pr at parseit#3\pr at endparse{#4}}%
+    \long\def\next#1{#2}%
+    \the\expandafter\toks@\next}
+\long\expandafter\def\csname pr at parse#\endcsname
+  #1#2#3\pr at endparse#4{\begingroup
+    \toks@{#4}%
+    \long\edef\next##1{\toks@{\the\toks@##1}}%
+    \toks@{\endgroup \pr at parseit#3\pr at endparse}%
+    \long\def\reserved at a#1{{#2}}%
+    \the\expandafter\next\reserved at a}
+\def\pr at endaftergroup#1{#1\aftergroup\pr at endbox}
+\let\pr at endsnarf\relax
+\long\def\pr at snarfafter#1{\ifpr at outer
+     \pr at ship@start
+     \let\pr at ship@start\relax
+     \let\pr at endsnarf\endgroup
+   \else
+     \let\pr at endsnarf\relax
+   \fi
+  \pr at protect{\pr at callafter\pr at startsnarf#1]\pr at endparse}}
+\def\pr at startsnarf#1{#1\begingroup
+   \pr at startbox{\begingroup\aftergroup\pr at endbox}{\endgroup}%
+   \ignorespaces}
+\renewenvironment{preview}{\begingroup
+   \pr at startbox{\begingroup\aftergroup\pr at endbox}%
+               {\endgroup}%
+   \ignorespaces}%
+   {\ifhmode\unskip\fi\endgroup}
+\renewenvironment{nopreview}{\pr at outerfalse\ignorespaces}%
+  {\ifhmode\unskip\fi}
+\newtoks\pr at output
+\pr at output\output
+\output{%
+  \pr at outerfalse
+  \let\@begindvi\@empty
+  \the\pr at output}
+\let\output\pr at output
+\def\pr at typeinfos{\typeout{Preview: Fontsize \f at size pt}%
+  \ifnum\mag=\@m\else\typeout{Preview: Magnification \number\mag}\fi
+  \ifx\pdfoutput\@undefined \else
+    \ifx\pdfoutput\relax \else
+      \ifnum\pdfoutput>\z@
+        \typeout{Preview: PDFoutput 1}%
+      \fi
+    \fi
+  \fi
+}
+\AtBeginDocument{\pr at typeinfos}
+\pr at loadcfg{prdefault}
+\endinput
+%%
+%% End of file `preview.sty'.
diff --git a/admin/userdoc-source/tutorial.rst b/admin/userdoc-source/tutorial.rst
new file mode 100644
index 0000000..ff5d1fd
--- /dev/null
+++ b/admin/userdoc-source/tutorial.rst
@@ -0,0 +1,258 @@
+.. _QuickStartTutorial:
+
+Quickstart Tutorial
+===================
+
+In this tutorial, we will create an XMDS2 script to solve the Lorenz Attractor, an example of a dynamical system that exhibits chaos. The equations describing this problem are 
+
+.. math::
+    \frac{dx}{dt} &= \sigma (y - x)\\
+    \frac{dy}{dt} &= x (\rho - z) - y\\
+    \frac{dz}{dt} &= xy - \beta z
+
+where we will solve with the parameters :math:`\sigma=10`, :math:`\rho=28`, :math:`\beta = \frac{8}{3}` and the initial condition :math:`x(0) = y(0) = z(0) = 1`.
+
+Below is a script that solves this problem (it's also saved as examples/lorenz.xmds in your XMDS2 directory). Don't worry if it doesn't make sense yet, soon we'll break it down into easily digestible parts.
+
+.. code-block:: xpdeint
+    
+    <?xml version="1.0" encoding="UTF-8"?>
+    <simulation xmds-version="2">
+      <name>lorenz</name>
+      
+      <!-- While not strictly necessary, the following two tags are handy. -->
+      <author>Graham Dennis</author>
+      <description>
+        The Lorenz Attractor, an example of chaos.
+      </description>
+      
+      <!-- 
+      This element defines some constants.  It can be used for other 
+      features as well, but we will go into that in more detail later.
+      -->
+      <features>
+        <globals>
+            <![CDATA[
+            real sigma = 10.0;
+            real b = 8.0/3.0;
+            real r = 28.0;
+            ]]>
+         </globals>
+       </features>
+       
+      <!-- 
+      This part defines all of the dimensions used in the problem,
+      in this case, only the dimension of 'time' is needed.
+      -->
+      <geometry>
+        <propagation_dimension> t </propagation_dimension>
+      </geometry>
+      
+      <!-- A 'vector' describes the variables that we will be evolving. -->
+      <vector name="position" type="real">
+        <components>
+          x y z
+        </components>
+        <initialisation>
+          <![CDATA[
+          x = y = z = 1.0;
+          ]]>
+        </initialisation>
+      </vector>
+      
+      <sequence>
+        <!--
+        Here we define what differential equations need to be solved
+        and what algorithm we want to use.
+        -->
+        <integrate algorithm="ARK89" interval="20.0" tolerance="1e-7">
+          <samples>5000</samples>
+          <operators>
+            <integration_vectors>position</integration_vectors>
+            <![CDATA[
+            dx_dt = sigma*(y-x);
+            dy_dt = r*x - y - x*z;
+            dz_dt = x*y - b*z;
+            ]]>
+          </operators>
+        </integrate>
+      </sequence>
+      
+      <!-- This part defines what data will be saved in the output file -->
+      <output format="hdf5" filename="lorenz.xsil">
+        <sampling_group initial_sample="yes">
+          <moments>xR yR zR</moments>
+          <dependencies>position</dependencies>
+          <![CDATA[
+            xR = x;
+            yR = y;
+            zR = z;
+          ]]>
+        </sampling_group>
+      </output>
+    </simulation>
+
+You can compile and run this script with **XMDS2**. To compile the script, just pass the name of the script as an argument to **XMDS2**.
+
+    .. code-block:: none
+
+        $ xmds2 lorenz.xmds
+        xmds2 version 2.1 "Happy Mollusc" (r2680)
+        Copyright 2000-2012 Graham Dennis, Joseph Hope, Mattias Johnsson
+                            and the xmds team
+        Generating source code...
+        ... done
+        Compiling simulation...
+        ... done. Type './lorenz' to run.
+
+Now we can execute the generated program 'lorenz'.
+
+    .. code-block:: none
+
+        $ ./lorenz 
+        Sampled field (for moment group #1) at t = 0.000000e+00
+        Sampled field (for moment group #1) at t = 4.000000e-03
+        Current timestep: 4.000000e-03
+        Sampled field (for moment group #1) at t = 8.000000e-03
+        Current timestep: 4.000000e-03
+
+        ... many lines omitted ...
+
+        Current timestep: 4.000000e-03
+        Sampled field (for moment group #1) at t = 1.999600e+01
+        Current timestep: 4.000000e-03
+        Sampled field (for moment group #1) at t = 2.000000e+01
+        Current timestep: 4.000000e-03
+        Segment 1: minimum timestep: 9.997900e-06 maximum timestep: 4.000000e-03
+          Attempted 7386 steps, 0.00% steps failed.
+        Generating output for lorenz
+
+The program generated by **XMDS2** has now integrated your equations and produced two files.  The first is the XML file "lorenz.xsil", which contains the all the information used to generate the simulation (including the XMDS2 code) and the metadata description of the output.  The second file is named "lorenz.h5", which is a `HDF5 <http://www.hdfgroup.org/HDF5>`_ file containing all of the output data.   You can analysing these files yourself, or import them into your favourite visualisa [...]
+
+    .. code-block:: none
+
+        $ xsil2graphics2 -e lorenz.xsil 
+        xsil2graphics2 from xmds2 version 2.1 "Happy Mollusc" (r2680)
+        Generating output for Mathematica 6+.
+        Writing import script for 'lorenz.xsil' to 'lorenz.nb'.
+
+This has now generated the file 'lorenz.nb', which is a Mathematica notebook that loads the output data of the simulation.  Loading it into Mathematica allows us to plot the points {xR1, yR1, zR1}:
+
+    .. code-block:: none
+
+        ll = Transpose[{xR1, yR1, zR1}];
+        ListPointPlot3D[ll]
+
+.. image:: images/lorenz.*
+    :align: center
+
+...and we see the lobes of the strange attractor.  Now let us examine the code that produced this simulation.
+
+First, we have the top level description of the code.
+
+.. code-block:: xpdeint
+
+    <?xml version="1.0" encoding="UTF-8"?>
+    <simulation xmds-version="2">
+      <name>lorenz</name>
+      
+      <!-- While not strictly necessary, the following two tags are handy. -->
+      <author>Graham Dennis</author>
+      <description>
+        The Lorenz Attractor, an example of chaos.
+      </description>
+
+One of the advantages of an XML format is that these tags are almost entirely self-explanatory.  XMDS2 files follow full XML syntax, so elements can be commented out using the ``<!--`` and ``-->`` brackets, and we have an example of that here. 
+
+The first line, ``<?xml ...>``, just specifies the encoding and XML version. It is optional, but its presence helps some text editors perform the correct syntax highlighting.
+
+The ``<simulation>`` element is mandatory, and encloses the entire simulation script.
+
+The ``<name>`` element is optional, but recommended. It defines the name of the executable program that will be generated, as well as the default name of the output data files (although this can be over-ridden in the ``<output>`` element if desired). If ``<name>`` is not present, it will default to the filename of the script.
+
+The next element we have used can be skipped entirely if you wish to use the default set of features and you don't want to define any global constants for your simulation.  
+
+.. code-block:: xpdeint
+    
+      <features>
+        <globals>
+            <![CDATA[
+            real sigma = 10.0;
+            real b = 8.0/3.0;
+            real r = 28.0;
+            ]]>
+         </globals>
+       </features>
+
+The ``<features>`` element can be used to choose a large number of features that will be discussed later, but here we have only used it to define a ``<globals>`` element.  This element contains a block of text with ``<![CDATA[`` at the start and ``]]>`` at the end.  These 'CDATA' blocks  are used in several places in an XMDS script, and define a block of text that will be pasted directly into the generated C-code.  They must therefore be formatted in legal C-syntax, and any legal C-synta [...]
+
+The next element is the essential ``<geometry>`` element.
+
+.. code-block:: xpdeint
+    
+      <geometry>
+        <propagation_dimension> t </propagation_dimension>
+      </geometry>
+
+This element is used to define all the dimensions in the problem.  We only require the time dimension, which we are labelling 't', so this is a trivial example.  We will discuss transverse dimensions in more detail in the next worked example (:ref:`NonLinearSchrodingerEquation`), where we deal with the integration of a partial differential equation rather than ordinary differential equations.
+
+Next, we have the ``<vector>`` element.
+
+.. code-block:: xpdeint
+    
+      <vector name="position" type="real">
+        <components>
+          x y z
+        </components>
+        <initialisation>
+          <![CDATA[
+          x = y = z = 1.0;
+          ]]>
+        </initialisation>
+      </vector>
+
+We can define multiple vectors, but here we only need the variables that we wish to integrate.  We named this vector "position", as it defines the position in phase space.  These variables are real-valued (as opposed to, say, complex numbers), so we define ``type="real"``.  The ``<components>`` element defines the names of the elements of this vector, which we have called 'x', 'y' and 'z'.  Finally, we provide the initial values of the variables in a CDATA block within the ``<initialisat [...]
+
+Now we come to the heart of the simulation, where we define the evolution of our vector.  This evolution is held in the ``<sequence>`` element, which contains an ordered sequence of actions upon any defined vectors.  Vectors can be altered with a ``<filter>`` element, or integrated in the propagation dimension with an ``<integrate>`` element.
+
+.. code-block:: xpdeint
+    
+      <sequence>
+        <integrate algorithm="ARK89" interval="20.0" tolerance="1e-7">
+          <samples>5000</samples>
+          <operators>
+            <integration_vectors>position</integration_vectors>
+            <![CDATA[
+            dx_dt = sigma*(y-x);
+            dy_dt = r*x - y - x*z;
+            dz_dt = x*y - b*z;
+            ]]>
+          </operators>
+        </integrate>
+      </sequence>
+
+Here our sequence consists of a single ``<integrate>`` element.  It contains several important pieces of information.  At the heart, the ``<operators>`` element contains the equations of motion as described above, written in a very human-readable fashion.  It also contains an ``<integration_vectors>`` element, which defines which vectors are used in this integrate block.  We have only one vector defined in this simulation, so it is a trivial choice here.  
+
+All integrate blocks must define which algorithm is to be used - in this case the 8th (embedded 9th) order adaptive Runge-Kutta method, called "ARK89".  The details of different algorithms will be described later (FIXME: Link!), but for now all we need to know is that this algorithm requires a tolerance, and that smaller means more accurate, so we'll make it :math:`10^{-7}` by setting ``tolerance="1.0e-7"``.  Finally, any integration will proceed a certain length in the propagation dimen [...]
+
+The ``<samples>`` element says that the values of the output groups will be sampled 5000 times during this interval.  The nature of the output is defined in the last element in the simulation: the ``<output>`` element.
+
+.. code-block:: xpdeint
+    
+  <output format="hdf5" filename="lorenz.xsil">
+    <sampling_group initial_sample="yes">
+      <moments>xR yR zR</moments>
+      <dependencies>position</dependencies>
+      <![CDATA[
+        xR = x;
+        yR = y;
+        zR = z;
+      ]]>
+    </sampling_group>
+  </output>
+
+The two top-level arguments in the ``<output>`` element are "format" and "filename".  Here we define the output filename, although it would have defaulted to this value.  We also choose the format to be HDF5, which is why the simulation resulted in the binary file "lorenz.h5" as well as "lorenz.xsil".  If we had instead said ``format="ascii"``, then all of the output data would have been written in text form in "lorenz.xsil".
+
+The ``<output>`` element can contain any non-zero number of ``<sampling_group>`` elements, which specify the entire output of the program.  They allow for subsampling, integration of some or all of the transverse dimensions, and/or conversion of some dimensions into Fourier space, but these will be described in more detail in the following examples.  We have a ``<dependencies>`` element that specifies which vectors are needed for this output.  We specify the list of output variables with [...]
+
+And that's it.  This is quite a large framework to integrate three coupled ordinary differential equations, but the advantage of using XMDS2 is that vastly more complicated simulations can be performed without increasing the length or complexity of the XMDS2 script significantly.  The :ref:`WorkedExamples` section will provide more complicated examples with stochastic equations and partial differential equations.  If you are moved to solve your own problem using XMDS2, then perhaps the m [...]
diff --git a/admin/userdoc-source/upgrade.rst b/admin/userdoc-source/upgrade.rst
new file mode 100644
index 0000000..23af03c
--- /dev/null
+++ b/admin/userdoc-source/upgrade.rst
@@ -0,0 +1,10 @@
+.. _UpgradeFromXMDS1:
+
+Upgrading From XMDS 1.X
+=======================
+
+While **XMDS2** is a complete rewrite of the **XMDS** project, much of the syntax has remained very similar.  That said, your code will have to be rewritten as an XMDS2 program.  We recommend that you work through the :ref:`QuickStartTutorial` and perhaps the :ref:`WorkedExamples` sections, and then you should be good to go.
+
+The main news when switching to XMDS2 is the long list of new things you can do.  If it's an initial value problem, XMDS2 has a good chance of being able to solve it.
+
+We have made the decision to call the executables "xmds2" and "xsil2graphics2" so that you can keep using your old installation in parallel with the new version.
\ No newline at end of file
diff --git a/admin/userdoc-source/worked_examples.rst b/admin/userdoc-source/worked_examples.rst
new file mode 100644
index 0000000..243e668
--- /dev/null
+++ b/admin/userdoc-source/worked_examples.rst
@@ -0,0 +1,1359 @@
+.. _WorkedExamples:
+
+Worked Examples
+===============
+
+One of the best ways to learn XMDS2 is to see several illustrative examples.  Here are a set of example scripts and explanations of the code, which will be a good way to get started.  As an instructional aid, they are meant to be read sequentially, but the adventurous could try starting with one that looked like a simulation they wanted to run, and adapt for their own purposes.
+
+   :ref:`NonLinearSchrodingerEquation` (partial differential equation)
+   
+   :ref:`Kubo` (stochastic differential equations)
+
+   :ref:`Fibre` (stochastic partial differential equation using parallel processing)
+
+   :ref:`IntegerDimensionExample` (integer dimensions)
+
+   :ref:`WignerArguments` (two dimensional PDE using parallel processing, passing arguments in at run time)
+
+   :ref:`GroundStateBEC` (PDE with continual renormalisation - computed vectors, filters, breakpoints)
+
+   :ref:`HermiteGaussGroundStateBEC` (Hermite-Gaussian basis)
+   
+   :ref:`2DMultistateSE` (combined integer and continuous dimensions with matrix multiplication, aliases)
+
+All of these scripts are available in the included "examples" folder, along with more examples that demonstrate other tricks.  Together, they provide starting points for a huge range of different simulations.
+
+.. _NonLinearSchrodingerEquation:
+
+The nonlinear Schrödinger equation
+----------------------------------
+
+This worked example will show a range of new features that can be used in an **XMDS2** script, and we will also examine our first partial differential equation.  We will take the one dimensional nonlinear Schrödinger equation, which is a common nonlinear wave equation.  The equation describing this problem is:
+
+.. math::
+    \frac{\partial \phi}{\partial \xi} = \frac{i}{2}\frac{\partial^2 \phi}{\partial \tau^2} - \Gamma(\tau)\phi+i|\phi|^2 \phi
+
+where :math:`\phi` is a complex-valued field, and :math:`\Gamma(\tau)` is a :math:`\tau`-dependent damping term.  Let us look at an XMDS2 script that integrates this equation, and then examine it in detail.
+
+.. code-block:: xpdeint
+
+    <simulation xmds-version="2">
+      <name>nlse</name>
+
+      <author>Joe Hope</author>
+      <description>
+        The nonlinear Schrodinger equation in one dimension, 
+        which is a simple partial differential equation.  
+        We introduce several new features in this script.
+      </description>
+
+      <features>
+          <benchmark />
+          <bing />
+          <fftw plan="patient" />
+          <openmp />
+          <auto_vectorise />
+          <globals>
+              <![CDATA[
+              const double energy = 4;
+              const double vel = 0.3;
+              const double hwhm = 1.0;
+              ]]>
+           </globals>
+         </features>
+
+      <geometry>
+          <propagation_dimension> xi </propagation_dimension>
+          <transverse_dimensions>
+            <dimension name="tau" lattice="128"  domain="(-6, 6)" />
+          </transverse_dimensions>
+       </geometry>
+
+      <vector name="wavefunction" type="complex" dimensions="tau">
+        <components> phi </components>
+        <initialisation>
+          <![CDATA[
+          const double w0 = hwhm*sqrt(2/log(2));
+          const double amp = sqrt(energy/w0/sqrt(M_PI/2));
+          phi = amp*exp(-tau*tau/w0/w0)*exp(i*vel*tau);
+          ]]>
+        </initialisation>
+      </vector>
+
+      <vector name="dampingVector" type="real">
+        <components> Gamma </components>
+        <initialisation>
+          <![CDATA[
+          Gamma=1.0*(1-exp(-pow(tau*tau/4.0/4.0,10)));
+          ]]>
+        </initialisation>
+      </vector>
+
+      <sequence>
+        <integrate algorithm="ARK45" interval="20.0" tolerance="1e-7">
+          <samples>10 100 10</samples>
+          <operators>
+            <integration_vectors>wavefunction</integration_vectors>
+            <operator kind="ex" constant="yes">
+              <operator_names>Ltt</operator_names>
+              <![CDATA[
+                Ltt = -i*ktau*ktau*0.5;
+              ]]>
+            </operator>
+            <![CDATA[
+            dphi_dxi = Ltt[phi] - phi*Gamma + i*mod2(phi)*phi;
+            ]]>
+            <dependencies>dampingVector</dependencies>
+          </operators>
+        </integrate>
+      </sequence>
+
+      <output>
+        <sampling_group basis="tau" initial_sample="yes">
+          <moments>density</moments>
+          <dependencies>wavefunction</dependencies>
+          <![CDATA[
+            density = mod2(phi);
+          ]]>
+        </sampling_group>
+        
+        <sampling_group basis="tau(0)" initial_sample="yes">
+          <moments>normalisation</moments>
+          <dependencies>wavefunction</dependencies>
+          <![CDATA[
+            normalisation = mod2(phi);
+          ]]>
+        </sampling_group>
+        
+        <sampling_group basis="ktau(32)" initial_sample="yes">
+          <moments>densityK</moments>
+          <dependencies>wavefunction</dependencies>
+          <![CDATA[
+            densityK = mod2(phi);
+          ]]>
+        </sampling_group>
+
+      </output>
+    </simulation>
+
+Let us examine the new items in the ``<features>`` element that we have demonstrated here.  The existence of the ``<benchmark>`` element causes the simulation to be timed.  The ``<bing>`` element causes the computer to make a sound upon the conclusion of the simulation.  The ``<fftw>`` element is used to pass options to the `FFTW libraries for fast Fourier transforms <http://fftw.org>`_, which are needed to do spectral derivatives for the partial differential equation.  Here we used the  [...]
+
+Finally, we use two tags to make the simulation run faster.  The ``<auto_vectorise>`` element switches on several loop optimisations that exist in later versions of the GCC compiler.  The ``<openmp>`` element turns on threaded parallel processing using the OpenMP standard where possible.  These options are not activated by default as they only exist on certain compilers.  If your code compiles with them on, then they are recommended.
+
+Let us examine the ``<geometry>`` element.
+
+.. code-block:: xpdeint
+
+      <geometry>
+          <propagation_dimension> xi </propagation_dimension>
+          <transverse_dimensions>
+            <dimension name="tau" lattice="128"  domain="(-6, 6)" />
+          </transverse_dimensions>
+       </geometry>
+
+This is the first example that includes a transverse dimension.  We have only one dimension, and we have labelled it "tau".  It is a continuous dimension, but only defined on a grid containing 128 points (defined with the lattice variable), and on a domain from -6 to 6.  The default is that transforms in continuous dimensions are fast Fourier transforms, which means that this dimension is effectively defined on a loop, and the "tau=-6" and "tau=6" positions are in fact the same.  Other t [...]
+
+Two vector elements have been defined in this simulation.  One defines the complex-valued wavefunction "phi" that we wish to evolve.  We define the transverse dimensions over which this vector is defined by the ``dimensions`` tag in the description.  By default, it is defined over all of the transverse dimensions in the ``<geometry>`` element, so even though we have omitted this tag for the second vector, it also assumes that the vector is defined over all of tau.  
+
+The second vector element contains the component "Gamma" which is a function of the transverse variable tau, as specified in the equation of motion for the field.  This second vector could have been avoided in two ways.  First, the function could have been written explicitly in the integrate block where it is required, but calculating it once and then recalling it from memory is far more efficient.  Second, it could have been included in the "wavefunction" vector as another component, bu [...]
+
+The ``<integrate>`` element for a partial differential equation has some new features:
+
+.. code-block:: xpdeint
+
+        <integrate algorithm="ARK45" interval="20.0" tolerance="1e-7">
+          <samples>10 100 10</samples>
+          <operators>
+            <integration_vectors>wavefunction</integration_vectors>
+            <operator kind="ex" constant="yes">
+              <operator_names>Ltt</operator_names>
+              <![CDATA[
+                Ltt = -i*ktau*ktau*0.5;
+              ]]>
+            </operator>
+            <![CDATA[
+            dphi_dxi = Ltt[phi] - phi*Gamma + i*mod2(phi)*phi;
+            ]]>
+            <dependencies>dampingVector</dependencies>
+          </operators>
+        </integrate>
+
+There are some trivial changes from the tutorial script, such as the fact that we are using the ARK45 algorithm rather than ARK89.  Higher order algorithms are often better, but not always.  Also, since this script has multiple output groups, we have to specify how many times each of these output groups are sampled in the ``<samples>`` element, so there are three numbers there.  Besides the vectors that are to be integrated, we also specify that we want to use the vector "dampingVector"  [...]
+
+The equation of motion as written in the CDATA block looks almost identical to our desired equation of motion, except for the term based on the second derivative, which introduces an important new concept.  Inside the ``<operators>`` element, we can define any number of operators.  Operators are used to define functions in the transformed space of each dimension, which in this case is Fourier space.  The derivative of a function is equivalent to multiplying by :math:`i*k` in Fourier spac [...]
+
+Operators can be explicit (``kind="ex"``) or in the interaction picture (``kind="ip"``).  The interaction picture can be more efficient, but it restricts the possible syntax of the equation of motion.  Safe utilisation of interaction picture operators will be described later, but for now let us emphasise that **explicit operators should be used** unless the user is clear what they are doing.  That said, **XMDS2** will generate an error if the user tries to use interaction picture operato [...]
+
+The output of a partial differential equation offers more possibilities than an ordinary differential equation, and we examine some in this example.
+
+For vectors with transverse dimensions, we can sample functions of the vectors on the full lattice or a subset of the points.  In the ``<sampling_group>`` element, we must add a string called "basis" that determines the space in which each transverse dimension is to be sampled, optionally followed by the number of points to be sampled in parentheses.  If the number of points is not specified, it will default to a complete sampling of all points in that dimension.  If a non-zero number of [...]
+
+.. code-block:: xpdeint
+
+      <sampling_group basis="tau" initial_sample="yes">
+        <moments>density</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          density = mod2(phi);
+        ]]>
+      </sampling_group>
+
+The first output group samples the mod square of the vector "phi" over the full lattice of 128 points.
+
+If the lattice parameter is set to zero points, then the corresponding dimension is integrated.
+
+.. code-block:: xpdeint
+
+       <sampling_group basis="tau(0)" initial_sample="yes">
+         <moments>normalisation</moments>
+         <dependencies>wavefunction</dependencies>
+         <![CDATA[
+           normalisation = mod2(phi);
+         ]]>
+       </sampling_group>
+
+This second output group samples the normalisation of the wavefunction :math:`\int d\tau |\phi(\tau)|^2` over the domain of :math:`\tau`.  This output requires only a single real number per sample, so in the integrate element we have chosen to sample it many more times than the vectors themselves.
+
+Finally, functions of the vectors can be sampled with their dimensions in Fourier space.
+
+.. code-block:: xpdeint
+
+        <sampling_group basis="ktau(32)" initial_sample="yes">
+          <moments>densityK</moments>
+          <dependencies>wavefunction</dependencies>
+          <![CDATA[
+            densityK = mod2(phi);
+          ]]>
+        </sampling_group>
+
+The final output group above samples the mod square of the Fourier-space wavefunction phi on a sample of 32 points.
+
+
+.. _Kubo:
+
+Kubo Oscillator
+---------------
+
+This example demonstrates the integration of a stochastic differential equation.  We examine the Kubo oscillator, which is a complex variable whose phase is evolving according to a Wiener noise.  In a suitable rotating frame, the equation of motion for the variable is
+
+.. math::
+    \frac{dz}{dt} = i z \;\eta
+
+where :math:`\eta(t)` is the Wiener differential, and we interpret this as a Stratonovich equation.  In other common notation, this is sometimes written:
+
+.. math::
+    dz = i z \;\circ dW
+
+Most algorithms employed by XMDS require the equations to be input in the Stratonovich form.  Ito differential equations can always be transformed into Stratonovich euqations, and in this case the difference is equivalent to the choice of rotating frame.  This equation is solved by the following XMDS2 script:
+
+.. code-block:: xpdeint
+
+    <simulation xmds-version="2">
+      <name>kubo</name>
+      <author>Graham Dennis and Joe Hope</author>
+      <description>
+        Example Kubo oscillator simulation
+      </description>
+  
+      <geometry>
+        <propagation_dimension> t </propagation_dimension>
+      </geometry>
+  
+      <driver name="multi-path" paths="10000" />
+  
+      <features>
+        <error_check />
+        <benchmark />
+      </features>
+
+      <noise_vector name="drivingNoise" dimensions="" kind="wiener" type="real" method="dsfmt" seed="314 159 276">
+        <components>eta</components>
+      </noise_vector>
+  
+      <vector name="main" type="complex">
+        <components> z </components>
+        <initialisation>
+          <![CDATA[
+            z = 1.0;
+          ]]>
+        </initialisation>
+      </vector>
+  
+      <sequence>
+        <integrate algorithm="SI" interval="10" steps="1000">
+          <samples>100</samples>
+          <operators>
+            <integration_vectors>main</integration_vectors>
+            <dependencies>drivingNoise</dependencies>
+            <![CDATA[
+              dz_dt = i*z*eta;
+            ]]>
+          </operators>
+        </integrate>
+      </sequence>
+
+      <output>
+        <sampling_group initial_sample="yes">
+          <moments>zR zI</moments>
+          <dependencies>main</dependencies>
+          <![CDATA[
+            zR = z.Re();
+            zI = z.Im();
+          ]]>
+        </sampling_group>
+      </output>
+    </simulation>
+
+The first new item in this script is the ``<driver>`` element.  This element enables us to change top level management of the simulation.  Without this element, XMDS2 will integrate the stochastic equation as described.  With this element and the option ``name="multi-path"``, it will integrate it multiple times, using different random numbers each time.  The output will then contain the mean values and standard errors of your output variables.  The number of integrations included in the  [...]
+
+In the ``<features>`` element we have included the ``<error_check>`` element.  This performs the integration first with the specified number of steps (or with the specified tolerance), and then with twice the number of steps (or equivalently reduced tolerance).  The output then includes the difference between the output variables on the coarse and the fine grids as the 'error' in the output variables.  This error is particularly useful for stochastic integrations, where algorithms with a [...]
+
+We define the stochastic elements in a simulation with the ``<noise_vector>`` element.  
+
+.. code-block:: xpdeint
+
+    <noise_vector name="drivingNoise" dimensions="" kind="wiener" type="real" method="dsfmt" seed="314 159 276">
+     <components>eta</components>
+    </noise_vector>
+  
+This defines a vector that is used like any other, but it will be randomly generated with particular statistics and characteristics rather than initialised.  The name, dimensions and type tags are defined just as for normal vectors.  The names of the components are also defined in the same way.  The noise is defined as a Wiener noise here (``kind = "wiener"``), which is a zero-mean Gaussian random noise with an average variance equal to the discretisation volume (here it is just the step [...]
+
+We may also define a noise method to choose a non-default pseudo random number generator, and a seed for the random number generator.  Using a seed can be very useful when debugging the behaviour of a simulation, and many compilers have pseudo-random number generators that are superior to the default option (posix).
+
+The integrate block is using the semi-implicit algorithm (``algorithm="SI"``), which is a good default choice for stochastic problems, even though it is only second order convergent for deterministic equations.  More will be said about algorithm choice later, but for now we should note that adaptive algorithms based on Runge-Kutta methods are not guaranteed to converge safely for stochastic equations.  This can be particularly deceptive as they often succeed, particularly for almost any  [...]
+
+We include elements from the noise vector in the equation of motion just as we do for any other vector.  The default SI and Runge-Kutta algorithms converge to the *Stratonovich* integral.  Ito stochastic equations can be converted to Stratonovich form and vice versa.
+
+Executing the generated program 'kubo' gives slightly different output due to the "multi-path" driver.
+
+.. code-block:: none
+
+            $ ./kubo
+            Beginning full step integration ...
+            Starting path 1
+            Starting path 2
+
+            ... many lines omitted ...
+
+            Starting path 9999
+            Starting path 10000
+            Beginning half step integration ...
+            Starting path 1
+            Starting path 2
+
+            ... many lines omitted ...
+
+            Starting path 9999
+            Starting path 10000
+            Generating output for kubo
+            Maximum step error in moment group 1 was 4.942549e-04
+            Time elapsed for simulation is: 2.71 seconds
+
+The maximum step error in each moment group is given in absolute terms.  This is the largest difference between the full step integration and the half step integration.  While a single path might be very stochastic:
+
+.. figure:: images/kuboSingle.*
+    :align: center
+    
+    The mean value of the real and imaginary components of the z variable for a single path of the simulation.
+    
+The average over multiple paths can be increasingly smooth.  
+
+.. figure:: images/kubo10000.*
+    :align: center
+
+    The mean and standard error of the z variable averaged over 10000 paths, as given by this simulation.  It agrees within the standard error with the expected result of :math:`\exp(-t/2)`.
+
+
+.. _Fibre:
+
+Fibre Noise
+-----------
+
+This simulation is a stochastic partial differential equation, in which a one-dimensional damped field is subject to a complex noise. This script can be found in ``examples/fibre.xmds``.
+
+.. math::
+    \frac{\partial \psi}{\partial t} = -i \frac{\partial^2 \psi}{\partial x^2} -\gamma \psi+\beta \frac{1}{\sqrt{2}}\left(\eta_1(x)+i\eta_2(x)\right)
+    
+where the noise terms :math:`\eta_j(x,t)` are Wiener differentials and the equation is interpreted as a Stratonovich differential equation.  On a finite grid, these increments have variance :math:`\frac{1}{\Delta x \Delta t}`.
+
+.. code-block:: xpdeint
+    
+    <simulation xmds-version="2">
+      <name>fibre</name>
+      <author>Joe Hope and Graham Dennis</author>
+      <description>
+        Example fibre noise simulation
+      </description>
+  
+      <geometry>
+        <propagation_dimension> t </propagation_dimension>
+        <transverse_dimensions>
+          <dimension name="x" lattice="64"  domain="(-5, 5)" />
+        </transverse_dimensions>
+      </geometry>
+  
+      <driver name="mpi-multi-path" paths="8" />
+  
+      <features>
+        <auto_vectorise />
+        <benchmark />
+        <error_check />
+        <globals>
+          <![CDATA[
+          const real ggamma = 1.0;
+          const real beta = sqrt(M_PI*ggamma/10.0);
+          ]]>
+        </globals>
+      </features>
+  
+      <noise_vector name="drivingNoise" dimensions="x" kind="wiener" type="complex" method="dsfmt" seed="314 159 276">
+        <components>Eta</components>
+      </noise_vector>
+  
+      <vector name="main" initial_basis="x" type="complex">
+        <components>phi</components>
+        <initialisation>
+          <![CDATA[
+            phi = 0.0;
+          ]]>
+        </initialisation>
+      </vector>
+  
+      <sequence>
+        <integrate algorithm="SI" iterations="3" interval="2.5" steps="200000">
+          <samples>50</samples>
+          <operators>
+            <operator kind="ex" constant="yes">
+              <operator_names>L</operator_names>
+              <![CDATA[
+                L = -i*kx*kx;
+              ]]>
+            </operator>
+            <dependencies>drivingNoise</dependencies>
+            <integration_vectors>main</integration_vectors>
+            <![CDATA[
+              dphi_dt = L[phi] - ggamma*phi + beta*Eta;
+            ]]>
+          </operators>
+        </integrate>
+      </sequence>
+  
+      <output>
+        <sampling_group basis="kx" initial_sample="yes">
+          <moments>pow_dens</moments>
+          <dependencies>main</dependencies>
+          <![CDATA[
+            pow_dens = mod2(phi);
+          ]]>
+        </sampling_group>
+      </output>
+    </simulation>
+
+Note that the noise vector used in this example is complex-valued, and has the argument ``dimensions="x"`` to define it as a field of delta-correlated noises along the x-dimension.
+
+This simulation demonstrates the ease with which XMDS2 can be used in a parallel processing environment.  Instead of using the stochastic driver "multi-path", we simply replace it with "mpi-multi-path".  This instructs XMDS2 to write a parallel version of the program based on the widespread `MPI standard <http://www.open-mpi.org/>`_.  This protocol allows multiple processors or clusters of computers to work simultaneously on the same problem.  Free open source libraries implementing this [...]
+
+Executing this program is slightly different with the MPI option.  The details can change between MPI implementations, but as an example:
+
+.. code-block:: none
+
+        $xmds2 fibre.xmds
+        xmds2 version 2.1 "Happy Mollusc" (r2543)
+        Copyright 2000-2012 Graham Dennis, Joseph Hope, Mattias Johnsson
+                            and the xmds team
+        Generating source code...
+        ... done
+        Compiling simulation...
+        ... done. Type './fibre' to run.
+
+Note that different compile options (and potentially a different compiler) are used by XMDS2, but this is transparent to the user.  MPI simulations will have to be run using syntax that will depend on the MPI implementation.  Here we show the version based on the popular open source `Open-MPI <http://www.open-mpi.org/>`_ implementation.
+
+.. code-block:: none
+
+    $ mpirun -np 4 ./fibre
+    Found enlightenment... (Importing wisdom)
+    Planning for x <---> kx transform... done.
+    Beginning full step integration ...
+    Rank[0]: Starting path 1
+    Rank[1]: Starting path 2
+    Rank[2]: Starting path 3
+    Rank[3]: Starting path 4
+    Rank[3]: Starting path 8
+    Rank[0]: Starting path 5
+    Rank[1]: Starting path 6
+    Rank[2]: Starting path 7
+    Rank[3]: Starting path 4
+    Beginning half step integration ...
+    Rank[0]: Starting path 1
+    Rank[2]: Starting path 3
+    Rank[1]: Starting path 2
+    Rank[3]: Starting path 8
+    Rank[0]: Starting path 5
+    Rank[2]: Starting path 7
+    Rank[1]: Starting path 6
+    Generating output for fibre
+    Maximum step error in moment group 1 was 4.893437e-04
+    Time elapsed for simulation is: 20.99 seconds
+    
+In this example we used four processors.  The different processors are labelled by their "Rank", starting at zero.  Because the processors are working independently, the output from the different processors can come in a randomised order.  In the end, however, the .xsil and data files are constructed identically to the single processor outputs.
+
+The analytic solution to the stochastic averages of this equation is given by
+
+.. math::
+    \langle |\psi(k,t)|^2 \rangle = \exp(-2\gamma t)|\psi(k,0)|^2 +\frac{\beta^2 L_x}{4\pi \gamma} \left(1-\exp(-2\gamma t)\right)
+    
+where :math:`L_x` is the length of the x domain.  We see that a single integration of these equations is quite chaotic:
+
+.. figure:: images/fibreSingle.*
+    :align: center
+    
+    The momentum space density of the field as a function of time for a single path realisation.
+
+while an average of 1024 paths (change ``paths="8"`` to ``paths="1024"`` in the ``<driver>`` element) converges nicely to the analytic solution:
+
+.. figure:: images/fibre1024.*
+    :align: center
+    
+    The momentum space density of the field as a function of time for an average of 1024 paths.
+
+
+
+.. _IntegerDimensionExample:
+
+Integer Dimensions
+------------------
+
+This example shows how to handle systems with integer-valued transverse dimensions.  We will integrate the following set of equations
+
+.. math::
+    \frac{dx_j}{dt} = x_j \left(x_{j-1}-x_{j+1}\right)
+
+where :math:`x_j` are complex-valued variables defined on a ring, such that :math:`j\in \{0,j_{max}\}` and the :math:`x_{j_{max}+1}` variable is identified with the variable :math:`x_{0}`, and the variable :math:`x_{-1}` is identified with the variable :math:`x_{j_{max}}`.
+
+.. code-block:: xpdeint
+
+    <simulation xmds-version="2">
+      <name>integer_dimensions</name>
+      <author>Graham Dennis</author>
+      <description>
+        XMDS2 script to test integer dimensions.
+      </description>
+
+      <features>
+        <benchmark />
+        <error_check />
+        <bing />
+        <diagnostics /> <!-- This will make sure that all nonlocal accesses of dimensions are safe -->
+      </features>
+
+      <geometry>
+        <propagation_dimension> t </propagation_dimension>
+        <transverse_dimensions>
+          <dimension name="j" type="integer" lattice="5" domain="(0,4)" />
+        </transverse_dimensions>
+      </geometry>
+
+      <vector name="main" type="complex">
+        <components> x </components>
+        <initialisation>
+          <![CDATA[
+          x = 1.0e-3;
+          x(j => 0) = 1.0;
+          ]]>
+        </initialisation>
+      </vector>
+
+      <sequence>
+        <integrate algorithm="ARK45" interval="60" steps="25000" tolerance="1.0e-9">
+          <samples>1000</samples>
+          <operators>
+            <integration_vectors>main</integration_vectors>
+            <![CDATA[
+            long j_minus_one = (j-1) % _lattice_j;
+            if (j_minus_one < 0)
+              j_minus_one += _lattice_j;
+            long j_plus_one  = (j+1) % _lattice_j;
+            dx_dt(j => j) = x(j => j)*(x(j => j_minus_one) - x(j => j_plus_one));
+            ]]>
+          </operators>
+        </integrate>
+      </sequence>
+
+      <output>
+        <sampling_group basis="j" initial_sample="yes">
+          <moments>xR</moments>
+          <dependencies>main</dependencies>
+          <![CDATA[
+            xR = x.Re();
+          ]]>
+        </sampling_group>
+      </output>
+    </simulation>
+
+The first extra feature we have used in this script is the ``<diagnostics>`` element.  It performs run-time checking that our generated code does not accidentally attempt to access a part of our vector that does not exist.  Removing this tag will increase the speed of the simulation, but its presence helps catch coding errors.  
+
+The simulation defines a vector with a single transverse dimension labelled "j", of type "integer" ("int" and "long" can also be used as synonyms for "integer").  In the absence of an explicit type, the dimension is assumed to be real-valued.  The dimension has a "domain" argument as normal, defining the minimum and maximum values of the dimension's range.  The lattice element, if specified, is used as a check on the size of the domain, and will create an error if the two do not match.
+
+Integer-valued dimensions can be called non-locally.  Real-valued dimensions are typically coupled non-locally only through local operations in the transformed space of the dimension, but can be called non-locally in certain other situations as described in :ref:`the reference<ReferencingNonlocal>`.  The syntax for calling integer dimensions non-locally can be seen in the initialisation CDATA block:
+
+.. code-block:: xpdeint
+
+          x = 1.0e-3;
+          x(j => 0) = 1.0;
+
+where the syntax ``x(j => 0)`` is used to reference the variable :math:`x_0` directly.  We see a more elaborate example in the integrate CDATA block:
+
+.. code-block:: xpdeint
+
+            dx_dt(j => j) = x(j => j)*(x(j => j_minus_one) - x(j => j_plus_one));
+
+where the vector "x" is called using locally defined variables.  This syntax is chosen so that multiple dimensions can be addressed non-locally with minimal possibility for confusion.
+
+
+
+
+.. _WignerArguments:
+
+Wigner Function
+---------------
+
+This example integrates the two-dimensional partial differential equation
+
+.. math::
+    \begin{split}
+    \frac{\partial W}{\partial t} &= \Bigg[ \left(\omega + \frac{U_{int}}{\hbar}\left(x^2+y^2-1\right)\right) \left(x \frac{\partial}{\partial y} 
+    - y \frac{\partial}{\partial x}\right)\\
+    &\phantom{=\Bigg[} - \frac{U_{int}}{16 \hbar}\left(x\left(\frac{\partial^3}{\partial x^2 \partial y}
+    +\frac{\partial^3}{\partial y^3}\right)-y\left(\frac{\partial^3}{\partial y^2 \partial x}+\frac{\partial^3}{\partial x^3}\right)\right)\Bigg]W(x,y,t)
+    \end{split}
+
+with the added restriction that the derivative is forced to zero outside a certain radius.  This extra condition helps maintain the long-term stability of the integration. The script can be found in ``examples/wigner_arguments_mpi.xmds`` under your XMDS2 installation directory.
+
+.. code-block:: xpdeint
+
+    <simulation xmds-version="2">
+      <name>wigner</name>
+      <author>Graham Dennis and Joe Hope</author>
+      <description>
+        Simulation of the Wigner function for an anharmonic oscillator with the initial state
+        being a coherent state.
+      </description>
+      <features>
+        <benchmark />
+        <globals>
+          <![CDATA[
+            real Uint_hbar_on16;
+          ]]>
+        </globals>
+        <arguments>
+          <argument name="omega" type="real" default_value="0.0" />
+          <argument name="alpha_0"     type="real" default_value="3.0" />
+          <argument name="absorb"     type="real" default_value="8.0" />
+          <argument name="width" type="real" default_value="0.3" />
+          <argument name="Uint_hbar" type="real" default_value="1.0" />
+          <![CDATA[
+            /* derived constants */
+            Uint_hbar_on16 = Uint_hbar/16.0;
+          ]]>
+        </arguments>
+        <bing />
+        <fftw plan="patient" />
+        <openmp />
+      </features>
+
+      <driver name="distributed-mpi" />
+
+      <geometry>
+        <propagation_dimension> t </propagation_dimension>
+        <transverse_dimensions>
+          <dimension name="x" lattice="128"  domain="(-6, 6)" />
+          <dimension name="y" lattice="128"  domain="(-6, 6)" />
+        </transverse_dimensions>
+      </geometry>
+
+      <vector name="main" initial_basis="x y" type="complex">
+        <components> W </components>
+        <initialisation>
+          <![CDATA[
+            W = 2.0/M_PI * exp(-2.0*(y*y + (x-alpha_0)*(x-alpha_0)));
+          ]]>
+        </initialisation>
+      </vector>
+
+      <vector name="dampConstants" initial_basis="x y" type="real">
+        <components>damping</components>
+        <initialisation>
+          <![CDATA[
+          if (sqrt(x*x + y*y) > _max_x-width)
+            damping = 0.0;
+          else
+            damping = 1.0;
+          ]]>
+        </initialisation>
+      </vector>
+
+      <sequence>
+        <integrate algorithm="ARK89" tolerance="1e-7" interval="7.0e-4" steps="100000">
+          <samples>50</samples>
+          <operators>
+            <operator kind="ex" constant="yes">
+              <operator_names>Lx Ly Lxxx Lxxy Lxyy Lyyy</operator_names>
+              <![CDATA[
+                Lx = i*kx;
+                Ly = i*ky;
+                Lxxx = -i*kx*kx*kx;
+                Lxxy = -i*kx*kx*ky;
+                Lxyy = -i*kx*ky*ky;
+                Lyyy = -i*ky*ky*ky;
+              ]]>
+            </operator>
+            <integration_vectors>main</integration_vectors>
+            <dependencies>dampConstants</dependencies>
+            <![CDATA[
+            real rotation = omega + Uint_hbar*(-1.0 + x*x + y*y);
+
+            dW_dt = damping * ( rotation * (x*Ly[W] - y*Lx[W]) 
+                        - Uint_hbar_on16*( x*(Lxxy[W] + Lyyy[W]) - y*(Lxyy[W] + Lxxx[W]) )
+                    );
+            ]]>
+          </operators>
+        </integrate>
+      </sequence>
+
+      <output>
+        <sampling_group basis="x y" initial_sample="yes">
+          <moments>WR WI</moments>
+          <dependencies>main</dependencies>
+          <![CDATA[
+            _SAMPLE_COMPLEX(W);
+          ]]>
+        </sampling_group>
+      </output>
+    </simulation>
+
+This example demonstrates two new features of XMDS2.  The first is the use of parallel processing for a deterministic problem.  The FFTW library only allows MPI processing of multidimensional vectors.  For multidimensional simulations, the generated program can be parallelised simply by adding the ``name="distributed-mpi"`` argument to the ``<driver>`` element.  
+
+.. code-block:: xpdeint
+
+    $ xmds2 wigner_argument_mpi.xmds 
+    xmds2 version 2.1 "Happy Mollusc" (r2680)
+    Copyright 2000-2012 Graham Dennis, Joseph Hope, Mattias Johnsson
+                        and the xmds team
+    Generating source code...
+    ... done
+    Compiling simulation...
+    ... done. Type './wigner' to run.
+        
+To use multiple processors, the final program is then called using the (implementation specific) MPI wrapper:
+
+.. code-block:: xpdeint
+
+    $ mpirun -np 2 ./wigner
+    Planning for (distributed x, y) <---> (distributed ky, kx) transform... done.
+    Planning for (distributed x, y) <---> (distributed ky, kx) transform... done.
+    Sampled field (for moment group #1) at t = 0.000000e+00
+    Current timestep: 5.908361e-06
+    Sampled field (for moment group #1) at t = 1.400000e-05
+    Current timestep: 4.543131e-06
+    
+    ...
+
+The possible acceleration achievable when parallelising a given simulation depends on a great many things including available memory and cache.  As a general rule, it will improve as the simulation size gets larger, but the easiest way to find out is to test.  The optimum speed up is obviously proportional to the number of available processing cores.
+
+The second new feature in this simulation is the ``<arguments>`` element in the ``<features>`` block.  This is a way of specifying global variables with a given type that can then be input at run time.  The variables are specified in a self explanatory way
+
+.. code-block:: xpdeint
+
+        <arguments>
+          <argument name="omega" type="real" default_value="0.0" />
+            ...
+          <argument name="Uint_hbar" type="real" default_value="1.0" />
+        </arguments>
+        
+where the "default_value" is used as the valuable of the variable if no arguments are given.  In the absence of the generating script, the program can document its options with the ``--help`` argument:
+
+.. code-block:: none
+
+    $ ./wigner --help
+    Usage: wigner --omega <real> --alpha_0 <real> --absorb <real> --width <real> --Uint_hbar <real>
+
+    Details:
+    Option		Type		Default value
+    -o,  --omega	real 		0.0
+    -a,  --alpha_0	real 		3.0
+    -b,  --absorb	real 		8.0
+    -w,  --width	real 		0.3
+    -U,  --Uint_hbar	real 		1.0
+
+We can change one or more of these variables' values in the simulation by passing it at run time.
+
+.. code-block:: none
+
+    $ mpirun -np 2 ./wigner --omega 0.1 --alpha_0 2.5 --Uint_hbar 0
+    Found enlightenment... (Importing wisdom)
+    Planning for (distributed x, y) <---> (distributed ky, kx) transform... done.
+    Planning for (distributed x, y) <---> (distributed ky, kx) transform... done.
+    Sampled field (for moment group #1) at t = 0.000000e+00
+    Current timestep: 1.916945e-04
+    
+    ...
+    
+The values that were used for the variables, whether default or passed in, are stored in the output file (wigner.xsil).
+
+.. code-block:: xpdeint
+
+    <info>
+    Script compiled with XMDS2 version 2.1 "Happy Mollusc" (r2680)
+    See http://www.xmds.org for more information.
+
+    Variables that can be specified on the command line:
+      Command line argument omega = 1.000000e-01
+      Command line argument alpha_0 = 2.500000e+00
+      Command line argument absorb = 8.000000e+00
+      Command line argument width = 3.000000e-01
+      Command line argument Uint_hbar = 0.000000e+00
+    </info>
+    
+Finally, note the shorthand used in the output group
+
+.. code-block:: xpdeint
+
+      <![CDATA[
+        _SAMPLE_COMPLEX(W);
+      ]]>
+
+which is short for
+
+.. code-block:: xpdeint
+
+      <![CDATA[
+        WR = W.Re();
+        WI = W.Im();
+      ]]>
+ 
+
+.. _GroundStateBEC:
+
+Finding the Ground State of a BEC (continuous renormalisation)
+--------------------------------------------------------------
+
+This simulation solves another partial differential equation, but introduces several powerful new features in XMDS2.  The nominal problem is the calculation of the lowest energy eigenstate of a non-linear Schrödinger equation:
+
+.. math::
+    \frac{\partial \phi}{\partial t} = i \left[\frac{1}{2}\frac{\partial^2}{\partial y^2} - V(y) - U_{int}|\phi|^2\right]\phi
+
+which can be found by evolving the above equation in imaginary time while keeping the normalisation constant.  This causes eigenstates to exponentially decay at the rate of their eigenvalue, so after a short time only the state with the lowest eigenvalue remains.  The evolution equation is straightforward:
+
+.. math::
+    \frac{\partial \phi}{\partial t} = \left[\frac{1}{2}\frac{\partial^2}{\partial y^2} - V(y) - U_{int}|\phi|^2\right]\phi
+
+but we will need to use new XMDS2 features to manage the normalisation of the function :math:`\phi(y,t)`.  The normalisation for a non-linear Schrödinger equation is given by :math:`\int dy |\phi(y,t)|^2 = N_{particles}`, where :math:`N_{particles}` is the number of particles described by the wavefunction.  
+
+The code for this simulation can be found in ``examples/groundstate_workedexamples.xmds``:
+
+.. code-block:: xpdeint
+
+    <simulation xmds-version="2">
+      <name>groundstate</name>
+      <author>Joe Hope</author>
+      <description>
+        Calculate the ground state of the non-linear Schrodinger equation in a harmonic magnetic trap.
+        This is done by evolving it in imaginary time while re-normalising each timestep.
+      </description>
+
+      <features>
+        <auto_vectorise />
+        <benchmark />
+        <bing />
+        <fftw plan="exhaustive" />
+        <globals>
+          <![CDATA[
+            const real Uint = 2.0;
+            const real Nparticles = 5.0;
+          ]]>
+        </globals>
+      </features>
+
+      <geometry>
+        <propagation_dimension> t </propagation_dimension>
+        <transverse_dimensions>
+          <dimension name="y" lattice="256"  domain="(-15.0, 15.0)" />
+        </transverse_dimensions>
+      </geometry>
+
+      <vector name="potential" initial_basis="y" type="real">
+        <components> V1 </components>
+        <initialisation>
+          <![CDATA[
+            V1  = 0.5*y*y;
+          ]]>
+        </initialisation>
+      </vector>
+
+      <vector name="wavefunction" initial_basis="y" type="complex">
+        <components> phi </components>
+        <initialisation>
+          <![CDATA[
+            if (fabs(y) < 3.0) {
+              phi = 1.0;
+              // This will be automatically normalised later
+            } else {
+              phi = 0.0;
+            }
+                ]]>
+        </initialisation>
+      </vector>
+
+      <computed_vector name="normalisation" dimensions="" type="real">
+        <components> Ncalc </components>
+        <evaluation>
+          <dependencies basis="y">wavefunction</dependencies>
+          <![CDATA[
+            // Calculate the current normalisation of the wave function.
+            Ncalc = mod2(phi);
+          ]]>
+        </evaluation>
+      </computed_vector>
+
+      <sequence>
+          <filter>
+            <![CDATA[
+              printf("Hello world from a filter segment!\n");
+            ]]>
+          </filter>
+
+        <filter>
+            <dependencies>normalisation wavefunction</dependencies>
+          <![CDATA[
+            phi *= sqrt(Nparticles/Ncalc);
+          ]]>
+        </filter>
+
+        <integrate algorithm="ARK45" interval="1.0" steps="4000" tolerance="1e-10">
+          <samples>25 4000</samples>
+          <filters where="step end">
+            <filter>
+              <dependencies>wavefunction normalisation</dependencies>
+              <![CDATA[
+                // Correct normalisation of the wavefunction
+                phi *= sqrt(Nparticles/Ncalc);
+              ]]>
+            </filter>
+          </filters>
+          <operators>
+            <operator kind="ip" constant="yes">
+              <operator_names>T</operator_names>
+              <![CDATA[
+                T = -0.5*ky*ky;
+              ]]>
+            </operator>
+            <integration_vectors>wavefunction</integration_vectors>
+            <dependencies>potential</dependencies>
+            <![CDATA[
+              dphi_dt = T[phi] - (V1 + Uint*mod2(phi))*phi;
+            ]]>
+          </operators>
+        </integrate>
+
+        <breakpoint filename="groundstate_break.xsil">
+          <dependencies basis="ky">wavefunction </dependencies>
+        </breakpoint>
+
+      </sequence>
+
+      <output>
+        <sampling_group basis="y" initial_sample="yes">
+          <moments>norm_dens</moments>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            norm_dens = mod2(phi);
+          ]]>
+        </sampling_group>
+        
+        <sampling_group initial_sample="yes">
+          <moments>norm</moments>
+          <dependencies>normalisation</dependencies>
+          <![CDATA[
+            norm = Ncalc;
+          ]]>
+        </sampling_group>
+      </output>
+    </simulation>
+
+We have used the ``plan="exhasutive"`` option in the ``<fftw>`` element to ensure that the absolute fastest transform method is found.  Because the FFTW package stores the results of its tests (by default in the ~/.xmds/wisdom directory), this option does not cause significant computational overhead, except perhaps on the very first run of a new program.
+
+This simulation introduces the first example of a very powerful feature in XMDS2: the ``<computed_vector>`` element.  This has syntax like any other vector, including possible dependencies on other vectors, and an ability to be used in any element that can use vectors.  The difference is that, much like noise vectors, computed vectors are recalculated each time they are required.  This means that a computed vector can never be used as an integration vector, as its values are not stored.  [...]
+
+The difference between a computed vector and a stored vector is emphasised by the replacement of the ``<initialisation>`` element with an ``<evaluation>`` element.  Apart from the name, they have virtually identical purpose and syntax.  
+
+.. code-block:: xpdeint
+
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components> Ncalc </components>
+    <evaluation>
+      <dependencies basis="y">wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi);
+      ]]>
+    </evaluation>
+  </computed_vector>
+
+Here, our computed vector has no transverse dimensions and depends on the components of "wavefunction", so the extra transverse dimensions are integrated out.  This code therefore integrates the square modulus of the field, and returns it in the variable "Ncalc".  This will be used below to renormalise the "phi" field.  Before we examine that process, we have to introduce the ``<filter>`` element.
+
+The ``<filter>`` element can be placed in the ``<sequence>`` element, or inside ``<integrate>`` elements as we will see next.  Elements placed in the ``<sequence>`` element are executed in the order they are found in the .xmds file.  Filter elements place the included CDATA block directly into the generated program at the designated position.  If the element does not contain any dependencies, like in our first example, then the code is placed alone:
+
+.. code-block:: xpdeint
+
+    <filter>
+      <![CDATA[
+        printf("Hello world from a filter segment!\n");
+      ]]>
+    </filter>
+
+This filter block merely prints a string into the output when the generated program is run.  If the ``<filter>`` element contains dependencies, then the variables defined in those vectors (or computed vectors, or noise vectors) will be available, and the CDATA block will be placed inside loops that run over all the transverse dimensions used by the included vectors.  The second filter block in this example depends on both the "wavefunction" and "normalisation" vectors:
+
+.. code-block:: xpdeint
+
+    <filter>
+        <dependencies>normalisation wavefunction</dependencies>
+      <![CDATA[
+        phi *= sqrt(Nparticles/Ncalc);
+      ]]>
+    </filter>
+
+Since this filter depends on a vector with the transverse dimension "y", this filter will execute for each point in "y".  This code multiplies the value of the field "phi" by the factor required to produce a normalised function in the sense that  :math:`\int dy |\phi(y,t)|^2 = N_{particles}`.
+
+The next usage of a ``<filter>`` element in this program is inside the ``<integrate>`` element, where all filters are placed inside a ``<filters>`` element.
+
+.. code-block:: xpdeint
+
+    <filters where="step end">
+      <filter>
+        <dependencies>wavefunction normalisation</dependencies>
+        <![CDATA[
+          // Correct normalisation of the wavefunction
+          phi *= sqrt(Nparticles/Ncalc);
+        ]]>
+      </filter>
+    </filters>
+
+Filters placed in an integration block are applied each integration step.  The "where" flag is used to determine whether the filter should be applied directly before or directly after each integration step.  The default value for the where flag is ``where="step start"``, but in this case we chose "step end" to make sure that the final output was normalised after the last integration step.
+
+At the end of the sequence element we introduce the ``<breakpoint>`` element.  This serves two purposes.  The first is a simple matter of convenience.  Often when we manage our input and output from a simulation, we are interested solely in storing the exact state of our integration vectors.  A breakpoint element does exactly that, storing the components of any vectors contained within, taking all the normal options of the ``<output>`` element but not requiring any ``<sampling_group>`` e [...]
+
+.. code-block:: xpdeint
+
+    <breakpoint filename="groundstate_break.xsil">
+      <dependencies basis="ky">wavefunction</dependencies>
+    </breakpoint>
+
+If the filename argument is omitted, the output filenames are numbered sequentially.  Any given ``<breakpoint>`` element must only depend on vectors with identical dimensions.
+
+This program begins with a very crude guess to the ground state, but it rapidly converges to the lowest eigenstate.
+
+.. figure:: images/groundstateU2.*
+    :align: center
+    
+    The shape of the ground state rapidly approaches the lowest eigenstate.  For weak nonlinearities, it is nearly Gaussian.
+    
+.. figure:: images/groundstateU20.*
+    :align: center
+
+    When the nonlinear term is larger (:math:`U=20`), the ground state is wider and more parabolic.
+
+
+
+
+.. _HermiteGaussGroundStateBEC:
+
+Finding the Ground State of a BEC again
+---------------------------------------
+
+Here we repeat the same simulation as in the :ref:`GroundStateBEC` example, using a different transform basis.  While spectral methods are very effective, and Fourier transforms are typically very efficient due to the Fast Fourier transform algorithm, it is often desirable to describe nonlocal evolution in bases other than the Fourier basis.  The previous calculation was the Schrödinger equation with a harmonic potential and a nonlinear term.  The eigenstates of such a system are known a [...]
+
+.. math::
+    \left[-\frac{\hbar}{2 m}\frac{\partial^2}{\partial x^2} + \frac{1}{2}\omega^2 x^2\right]\phi_n(x) = E_n \phi_n(x)
+
+where
+
+.. math::
+    \phi_n(x,t) = \sqrt{\frac{1}{2^n n!}} \left(\frac{m \omega}{\hbar \pi}\right)^\frac{1}{4} e^{-\frac{m \omega x^2}{2\hbar}} H_n\left(\sqrt{\frac{m \omega}{\hbar}x}\right),\;\;\;\;\;\;E_n = \left(n+\frac{1}{2}\right) \omega
+
+where :math:`H_n(u)` are the physicist's version of the Hermite polynomials.  Rather than describing the derivatives as diagonal terms in Fourier space, we therefore have the option of describing the entire :math:`-\frac{\hbar}{2 m}\frac{\partial^2}{\partial x^2} + \frac{1}{2}\omega^2 x^2` term as a diagonal term in the hermite-Gaussian basis.  Here is an XMDS2 simulation that performs the integration in this basis. The following is a simplified version of the ``examples/hermitegauss_gro [...]
+
+.. code-block:: xpdeint
+
+    <simulation xmds-version="2">
+      <name>hermitegauss_groundstate</name>
+      <author>Graham Dennis</author>
+      <description>
+        Solve for the groundstate of the Gross-Pitaevskii equation using the hermite-Gauss basis.
+      </description>
+  
+      <features>
+        <benchmark />
+        <bing />
+        <validation kind="run-time" />
+        <globals>
+          <![CDATA[
+            const real omegaz = 2*M_PI*20;
+            const real omegarho = 2*M_PI*200;
+            const real hbar = 1.05457148e-34;
+            const real M = 1.409539200000000e-25;
+            const real g = 9.8;
+            const real scatteringLength = 5.57e-9;
+            const real transverseLength = 1e-5;
+            const real Uint = 4.0*M_PI*hbar*hbar*scatteringLength/M/transverseLength/transverseLength;
+            const real Nparticles = 5.0e5;
+        
+            /* offset constants */
+            const real EnergyOffset = 0.3*pow(pow(3.0*Nparticles/4*omegarho*Uint,2.0)*M/2.0,1/3.0); // 1D   
+          ]]>
+        </globals>
+      </features>
+  
+      <geometry>
+        <propagation_dimension> t </propagation_dimension>
+        <transverse_dimensions>
+          <dimension name="x" lattice="100" length_scale="sqrt(hbar/(M*omegarho))" transform="hermite-gauss" />
+        </transverse_dimensions>
+      </geometry>
+  
+      <vector name="wavefunction" initial_basis="x" type="complex">
+        <components> phi </components>
+        <initialisation>
+          <![CDATA[
+          phi = sqrt(Nparticles) * pow(M*omegarho/(hbar*M_PI), 0.25) * exp(-0.5*(M*omegarho/hbar)*x*x);
+          ]]>
+        </initialisation>
+      </vector>
+  
+      <computed_vector name="normalisation" dimensions="" type="real">
+        <components> Ncalc </components>
+        <evaluation>
+          <dependencies basis="x">wavefunction</dependencies>
+          <![CDATA[
+            // Calculate the current normalisation of the wave function.
+            Ncalc = mod2(phi);
+          ]]>
+        </evaluation>
+      </computed_vector>
+  
+      <sequence>
+        <integrate algorithm="ARK45" interval="1.0e-2" steps="4000"  tolerance="1e-10">
+          <samples>100 100</samples>
+          <filters>
+            <filter>
+              <dependencies>wavefunction normalisation</dependencies>
+              <![CDATA[
+                // Correct normalisation of the wavefunction
+                phi *= sqrt(Nparticles/Ncalc);
+              ]]>
+            </filter>
+          </filters>
+          <operators>
+            <operator kind="ip" constant="yes" type="real">
+              <operator_names>L</operator_names>
+              <![CDATA[
+                L = EnergyOffset/hbar - (nx + 0.5)*omegarho;
+              ]]>
+            </operator>
+            <integration_vectors>wavefunction</integration_vectors>
+            <![CDATA[
+              dphi_dt = L[phi] - Uint/hbar*mod2(phi)*phi;
+            ]]>
+          </operators>
+        </integrate>
+
+        <filter>
+            <dependencies>normalisation wavefunction</dependencies>
+          <![CDATA[
+            phi *= sqrt(Nparticles/Ncalc);
+          ]]>
+        </filter>
+    
+        <breakpoint filename="hermitegauss_groundstate_break.xsil" format="ascii">
+          <dependencies basis="nx">wavefunction</dependencies>
+        </breakpoint>
+      </sequence>
+  
+      <output>
+        <sampling_group basis="x" initial_sample="yes">
+          <moments>dens</moments>
+          <dependencies>wavefunction</dependencies>
+          <![CDATA[
+            dens = mod2(phi);
+          ]]>
+        </sampling_group>
+        <sampling_group basis="kx" initial_sample="yes">
+          <moments>dens</moments>
+          <dependencies>wavefunction</dependencies>
+          <![CDATA[
+            dens = mod2(phi);
+          ]]>
+        </sampling_group>
+      </output>
+    </simulation>
+
+The major difference in this simulation code, aside from the switch back from dimensionless units, is the new transverse dimension type in the ``<geometry>`` element.
+
+.. code-block:: xpdeint
+ 
+          <dimension name="x" lattice="100" length_scale="sqrt(hbar/(M*omegarho))" transform="hermite-gauss" />
+
+We have explicitly defined the "transform" option, which by defaults expects the Fourier transform.  The ``transform="hermite-gauss"`` option requires the 'mpmath' package installed, just as Fourier transforms require the FFTW package to be installed.  The "lattice" option details the number of hermite-Gaussian eigenstates to include, and automatically starts from the zeroth order polynomial and increases.  The number of hermite-Gaussian modes fully determines the irregular spatial grid  [...]
+
+The ``length_scale="sqrt(hbar/(M*omegarho))"`` option requires a real number, but since this script defines it in terms of variables, XMDS2 is unable to verify that the resulting function is real-valued at the time of generating the code.  XMDS2 will therefore fail to compile this program without the feature:
+
+.. code-block:: xpdeint
+
+        <validation kind="run-time" />
+
+which disables many of these checks at the time of writing the C-code.
+
+.. _2DMultistateSE:
+
+Multi-component Schrödinger equation
+------------------------------------
+
+This example demonstrates a simple method for doing matrix calculations in XMDS2.  We are solving the multi-component PDE
+
+.. math::
+    \frac{\partial \phi_j(x,y)}{\partial t} = \frac{i}{2}\left(\frac{\partial^2}{\partial x^2}+\frac{\partial^2}{\partial y^2}\right)\phi_j(x,y) - i U(x,y) \sum_k V_{j k}\phi_k(x,y)
+    
+where the last term is more commonly written as a matrix multiplication.  Writing this term out explicitly is feasible for a small number of components, but when the number of components becomes large, or perhaps :math:`V_{j k}` should be precomputed for efficiency reasons, it is useful to be able to perform this sum over the integer dimensions automatically.  This example show how this can be done naturally using a computed vector.  The XMDS2 script is as follows:
+
+.. code-block:: xpdeint
+
+        <simulation xmds-version="2">
+          <name>2DMSse</name>
+
+          <author>Joe Hope</author>
+          <description>
+            Schroedinger equation for multiple internal states in two spatial dimensions.
+          </description>
+
+          <features>
+              <benchmark />
+              <bing />
+              <fftw plan="patient" />
+              <openmp />
+              <auto_vectorise />
+             </features>
+
+          <geometry>
+              <propagation_dimension> t </propagation_dimension>
+              <transverse_dimensions>
+                  <dimension name="x" lattice="32"  domain="(-6, 6)" />
+                  <dimension name="y" lattice="32"  domain="(-6, 6)" />
+                  <dimension name="j" type="integer" lattice="2" domain="(0,1)" aliases="k"/>
+              </transverse_dimensions>
+           </geometry>
+
+          <vector name="wavefunction" type="complex" dimensions="x y j">
+            <components> phi </components>
+            <initialisation>
+              <![CDATA[
+              phi = j*sqrt(2/sqrt(M_PI/2))*exp(-(x*x+y*y)/4)*exp(i*0.1*x);
+              ]]>
+            </initialisation>
+          </vector>
+
+          <vector name="spatialInteraction" type="real" dimensions="x y">
+            <components> U </components>
+            <initialisation>
+              <![CDATA[
+              U=exp(-(x*x+y*y)/4);
+              ]]>
+            </initialisation>
+          </vector>
+
+          <vector name="internalInteraction" type="real" dimensions="j k">
+            <components> V </components>
+            <initialisation>
+              <![CDATA[
+              V=3*(j*(1-k)+(1-j)*k);
+              ]]>
+            </initialisation>
+          </vector>
+
+          <computed_vector name="coupling" dimensions="x y j" type="complex">
+            <components>
+              VPhi
+            </components>
+            <evaluation>
+              <dependencies basis="x y j k">internalInteraction wavefunction</dependencies>
+              <![CDATA[
+                // Calculate the current normalisation of the wave function.
+                VPhi = V*phi(j => k);
+              ]]>
+            </evaluation>
+          </computed_vector>
+
+          <sequence>
+            <integrate algorithm="ARK45" interval="2.0" tolerance="1e-7">
+              <samples>20 100</samples>
+              <operators>
+                <integration_vectors>wavefunction</integration_vectors>
+                <operator kind="ex" constant="yes">
+                  <operator_names>Ltt</operator_names>
+                  <![CDATA[
+                    Ltt = -i*(kx*kx+ky*ky)*0.5;
+                  ]]>
+                </operator>
+                <![CDATA[
+                dphi_dt = Ltt[phi] -i*U*VPhi;
+                ]]>
+                <dependencies>spatialInteraction coupling</dependencies>
+              </operators>
+            </integrate>
+          </sequence>
+
+          <output>
+            <sampling_group basis="x y j" initial_sample="yes">
+              <moments>density</moments>
+              <dependencies>wavefunction</dependencies>
+              <![CDATA[
+                density = mod2(phi);
+              ]]>
+            </sampling_group>
+            <sampling_group basis="x(0) y(0) j" initial_sample="yes">
+              <moments>normalisation</moments>
+              <dependencies>wavefunction</dependencies>
+              <![CDATA[
+                normalisation = mod2(phi);
+              ]]>
+            </sampling_group>
+          </output>
+        </simulation>
+
+The only truly new feature in this script is the "aliases" option on a dimension.  The integer-valued dimension in this script indexes the components of the PDE (in this case only two).  The  :math:`V_{j k}` term is required to be a square array of dimension of this number of components.  If we wrote the k-index of :math:`V_{j k}` using a separate ``<dimension>`` element, then we would not be enforcing the requirement that the matrix be square.  Instead, we note that we will be using mul [...]
+
+.. code-block:: xpdeint
+
+                  <dimension name="j" type="integer" lattice="2" domain="(0,1)" aliases="k"/>
+
+This means that we can use the index "k", which will have exactly the same properties as the "j" index.  This is used to define the "V" function in the "internalInteraction" vector.  Now, just as we use a computed vector to perform an integration over our fields, we use a computed vector to calculate the sum.
+
+.. code-block:: xpdeint
+
+        <computed_vector name="coupling" dimensions="x y j" type="complex">
+          <components>
+            VPhi
+          </components>
+          <evaluation>
+            <dependencies basis="x y j k">internalInteraction wavefunction</dependencies>
+            <![CDATA[
+              // Calculate the current normalisation of the wave function.
+              VPhi = V*phi(j => k);
+            ]]>
+          </evaluation>
+        </computed_vector>
+
+Since the output dimensions of the computed vector do not include a "k" index, this index is integrated.  The volume element for this summation is the spacing between neighbouring values of "j", and since this spacing is one, this integration is just a sum over k, as required.
+
+
+By this point, we have introduced most of the important features in XMDS2.  More details on other transform options and rarely used features can be found in the :ref:`advancedTopics` section.
+
+
diff --git a/admin/userdoc-source/xsil2graphics2.rst b/admin/userdoc-source/xsil2graphics2.rst
new file mode 100644
index 0000000..0665961
--- /dev/null
+++ b/admin/userdoc-source/xsil2graphics2.rst
@@ -0,0 +1,8 @@
+.. _xsil2graphics2:
+
+xsil2graphics2
+===============
+
+**xsil2graphics2** is a way of converting ".xsil" files to formats that other programs can read.  The syntax is described in the :ref:`QuickStartTutorial`, and by using the ``xsil2graphics2 --help`` option.  It currently can covert any output format for use by Mathematica.
+
+We recommend HDF5 format instead of the binary format for output and input, as many visualisation tools can already read/write to this format directly.
\ No newline at end of file
diff --git a/admin/xpdeint.tmbundle/Syntaxes/Cheetah - xpdeint template.tmLanguage b/admin/xpdeint.tmbundle/Syntaxes/Cheetah - xpdeint template.tmLanguage
new file mode 100644
index 0000000..5eef140
--- /dev/null
+++ b/admin/xpdeint.tmbundle/Syntaxes/Cheetah - xpdeint template.tmLanguage	
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>fileTypes</key>
+	<array>
+		<string>tmpl</string>
+	</array>
+	<key>foldingStartMarker</key>
+	<string>/\*\*|\{\s*$</string>
+	<key>foldingStopMarker</key>
+	<string>\*\*/|^\s*\}</string>
+	<key>name</key>
+	<string>Cheetah - xpdeint template</string>
+	<key>patterns</key>
+	<array>
+		<dict>
+			<key>match</key>
+			<string>@(def [_a-zA-Z]\w*|end def|set|del|extends|attr|return|stop|import|from|try|except|raise)</string>
+			<key>name</key>
+			<string>string.unquoted.keyword.control.cheetah</string>
+		</dict>
+		<dict>
+			<key>match</key>
+			<string>@(if|end if|continue|break|for|end for|else if|else|pass|elif|while|end while).*</string>
+			<key>name</key>
+			<string>string.unquoted.keyword.control.flow.cheetah</string>
+		</dict>
+		<dict>
+			<key>match</key>
+			<string>@(super|filter|end filter|capture|end capture|silent|slurp|assert|@[_a-zA-Z][_a-zA-Z0-9.]*)</string>
+			<key>name</key>
+			<string>string.unquoted.keyword.other.cheetah</string>
+		</dict>
+		<dict>
+			<key>begin</key>
+			<string>@\*</string>
+			<key>end</key>
+			<string>\*@</string>
+			<key>name</key>
+			<string>string.unquoted.comment.block.cheetah</string>
+		</dict>
+		<dict>
+			<key>begin</key>
+			<string>@#</string>
+			<key>beginCaptures</key>
+			<dict>
+				<key>0</key>
+				<dict>
+					<key>name</key>
+					<string>punctuation.definition.comment.cheetah</string>
+				</dict>
+			</dict>
+			<key>end</key>
+			<string>$\n?</string>
+			<key>name</key>
+			<string>string.unquoted.comment.line.athash.cheetah</string>
+		</dict>
+		<dict>
+			<key>include</key>
+			<string>source.c++</string>
+		</dict>
+	</array>
+	<key>scopeName</key>
+	<string>source.c++.xpdeintcheetah</string>
+	<key>uuid</key>
+	<string>8321049C-C450-450C-AD7A-277F8100A544</string>
+</dict>
+</plist>
diff --git a/admin/xpdeint.tmbundle/Syntaxes/xpdeint.tmLanguage b/admin/xpdeint.tmbundle/Syntaxes/xpdeint.tmLanguage
new file mode 100644
index 0000000..a2ffef3
--- /dev/null
+++ b/admin/xpdeint.tmbundle/Syntaxes/xpdeint.tmLanguage
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>fileTypes</key>
+	<array>
+		<string>xmds</string>
+	</array>
+	<key>firstLineMatch</key>
+	<string><?(?i:xmds)</string>
+	<key>foldingStartMarker</key>
+	<string>(?x)
+		(^\s*(<[^!?%/](?!.+?(/>|</.+?>))|<[!%]--(?!.+?--%?>)|<%[!]?(?!.+?%>))
+		|^(?![^{]*?//|[^{]*?/\*(?!.*?\*/.*?\{)).*?\{\s*($|//|/\*(?!.*?\*/.*\S))
+		)</string>
+	<key>foldingStopMarker</key>
+	<string>^\s*(</[^>]+>|[/%]>|-->)\s*$|^\s*\}</string>
+	<key>keyEquivalent</key>
+	<string>^~X</string>
+	<key>name</key>
+	<string>XMDS</string>
+	<key>patterns</key>
+	<array>
+		<dict>
+			<key>begin</key>
+			<string><!\[CDATA\[</string>
+			<key>captures</key>
+			<dict>
+				<key>0</key>
+				<dict>
+					<key>name</key>
+					<string>meta.tag.xml.xmds</string>
+				</dict>
+			</dict>
+			<key>contentName</key>
+			<string>source.c++.embedded.xmds</string>
+			<key>end</key>
+			<string>]]></string>
+			<key>patterns</key>
+			<array>
+				<dict>
+					<key>include</key>
+					<string>source.c++</string>
+				</dict>
+				<dict>
+					<key>match</key>
+					<string>\b(complex|fftw_complex)\b</string>
+					<key>name</key>
+					<string>storage.type.c++.xmds</string>
+				</dict>
+				<dict>
+					<key>match</key>
+					<string>\b((r|p)complex|real|imag|mod(2)?|arg|conj|c_(exp|log|sqrt))\b</string>
+					<key>name</key>
+					<string>support.function.xmds</string>
+				</dict>
+				<dict>
+					<key>match</key>
+					<string>\bi\b</string>
+					<key>name</key>
+					<string>constant.numeric.c++.xmds</string>
+				</dict>
+			</array>
+		</dict>
+		<dict>
+			<key>include</key>
+			<string>text.xml</string>
+		</dict>
+	</array>
+	<key>scopeName</key>
+	<string>text.xml.xmds</string>
+	<key>uuid</key>
+	<string>C57D99F8-C368-461F-B510-9590A6F552CB</string>
+</dict>
+</plist>
diff --git a/admin/xpdeint.tmbundle/info.plist b/admin/xpdeint.tmbundle/info.plist
new file mode 100644
index 0000000..e68b05c
--- /dev/null
+++ b/admin/xpdeint.tmbundle/info.plist
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>name</key>
+	<string>xpdeint</string>
+	<key>ordering</key>
+	<array>
+		<string>8321049C-C450-450C-AD7A-277F8100A544</string>
+		<string>CF496F1F-814E-4F57-926B-83EBED3037CF</string>
+	</array>
+	<key>uuid</key>
+	<string>05E72337-772C-4F29-AE57-E1C835A4025A</string>
+</dict>
+</plist>
diff --git a/bin/xmds2 b/bin/xmds2
new file mode 100644
index 0000000..29b8ba2
--- /dev/null
+++ b/bin/xmds2
@@ -0,0 +1,4 @@
+#!/usr/bin/env python
+from xpdeint import parser2
+import sys
+sys.exit(parser2.main())
\ No newline at end of file
diff --git a/bin/xsil2graphics2 b/bin/xsil2graphics2
new file mode 100644
index 0000000..395895b
--- /dev/null
+++ b/bin/xsil2graphics2
@@ -0,0 +1,4 @@
+#!/usr/bin/env python
+from xpdeint import xsil2graphicsParser
+import sys
+sys.exit(xsil2graphicsParser.main())
\ No newline at end of file
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..ced6488
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,5 @@
+xmds2 (2.1.2-1-20121121) wheezy-evmik; urgency=low
+
+  * Debianization
+
+ -- Eugeniy Mikhailov <evgmik at gmail.com>  Wed, 21 Nov 2012 15:11:20 -0500
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..7f8f011
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+7
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..3ab3b54
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,45 @@
+Source: xmds2
+Section: python
+Priority: optional
+Maintainer: Eugeniy Mikhailov <evgmik at gmail.com>
+Build-Depends: debhelper (>= 7.0.50~),
+	       cdbs (>= 0.4.43),
+               python-h5py,
+               python-setuptools,
+               python-pyparsing,
+               python-markdown,
+               python-mpmath,
+	       python-numpy,
+	       python-lxml,
+               python-cheetah
+Standards-Version: 3.8.4
+XB-Python-Version: ${python:Versions}
+Homepage: http://xmds.sourceforge.net/
+
+Package: xmds2
+Architecture: any
+Depends: ${python:Depends}, 
+         ${shlibs:Depends}, 
+         ${misc:Depends}, 
+         fftw3-dev, 
+	 libhdf5-serial-dev,
+	 libatlas-base-dev,
+         libmpich2-dev, 
+	 mpich2, 
+	 python-h5py,
+	 python-setuptools,
+	 python-pyparsing,
+	 python-markdown,
+	 python-mpmath,
+	 python-numpy,
+	 python-lxml,
+	 python-cheetah, 
+         python-pyparsing, 
+         g++
+Description: eXtensible Multi-Dimensional Simulator
+ XMDS is a code generator that integrates equations, from Ordinary
+ Differential Equations (ODEs) up to stochastic Partial Differential
+ Equations (PDEs). You write them down in human readable form in an
+ XML file, and it goes away and writes and compiles a C++ program that
+ integrates those equations as fast as it can possibly be done in your
+ architecture.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..54a627a
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,31 @@
+This work was packaged for Debian by:
+
+    Eugeniy Mikhailov <evgmik at gmail.com> on Tue, 17 May 2011 11:48:44 -0400
+
+It was downloaded from:
+
+    http://www.xmds.org/
+
+Upstream Author(s):
+
+    Graham Dennis <graham.dennis at anu.edu.au>,
+    Andy Ferris,
+    Joe Hope,
+    Michael Hush,
+    Mattias Johnsson,
+    Gabriel McManus
+
+Copyright:
+
+    Copyright (C) 2000-2012 Graham Dennis, Andy Ferris, Joe Hope, Michael Hush, Mattias Johnsson, Gabriel McManus
+
+License:
+
+    GNU General Public License 2
+
+The Debian packaging is:
+
+    Copyright (C) 2011-2012 Eugeniy Mikhailov <evgmik at gmail.com>
+
+and is licensed under the GPL version 3,
+see "/usr/share/common-licenses/GPL-3".
diff --git a/debian/docs b/debian/docs
new file mode 100644
index 0000000..b1731f3
--- /dev/null
+++ b/debian/docs
@@ -0,0 +1,3 @@
+README
+COPYRIGHT
+ReleaseNotes
diff --git a/debian/pycompat b/debian/pycompat
new file mode 100644
index 0000000..0cfbf08
--- /dev/null
+++ b/debian/pycompat
@@ -0,0 +1 @@
+2
diff --git a/debian/pyversions b/debian/pyversions
new file mode 100644
index 0000000..ec68696
--- /dev/null
+++ b/debian/pyversions
@@ -0,0 +1 @@
+2.5-2.9
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..4b8666c
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,28 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+
+# this blocks attempts to download python build dependencies
+# if the relevant package is incidentally forgotten in Build-Depends 
+export http_proxy = http://127.0.0.1:9/ 
+
+#DH_VERBOSE=1
+
+%:
+	dh $@ --with python2
+
+override_dh_auto_install:
+	python setup.py install --root=debian/xmds2 --install-layout=deb 
+
+override_dh_auto_test:
+
+override_dh_auto_clean:
+	dh_clean
+	cd xpdeint; waf/waf-light configure
+	make clean
+	rm -rf xmds2.egg-info/
+	rm -f xpdeint/.lock-waf_linux2_build
+	rm -f xpdeint/.wafpickle-98
+	rm -f xpdeint/Version.py
+	rm -rf xpdeint/c4che/
+	rm -f xpdeint/config.log
+
diff --git a/debian/xmds2.examples b/debian/xmds2.examples
new file mode 100644
index 0000000..e39721e
--- /dev/null
+++ b/debian/xmds2.examples
@@ -0,0 +1 @@
+examples/*
diff --git a/debian/xmds2.manpages b/debian/xmds2.manpages
new file mode 100644
index 0000000..536177e
--- /dev/null
+++ b/debian/xmds2.manpages
@@ -0,0 +1,2 @@
+man/xmds2.1
+man/xsil2graphics2.1
diff --git a/documentation/.buildinfo b/documentation/.buildinfo
new file mode 100644
index 0000000..44f81c2
--- /dev/null
+++ b/documentation/.buildinfo
@@ -0,0 +1,4 @@
+# Sphinx build info version 1
+# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
+config: 7cf3005835a9c6446e373e48bdc8c2f8
+tags: 645f666f9bcd5a90fca523b33c5a78b7
diff --git a/documentation/_images/FourierTransformEx1.png b/documentation/_images/FourierTransformEx1.png
new file mode 100644
index 0000000..792c790
Binary files /dev/null and b/documentation/_images/FourierTransformEx1.png differ
diff --git a/documentation/_images/FourierTransformEx2.png b/documentation/_images/FourierTransformEx2.png
new file mode 100644
index 0000000..970db9a
Binary files /dev/null and b/documentation/_images/FourierTransformEx2.png differ
diff --git a/documentation/_images/FourierTransformEx3.png b/documentation/_images/FourierTransformEx3.png
new file mode 100644
index 0000000..70ef606
Binary files /dev/null and b/documentation/_images/FourierTransformEx3.png differ
diff --git a/documentation/_images/fibre1024.png b/documentation/_images/fibre1024.png
new file mode 100644
index 0000000..b8a2b64
Binary files /dev/null and b/documentation/_images/fibre1024.png differ
diff --git a/documentation/_images/fibreSingle.png b/documentation/_images/fibreSingle.png
new file mode 100644
index 0000000..5e756ec
Binary files /dev/null and b/documentation/_images/fibreSingle.png differ
diff --git a/documentation/_images/groundstateU2.png b/documentation/_images/groundstateU2.png
new file mode 100644
index 0000000..9a46c04
Binary files /dev/null and b/documentation/_images/groundstateU2.png differ
diff --git a/documentation/_images/groundstateU20.png b/documentation/_images/groundstateU20.png
new file mode 100644
index 0000000..4b6e5d2
Binary files /dev/null and b/documentation/_images/groundstateU20.png differ
diff --git a/documentation/_images/kubo10000.png b/documentation/_images/kubo10000.png
new file mode 100644
index 0000000..6672c34
Binary files /dev/null and b/documentation/_images/kubo10000.png differ
diff --git a/documentation/_images/kuboSingle.png b/documentation/_images/kuboSingle.png
new file mode 100644
index 0000000..8426c0c
Binary files /dev/null and b/documentation/_images/kuboSingle.png differ
diff --git a/documentation/_images/lorenz.png b/documentation/_images/lorenz.png
new file mode 100644
index 0000000..03083fa
Binary files /dev/null and b/documentation/_images/lorenz.png differ
diff --git a/documentation/_sources/advanced_topics.txt b/documentation/_sources/advanced_topics.txt
new file mode 100644
index 0000000..aaa51fb
--- /dev/null
+++ b/documentation/_sources/advanced_topics.txt
@@ -0,0 +1,276 @@
+.. _AdvancedTopics:
+
+Advanced Topics
+===============
+
+This section has further details on some important topics.
+
+:ref:`Importing` (importing data into XMDS2, and data formats used in the export)
+
+:ref:`Convolutions` (extra information on the Fourier transforms used in XMDS2, and applications to defining convolutions)
+
+:ref:`DimensionAliases` (dimensions which are declared to be identical, useful for correlation functions)
+
+.. _Importing:
+
+Importing data
+--------------
+
+There are many cases where it is advantageous to import previously acquired data into XMDS2. For example, the differential equation you wish to solve may depend on a complicated functional form, which is more easily obtained via an analytical package such as Mathematica or Maple. Furthermore, importing data from another source can be quicker than needlessly performing calculations in XMDS2. In this tutorial, we shall consider an example of importing into XMDS2 a function generated in Mat [...]
+
+Suppose we want to import the following function into XMDS2:
+
+.. math::
+    f(x) = x^2
+
+The first step is to create an hdf5 file, from XMDS2, which specifies the dimensions of the grid for the x dimension. Create and save a new XMDS2 file. For the purposes of this tutorial we shall call it "grid_specifier.xmds" with name "grid_specifier". Within this file, enter the following "dummy" vector - which we shall call "gen_dummy" - which depends on the x dimension:
+
+.. code-block:: xpdeint
+
+    <vector type="real" name="gen_dummy" dimensions="x">
+      <components>dummy</components>
+      <initialisation>
+      <![CDATA[ 
+        dummy = x;
+          ]]>
+      </initialisation>
+    </vector>
+
+What "dummy" is is not actually important. It is only necessary that it is a function of :math:`x`. However, it is important that the domain and lattice for the :math:`x` dimension are identical to those in the XMDS2 you plan to import the function into. We output the following xsil file (in hdf5 format) by placing a breakpoint in the sequence block as follows:
+
+.. code-block:: xpdeint
+
+    <sequence>
+      <breakpoint filename="grid.xsil" format="hdf5">
+          <dependencies>
+            gen_dummy
+          </dependencies>
+      </breakpoint>
+
+In terminal, compile the file "grid_specifier.xmds" in XMDS2 and run the c code as usual. This creates two files - "grid.xsil" and "grid.h5". The file "grid.h5" contains the list of points which make up the grids for the x dimensions. This data can now be used to ensure that the function :math:`f(x)` which we will import into XMDS2 is compatible with the the specified grid in your primary XMDS2 file.
+
+In order to read the "grid.h5" data into Mathematica version 6.0, type the following command into terminal:.. code-block::
+
+    xsil2graphics2 -e grid.xsil
+    
+This creates the Mathematica notebook "grid.nb". Open this notebook in Mathematica and evaluate the first set of cells. This has loaded the grid information into Mathematica. For example, suppose you have specified that the :math:`x` dimension has a lattice of 128 points and a domain of (-32, 32). Then calling "x1" in Mathematica should return the following list:
+
+.. code-block:: none
+ 
+  {-32., -31.5, -31., -30.5, -30., -29.5, -29., -28.5, -28., -27.5, 
+  -27., -26.5, -26., -25.5, -25., -24.5, -24., -23.5, -23., -22.5, 
+  -22., -21.5, -21., -20.5, -20., -19.5, -19., -18.5, -18., -17.5, 
+  -17., -16.5, -16., -15.5, -15., -14.5, -14., -13.5, -13., -12.5, 
+  -12., -11.5, -11., -10.5, -10., -9.5, -9., -8.5, -8., -7.5, -7., 
+  -6.5, -6., -5.5, -5., -4.5, -4., -3.5, -3., -2.5, -2., -1.5, -1., 
+  -0.5, 0., 0.5, 1., 1.5, 2., 2.5, 3., 3.5, 4., 4.5, 5., 5.5, 6., 6.5, 
+  7., 7.5, 8., 8.5, 9., 9.5, 10., 10.5, 11., 11.5, 12., 12.5, 13., 
+  13.5, 14., 14.5, 15., 15.5, 16., 16.5, 17., 17.5, 18., 18.5, 19., 
+  19.5, 20., 20.5, 21., 21.5, 22., 22.5, 23., 23.5, 24., 24.5, 25., 
+  25.5, 26., 26.5, 27., 27.5, 28., 28.5, 29., 29.5, 30., 30.5, 31., 
+  31.5}
+
+This is, of course, the list of points which define our grid.
+
+We are now in a position to define the function :math:`f(x)` in Mathematica. Type the following command into a cell in the Mathematica notebook "grid.nb":
+
+.. code-block:: none
+
+  f[x_]:= x^2
+
+At this stage this is an abstract mathematical function as defined in Mathematica. What we need is a list of values for :math:`f(x)` corresponding to the specified grid points. We will call this list "func". This achieved by simply acting the function on the list of grid points "x1":
+
+.. code-block:: none
+
+  func := f[x1]
+
+For the example grid mentioned above, calling "func" gives the following list:
+
+.. code-block:: none
+
+  {1024., 992.25, 961., 930.25, 900., 870.25, 841., 812.25, 784.,
+  756.25, 729., 702.25, 676., 650.25, 625., 600.25, 576., 552.25, 529., 
+  506.25, 484., 462.25, 441., 420.25, 400., 380.25, 361., 342.25, 324., 
+  306.25, 289., 272.25, 256., 240.25, 225., 210.25, 196., 182.25, 169., 
+  156.25, 144., 132.25, 121., 110.25, 100., 90.25, 81., 72.25, 64., 
+  56.25, 49., 42.25, 36., 30.25, 25., 20.25, 16., 12.25, 9., 6.25, 4., 
+  2.25, 1., 0.25, 0., 0.25, 1., 2.25, 4., 6.25, 9., 12.25, 16., 20.25, 
+  25., 30.25, 36., 42.25, 49., 56.25, 64., 72.25, 81., 90.25, 100., 
+  110.25, 121., 132.25, 144., 156.25, 169., 182.25, 196., 210.25, 225., 
+  240.25, 256., 272.25, 289., 306.25, 324., 342.25, 361., 380.25, 400., 
+  420.25, 441., 462.25, 484., 506.25, 529., 552.25, 576., 600.25, 625., 
+  650.25, 676., 702.25, 729., 756.25, 784., 812.25, 841., 870.25, 900., 
+  930.25, 961., 992.25}
+  
+  
+The next step is to export the list "func" as an h5 file that XMDS2 can read. This is done by typing the following command into a Mathematica cell:
+  
+.. code-block:: none
+  
+   SetDirectory[NotebookDirectory[]];
+   Export["func.h5", {func, x1}, {"Datasets", { "function_x", "x"}}]
+   
+In the directory containing the notebook "grid.nb" you should now see the file "func.h5". This file essentially contains the list ``{func, x1}``. However, the hdf5 format stores func and x1 as separate entities called "Datasets". For importation into XMDS2 it is necessary that these datasets are named. This is precisely what the segment ``{"Datasets", { "function_x", "x"}}`` in the above Mathematica command does. The dataset corresponding to the grid x1 needs to be given the name of the  [...]
+
+The final step is to import the file "func.h5" into your primary XMDS2 file. This data will be stored as a vector called "gen_function_x", in component "function_x".
+
+.. code-block:: xpdeint
+
+  <vector type="real" name="gen_function_x" dimensions="x">
+    <components>function_x</components> 
+    <initialisation kind="hdf5">
+      <filename> function_x.h5 </filename>
+    </initialisation>
+  </vector>
+  
+You're now done. Anytime you want to use :math:`f(x)` you can simply refer to "function_x" in the vector "gen_function_x".
+
+The situation is slightly more complicated if the function you wish to import depends on more than one dimension. For example, consider
+
+.. math::
+    g(x,y) = x \sin(y)
+
+As for the single dimensional case, we need to export an hdf5 file from XMDS2 which specifies the dimensions of the grid. As in the one dimensional case, this is done by creating a dummy vector which depends on all the relevant dimensions:
+
+.. code-block:: xpdeint
+
+    <vector type="real" name="gen_dummy" dimensions="x y">
+      <components>dummy</components>
+      <initialisation>
+      <![CDATA[ 
+        dummy = x;
+          ]]>
+      </initialisation>
+    </vector>
+    
+and exporting it as shown above.
+
+After importing the grid data into Mathematica, define the multi-dimensional function which you wish to import into XMDS2:
+
+.. code-block:: none
+
+  g[x_,y_]:= x*Sin[y]
+  
+We need to create a 2x2 array of data which depends upon the imported lists x1 and y1. This can be done by using the Table function:
+
+.. code-block:: none
+
+  func := Table[g[x, p], {x, x1}, {p, p1}]
+  
+This function can be exported as an h5 file,
+
+.. code-block:: none
+  
+  SetDirectory[NotebookDirectory[]];
+  Export["func.h5", {func, x1, y1}, {"Datasets", { "function_x", "x", "y"}}]
+
+and imported into XMDS2 as outlined above.
+
+.. _Convolutions:
+
+Convolutions and Fourier transforms
+-----------------------------------
+
+When evaluating a numerical Fourier transform, XMDS2 doesn't behave as expected. While many simulations have ranges in their spatial coordinate (here assumed to be x) that range from some negative value :math:`x_\text{min}` to some positive value :math:`x_\text{max}`, the Fourier transform used in XMDS2 treats all spatial coordinates as starting at zero. The result of this is that a phase factor of the form :math:`e^{-i x_\text{min} k}` is applied to the Fourier space functions after all [...]
+
+The standard Fourier transform is
+
+.. math::
+
+	\mathcal{F}\left[f(x)\right](k) = \frac{1}{\sqrt{2\pi}}\int_{x_\text{min}}^{x_\text{max}} f(x) e^{-i x k} dx
+
+The XMDS2 Fourier transform is
+
+.. math::
+	\tilde{\mathcal{F}}\left[f(x)\right](k) &= \frac{1}{\sqrt{2\pi}}\int_{x_\text{min}}^{x_\text{max}} f(x) e^{-i (x+ x_\text{min}) k} dx \\
+	&= e^{-i x_\text{min} k} \mathcal{F}\left[f(x)\right](k)
+
+When the number of forward Fourier transforms and backwards Fourier transforms are unequal a phase factor is required. Some examples of using Fourier transforms in XMDS2 are shown below.
+
+Example 1
+^^^^^^^^^
+
+.. image:: images/FourierTransformEx1.*
+    :align: center
+
+When data is input in Fourier space and output in real space there is one backwards Fourier transform is required. Therefore the Fourier space data must be multiplied by a phase factor before the backwards Fourier transform is applied.
+
+.. math::
+
+	\mathcal{F}^{-1}[F(k)](x) = \tilde{\mathcal{F}}[e^{i x_\text{min} k} F(k)](x)
+
+Example 2
+^^^^^^^^^
+.. image:: images/FourierTransformEx2.*
+    :align: center
+    
+Functions of the form :math:`h(x) = \int f(x') g(x-x') dx'` can be evaluated using the convolution theorem:
+
+.. math::
+
+	\mathcal{F}[h(x)](k) = \mathcal{F}[f(x)](k) \times \mathcal{F}[g(x)](k)
+
+This requires two forward Fourier transforms to get the two functions f and g into Fourier space, and one backwards Fourier transform to get the resulting product back into real space. Thus in Fourier space the product needs to be multiplied by a phase factor :math:`e^{-i x_\text{min} k}`
+
+
+Example 3
+^^^^^^^^^
+.. image:: images/FourierTransformEx3.*
+    :align: center
+    
+Sometimes when the convolution theorem is used one of the forward Fourier transforms is calculated analytically and input in Fourier space. In this case only one forward numerical Fourier transform and one backward numerical Fourier transform is used. The number of forward and backward transforms are equal, so no phase factor is required.
+
+.. _LooseGeometryMatchingMode:
+
+'Loose' ``geometry_matching_mode``
+----------------------------------
+
+.. _DimensionAliases:
+
+Dimension aliases
+-----------------
+
+Dimension aliases specify that two or more dimensions have exactly the same ``lattice``, ``domain`` and ``transform``.  This can be useful in situations where the problem enforces this, for example when computing correlation functions or representing square matrices.  
+
+Dimension aliases are not just a short-hand for defining an additional dimension, they also permit dimensions to be accessed :ref:`non-locally <ReferencingNonlocal>`, which is essential when computing spatial correlation functions.
+
+Here is how to compute a spatial correlation function :math:`g^{(1)}(x, x') = \psi^*(x) \psi(x')` of the quantity ``psi``:
+
+.. code-block:: xpdeint
+
+  <simulation xmds-version="2">
+    
+    <!-- name, features block -->
+        
+    <geometry>
+      <propagation_dimension> t </propagation_dimension>
+      <transverse_dimensions>
+        <dimension name="x" lattice="1024" domain="(-1.0, 1.0)" aliases="xp" />
+      </transverse_dimensions>
+    </geometry>
+    
+    <vector name="wavefunction" type="complex" >
+      <components> psi </components>
+      <initialisation>
+        <!-- initialisation code -->
+      </initialisation>
+    </vector>
+    
+    <computed_vector name="correlation" dimensions="x xp" type="complex" >
+      <components> g1 </components>
+      <evaluation>
+        <dependencies> wavefunction </dependencies>
+        <![CDATA[
+          g1 = conj(psi(x => x)) * psi(x => xp);
+        ]]>
+      </evaluation>
+    </computed_vector>
+    
+    <!-- integration and sampling code -->
+    
+  </simulation>
+
+In this simulation note that the vector ``wavefunction`` defaults to only having the dimension "x" even though "xp" is also a dimension (implicitly declared through the ``aliases`` attribute).  ``vector``'s without an explicit ``dimensions`` attribute will only have the dimensions that are explicitly listed in the ``transverse_dimensions`` block, i.e. this will not include aliases.
+
+See the example ``groundstate_gaussian.xmds`` for a complete example.
+      
\ No newline at end of file
diff --git a/documentation/_sources/developer.txt b/documentation/_sources/developer.txt
new file mode 100644
index 0000000..2e77a43
--- /dev/null
+++ b/documentation/_sources/developer.txt
@@ -0,0 +1,121 @@
+Developer Documentation
+=======================
+
+Developers need to know more than users.  For example, they need to know about the test suite, and writing test cases.  They need to know how to perform a developer installation.  They need to know how to edit and compile this documentation.  They need a step-by-step release process.
+
+.. _TestScripts:
+
+Test scripts
+------------
+
+Every time you add a new feature and/or fix a new and exciting bug, it is a great idea to make sure that the new feature works and/or the bug stays fixed.  Fortunately, it is pleasantly easy to add a test case to the testing suite.
+
+1. Write normal XMDS script that behaves as you expect.
+2. Add a ``<testing>`` element to your script.  You can read the description of this element and its contents below, and have a look at other testcases for examples, but the basic structure is simple:.
+
+.. parsed-literal::
+
+      <:ref:`testing <TestingElement>`> 
+        <:ref:`command_line <CommandLineElement>`> <:ref:`/command_line <CommandLineElement>`>
+        <:ref:`arguments <ArgumentsElement>`>
+          <:ref:`argument <ArgumentElement>` />
+          <:ref:`argument <ArgumentElement>` />
+          ...
+        <:ref:`/arguments <ArgumentsElement>`>
+        <:ref:`input_xsil_file <InputXSILFileElement>` />
+        <:ref:`xsil_file <XSILFileElement>`>
+          <:ref:`moment_group <MomentGroupElement>` />
+          <:ref:`moment_group <MomentGroupElement>` />
+          ...
+        <:ref:`/xsil_file <XSILFileElement>`>
+      <:ref:`/testing <TestingElement>`>
+      
+3. Put into the appropriate ``testsuite/`` directory.
+4. run ``./run_tests.py`` This will automatically generate your ``_expected`` files.
+5. Commit the ``.xmds``, ``*_expected.xsil`` file and any ``*_expected*`` data files.
+  
+.. _TestingElement:
+
+Testing element
+~~~~~~~~~~~~~~~
+
+
+
+.. _CommandLineElement:
+
+command_line element
+~~~~~~~~~~~~~~~~~~~~
+
+
+.. _InputXSILFileElement:
+
+input_xsil_file element
+~~~~~~~~~~~~~~~~~~~~~~~
+
+
+.. _XSILFileElement:
+
+xsil_file element
+~~~~~~~~~~~~~~~~~
+
+
+.. _MomentGroupElement:
+
+moment_group element
+~~~~~~~~~~~~~~~~~~~~
+
+
+
+Steps to update ``XMDS`` script validator (XML schema)
+------------------------------------------------------
+
+1. Modify ``xpdeint/support/xpdeint.rnc``. This is a RelaxNG compact file, which specifies the XML schema which is only used for issuing warnings to users about missing or extraneous XML tags / attributes.
+2. Run ``make`` in ``xpdeint/support/`` to update ``xpdeint/support/xpdeint.rng``. This is the file which is actually used, which is in RelaxNG format, but RelaxNG compact is easier to read and edit.
+3. Commit both ``xpdeint/support/xpdeint.rnc`` and ``xpdeint/support/xpdeint.rng``.
+
+
+Directory layout
+----------------
+
+XMDS2's code and templates
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+All ``.tmpl`` files are Cheetah template files.  These are used to generate C++ code.  These templates are compiled as part of the XMDS2 build process to ``.py`` files of the same name.  Do not edit the generated ``.py`` files, always edit the ``.tmpl`` files and regenerate the corresponding ``.py`` files with ``make``.
+
+* ``xpdeint/``: 
+	* ``Features/``: Code for all ``<feature>`` elements, such as ``<globals>`` and ``<auto_vectorise>``
+		* ``Transforms/``: Code for the Fourier and matrix-based transforms (including MPI variants).
+	* ``Geometry/``: Code for describing the geometry of simulation dimensions and domains.  Includes code for ``Geometry``, ``Field`` and all ``DimensionRepresentations``.
+	* ``Operators/``: Code for all ``<operator>`` elements, including ``IP``, ``EX`` and the temporal derivative operator ``DeltaA``.
+	* ``Segments/``: Code for all elements that can appear in a ``<segments>`` tag.  This includes ``<integrate>``, ``<filter>``, and ``<breakpoint>``.
+		* ``Integrators``: Code for fixed and adaptive integration schemes, and all steppers (e.g. ``RK4``, ``RK45``, ``RK9``, etc.)
+	* ``Stochastic/``: Code for all random number generators and the random variables derived from them.
+		* ``Generators/``: Code for random number generators, includes ``dSFMT``, ``POSIX``, ``Solirte``.
+		* ``RandomVariables/``: Code for the random variables derived from the random number generators.  These are the gaussian, poissonian and uniform random variables.
+	* ``SimulationDrivers/``: Code for all ``<driver>`` elements.  In particular, this is where the location of MPI and multi-path code.
+	* ``Vectors/``: Code for all ``<vector>`` elements, and their initialisation.  This includes normal ``<vector>`` elements as well as ``<computed_vector>`` and ``<noise_vector>`` elements.
+	* ``includes/``: C++ header and sources files used by the generated simulations.
+	* ``support/``: Support files
+		* ``wscript``: ``waf`` build script for configuring and compiling generated simulations
+		* ``xpdeint.rnc``: Compact RelaxNG XML validation for XMDS scripts.  This is the source file for the XML RelaxNG file ``xpdeint.rng``
+		* ``xpdeint.rng``: RelaxNG XML validation for XMDS scripts.  To regenerate this file from ``xpdeint.rnc``, just run ``make`` in this directory.
+	* ``waf/``: Our included version of the Python configuration and build tool ``waf``.
+	* ``waf_extensions/``: ``waf`` tool for compiling Cheetah templates.
+	* ``xsil2graphics2/``: Templates for the output formats supported by ``xsil2graphics2``.
+	* ``wscript``: ``waf`` build script for XMDS2 itself.
+	* ``CodeParser.py``: Minimally parses included C++ code for handling nonlocal dimension access, IP/EX operators and IP operator validation.
+	* ``Configuration.py``: Manages configuration and building of generated simulations.
+	* ``FriendlyPlusStyle.py``: Sphinx plug-in to improve formatting of XMDS scripts in user documentation.
+	* This directory also contains code for the input script parser, code blocks, code indentation, and the root ``_ScriptElement`` class.
+
+
+Support files
+~~~~~~~~~~~~~
+
+* ``admin/``: Documentation source, Linux installer and release scripts.
+	* ``developer-doc-source/``: source for epydoc python class documentation (generated from python code).
+	* ``userdoc-source/``: source for the user documentation (results visible at www.xmds.org and xmds2.readthedocs.org).
+	* ``xpdeint.tmbundle/``: TextMate support bundle for Cheetah templates and XMDS scripts
+* ``bin/``: Executable scripts to be installed as part of XMDS2 (includes ``xmds2`` and ``xsil2graphics2``).
+* ``examples/``: Example XMDS2 input scripts demonstrating most of XMDS2's features.
+* ``testsuite/``: Testsuite of XMDS2 scripts.  Run the testsuite by executing ``./run_tests.py``
\ No newline at end of file
diff --git a/documentation/_sources/documentation_toc.txt b/documentation/_sources/documentation_toc.txt
new file mode 100644
index 0000000..bfb1f30
--- /dev/null
+++ b/documentation/_sources/documentation_toc.txt
@@ -0,0 +1,33 @@
+.. _Documentation:
+
+Welcome to the documentation for XMDS2!
+=======================================
+
+.. toctree::
+   :maxdepth: 2
+   
+   introduction
+   
+   installation
+
+   tutorial
+   
+   worked_examples
+
+   reference_index
+   
+   advanced_topics
+   
+   faq
+   
+   upgrade
+   
+   optimisation_hints
+   
+   xsil2graphics2
+
+   developer
+
+   licensing
+   
+   news
diff --git a/documentation/_sources/faq.txt b/documentation/_sources/faq.txt
new file mode 100644
index 0000000..5ab1d77
--- /dev/null
+++ b/documentation/_sources/faq.txt
@@ -0,0 +1,64 @@
+.. _FAQ:
+
+Frequently Asked Questions
+==========================
+
+XMDS scripts look complicated! How do I start?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you're unfamiliar with XMDS2, writing a script from scratch might seem difficult. In most cases, however, the best approach is to take an existing script and modify it for your needs. At the most basic level, you can simply take a script from the /examples directory that is similar to what you want to do, change the name of the integration variable(s) and replace the line describing the differential equation to use your DE instead. That's all you need to do, and will ensure all the sy [...]
+
+You can then incrementally change things such as the number of output points, what quantities get output, number of grid points, and so on. Many XMDS2 users have never written a script from scratch, and just use their previous scripts and example scripts as a scaffold when they create a script for a new problem.
+
+
+Where can I get help?
+~~~~~~~~~~~~~~~~~~~~~
+
+The documentation on this website is currently incomplete, but it still covers a fair bit and is worth reading. Similarly, the example scripts in the /examples directory cover most of the functionality of XMDS2, so it's worth looking looking through them to see if any of them do something similar to what you're trying to do.
+
+You should also feel free to email questions to the XMDS users' mailing list at xmds-users at lists.sourceforge.net, where the developers and other users can assist you. You can join the mailing list by going to http://sourceforge.net/projects/xmds/ and clicking on "mailing lists." Also, if you look through the mailing list archives, your particular problem may already have been discussed.
+
+
+How should I cite XMDS2?
+~~~~~~~~~~~~~~~~~~~~~~~~
+If you publish work that has involved XMDS2, please cite it as: `Comput. Phys. Commun. 184, 201-208 (2013) <http://dx.doi.org/10.1016/j.cpc.2012.08.016>`_.
+
+
+I think I found a bug! Where should I report it?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Please report bugs to the developer mailing list at xmds-devel at lists.sourceforge.net. In your email, please include a description of the problem and attach the XMDS2 script that triggers the bug.
+
+
+How do I put time dependence into my vectors?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Standard vectors can't have time dependence (or, more accurately, depend on the ``propagation_dimension`` variable), but computed vectors can. So, for example, if you have set your ``propagation_dimension`` as "t", you can simply use the variable "t" in your computed vector and it will work. 
+
+Alternatively, you can explicitly use the ``propagation_dimension`` variable in your differential equation inside the ``<operators>`` block.  
+
+
+Can I specify the range of my domain and number of grid points at run-time?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Yes, you can. In your script, specify the domain and number of grid points as arguments to be passed in at run-time, use those variables in your ``<geometry>`` block rather than explicitly specifying them, and use the ``<validation kind="run-time" />`` feature. See the :ref:`Validation <Validation>` entry in the Reference section for an example.
+
+While the domain can always be specified in this way, specifying the lattice size at run-time is currently only allowed with the following transforms: 'dct', 'dst', 'dft' and 'none' (see :ref:`Transforms <Validation>` in the Reference section).
+
+Also note that for some multi-dimensional spaces using different transforms, XMDS2 will sometimes optimise the code it generates based on the relative sizes of the dimensions. If one or more of the lattices are specified at run-time it is unable to do this and will have to make guesses. In some situations this may result in slightly slower code.
+
+
+When can I use IP operators (and why should I) and when must I use EX operators?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+An :ref:`<operator><OperatorNamesElement>` that specifies named operators to be used in integration equations can have the ``kind="IP"`` or ``kind="EX"`` attribute, standing for 'interaction picture' and 'explicit' operators respectively.  Explicit operators can be used in all situations, and simply construct and calculate a new vector of the form in the square brackets.  IP operators use less memory and can improve speed by allowing larger timesteps, but have two important restrictions. [...]
+
+Some explanation is in order.  The IP algorithm applies the operator separately to the rest of the evolution.  The reason this can be so effective is that the separate evolution can be performed exactly.  The solution of the equation :math:`\frac{d \psi}{dt} = L \psi` is :math:`\psi(t+\Delta t) = exp(L \Delta t) \psi(t)` for arbitrarily large timestep :math:`\Delta t`.  For a diagonal linear ``L``, the matrix exponential is straightforward.  Also, when it is constant, then the exponentia [...]
+
+Therefore, the limitations of IP operators themselves means that they can only be applied to to named components of one of the integration vectors, and not functions of those components.  Furthermore, an IP operator acting on a component must only be used in the derivative for that particular component.  Secondly, due to the implementation of IP operators in XMDS2, it is not safe to use them in comments, or in conjunction with declared variables.  It is also not safe to multiply or divid [...]
+
+
+Visual Editors
+~~~~~~~~~~~~~~
+
+In this section goes stuff about how to set up TextMate (or other editors to highlight xpdeint scripts).
diff --git a/documentation/_sources/index.txt b/documentation/_sources/index.txt
new file mode 100644
index 0000000..23f0b57
--- /dev/null
+++ b/documentation/_sources/index.txt
@@ -0,0 +1,17 @@
+.. xpdeint documentation master file, created by sphinx-quickstart on Tue Nov 18 15:10:03 2008.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+Welcome to XMDS2!
+=================
+
+This website provides the documentation for XMDS2 (an all-new version of :ref:`XMDS<XMDSHistory>`), a software package that allows the fast and easy solution of sets of ordinary, partial and stochastic differential equations, using a variety of efficient numerical algorithms.
+
+If you publish work that has involved XMDS2, please cite it as `Comput. Phys. Commun. 184, 201-208 (2013) <http://dx.doi.org/10.1016/j.cpc.2012.08.016>`_.
+
+Getting Started
+---------------
+
+To get a flavour of what XMDS2 can do, take a look at our :ref:`Quickstart Tutorial<QuickstartTutorial>`, then take a look at our comprehensive  :ref:`documentation<Documentation>`.  Automated installers are available for Linux and Mac OS X, refer to our :ref:`installation instructions<Installation>` for details.
+
+.. include:: news.rst 
\ No newline at end of file
diff --git a/documentation/_sources/installation.txt b/documentation/_sources/installation.txt
new file mode 100644
index 0000000..5555cdf
--- /dev/null
+++ b/documentation/_sources/installation.txt
@@ -0,0 +1,251 @@
+.. _Installation:
+
+************
+Installation
+************
+
+**XMDS2** can be installed on any unix-like system including Linux, Tru64, and Mac OS X.  It requires a C++ compiler, python, and several installed packages.  Many of these packages are optional, but a good idea to obtain full functionality.  
+
+Installers
+==========
+
+The easiest way to get started is with an installer.  If we don't have an installer for your system, follow the :ref:`manual installation <ManualInstallation>` instructions.
+
+.. tabularcolumns:: |c|c|c|
+
+.. list-table::
+    :widths: 15, 5, 5
+    :header-rows: 0
+
+    * - Linux (Ubuntu/Debian/Fedora/RedHat)
+
+      - `Download Linux Installer <http://svn.code.sf.net/p/xmds/code/trunk/xpdeint/admin/linux_installer.sh>`_
+
+      - :ref:`Learn more <linux_installation>`
+
+    * - OS X 10.6/10.7
+
+      - `Download OS X Installer <http://sourceforge.net/projects/xmds/files>`_
+
+      - :ref:`Learn more <mac_installation>`
+        
+    * - Other systems
+
+      - :ref:`Install from source <ManualInstallation>`
+      
+      -
+
+If you have one of the supported operating systems listed above, but you find the installer doesn't work for you, please let us know by emailing xmds-devel <at> lists.sourceforge.net. If you'd like to tweak the linux installer to work on a distribution we haven't tested, we'd love you to do that and let us know!
+
+.. _linux_installation:
+
+Linux installer instructions
+============================
+
+The linux installer has currently only been tested with Ubuntu, Debian, Fedora, and Red Hat. Download the installer here: http://svn.code.sf.net/p/xmds/code/trunk/xpdeint/admin/linux_installer.sh
+
+Once you have downloaded it, make the installer executable and run it by typing the following into a terminal::
+
+  chmod u+x linux_installer.sh
+  ./linux_installer.sh
+
+Alternatively, if you wish to download and run the installer in a single step, you can use the following command::
+
+  /bin/bash -c "$(wget -qO - http://svn.code.sf.net/p/xmds/code/trunk/xpdeint/admin/linux_installer.sh)"
+
+The linux installer installs all XMDS2 dependencies from your native package manager where possible (``apt-get`` for Ubuntu/Debian, ``yum`` for Fedora/Red Hat) but will download and compile the source code for libraries not available through the package manager. This means you'll need to be connected to the internet when running the installer. The installer should not be run with administrative privileges; it will ask you to enter your admin password at the appropriate point. 
+
+For instructions on how to install XMDS2 on systems where you lack administrative rights, see :ref:`ManualInstallation`.
+
+By default, this installer will install a known stable version of XMDS, which can be updated at any time by navigating to the XMDS directory and typing 'make update'. To install the latest developer version at the beginning, simply run the installer with the ``--develop`` option.
+
+Once XMDS2 has been installed, you can run it from the terminal by typing ``xmds2``. See the :ref:`QuickStartTutorial` for next steps.
+
+
+.. _mac_installation:
+
+Mac OS X Installation
+=====================
+
+Download
+--------
+
+Mac OS X 10.6 (Snow Leopard) or later XMDS 2 installer: http://sourceforge.net/projects/xmds/files/
+
+
+
+Using the Mac OS X Installer
+----------------------------
+
+A self-contained installer for Mac OS X 10.6 (Snow Leopard) and later is available from the link above. This installer is only compatible with Intel Macs.  This means that the older PowerPC architecture is *not supported*.  Xcode (Apple's developer tools) is required to use this installer. Xcode is available for free from the Mac App Store for 10.7 or later, and is available on the install disk of earlier Macs as an optional install.  For users of earlier operating systems (10.6.8 or ear [...]
+
+Once you have downloaded the XMDS installer, installation is as simple as dragging it to your Applications folder or any other location.  Click the XMDS application to launch it, and press the "Launch XMDS Terminal" button to open a Terminal window customised to work with XMDS.  The first time you do this, the application will complete the installation process.  This process can take a few minutes, but is only performed once.
+
+The terminal window launched by the XMDS application has environment variables set for using this installation of XMDS.  You can run XMDS in this terminal by typing ``xmds2``.  See the :ref:`QuickStartTutorial` for next steps.
+
+To uninstall XMDS, drag the XMDS application to the trash. XMDS places some files in the directory ``~/Library/XMDS``. Remove this directory to completely remove XMDS from your system.
+
+This package includes binaries for `OpenMPI <http://www.open-mpi.org>`_, `FFTW <http://www.fftw.org>`_, `HDF5 <http://www.hdfgroup.org/HDF5>`_ and `GSL <http://www.gnu.org/software/gsl>`_. These binaries are self-contained and do not overwrite any existing installations.
+
+.. _ManualInstallation:
+
+Manual installation from source
+===============================
+
+This installation guide will take you through a typical full install step by step. A large part of this procedure is obtaining and installing other libraries that XMDS2 requires, before installing XMDS2 itself. 
+
+While the instructions below detail these packages individually, if you have administrative privileges (or can request packages from your administrator) and if you are using an Ubuntu, Debian, Fedora or Red Hat linux distribution, you can install all required and optional dependencies (but not XMDS2 itself) via
+
+Ubuntu / Debian::
+
+  sudo apt-get install build-essential subversion libopenmpi-dev openmpi-bin python-dev python-setuptools python-cheetah python-numpy python-pyparsing python-lxml python-mpmath libhdf5-serial-dev libgsl0-dev python-sphinx python-h5py libatlas-base-dev
+
+Fedora / Red Hat::
+
+  sudo yum install gcc gcc-c++ make automake subversion openmpi-devel python-devel python-setuptools python-cheetah numpy gsl-devel python-sphinx libxml2-devel libxslt-devel atlas-devel hdf5-devel pyparsing pyparsing python-lxml python-mpmath h5py
+
+You will still have to download and build FFTW 3.3 from source (see below) since prebuilt packages with MPI and AVX support are not currently available in the repositories.
+
+Also note that this guide adds extra notes for users wishing to install XMDS2 using the SVN repository.  This requires a few extra steps, but allows you to edit your copy, and/or update your copy very efficiently (with all the usual advantages and disadvantages of using unreleased material).
+
+0. You will need a copy of XMDS2.  
+    The current release can be found at `Sourceforge <http://sourceforge.net/projects/xmds/>`_, and downloaded as a single file.
+    Download this file, and expand it in a directory where you want to keep the program files.
+    
+    * Developer-only instructions: You can instead check out a working copy of the source using SVN. 
+      In a directory where you want to check out the repository, run:
+      ``svn checkout https://svn.code.sf.net/p/xmds/code/trunk/xpdeint .``
+
+      (Only do this once.  To update your copy, type ``svn up`` or ``make update`` in the same directory, and then repeat any developer-only instructions below).
+    
+#. You will need a working C++ compiler.  
+    For Mac OS X, this means that the developer tools (XCode) should be installed.
+    One common free compiler is `gcc <http://gcc.gnu.org/>`_.  It can be downloaded using your favourite package manager.
+    XMDS2 can also use Intel's C++ compiler if you have it. 
+    Intel's compiler typically generates faster code than gcc, but it isn't free.
+
+#. You will need a `python distribution <http://www.python.org/>`_.  
+
+   * Mac OS X: It is pre-installed on Mac OS X 10.5 or later.
+   * Linux: It should be pre-installed. If not, install using your favourite package manager.
+   
+    We require python 2.4 or greater. XMDS2 does not support Python 3.
+   
+
+#. Install setuptools.
+    If you have root (sudo) access, the easy way to install this is by executing
+    ez_setup.py from the repository. Simply type ``sudo python ez_setup.py``
+
+       If you want to install into your home directory without root access, this is more complex:
+       
+       a) First create the path ~/lib/python2.5/site-packages (assuming you installed python version 2.5) and ~/bin
+          Add "export PYTHONPATH=~/lib/python2.5/site-packages:$PYTHONPATH" and "export PATH=~/bin:$PATH" (if necessary)
+          to your .bashrc file (and run ". ~/.bashrc")
+       
+       b) If necessary install setuptools, by executing ez_setup.py from the repository.
+          ``python ez_setup.py --prefix=~``
+          
+    If you use Mac OS X 10.5 or later, or installed the Enthought Python Distribution on Windows, then setuptools is already installed.
+    Though if the next step fails, you may need to upgrade setuptools.  To do that, type ``sudo easy_install -U setuptools``
+
+#. Install HDF5 and FFTW3 (and optionally MPI).
+    .. _hdf5_Installation:
+    
+    #. **HDF5** is a library for reading and writing the `Hierarchical Data Format <http://www.hdfgroup.org/HDF5/>`_.
+         This is a standardised data format which it is suggested that people use in preference to the older 'binary' output (which is 
+         compatible with xmds-1). The advantage of HDF5 is that this data format is understood by a variety of other tools. xsil2graphics2
+         provides support for loading data created in this format into Mathematica and Matlab.
+         
+         XMDS2 only requires the single process version of HDF5, so there is no need to install the MPI version.
+       
+         \* Sidebar: Installing HDF5 from source follows a common pattern, which you may find yourself repeating later:  
+         
+            #. After extracting the source directory, type ``configure`` and then add possible options.
+            
+                (For HDF5, install with the ``--prefix=/usr/local/`` option if you want XMDS2 to find the library automatically.  This is rarely needed for other packages.)
+                
+            #. Once that is finished, type ``make``.  Then wait for that to finish, which will often be longer than you think.
+            
+            #. Finally, type ``sudo make install`` to install it into the appropriate directory.
+        
+    #. **FFTW** is the library XMDS2 uses for Fourier transforms. 
+         This is the transform most people will use in their simulations. If you need
+         support for MPI distributed simulations, you must configure FFTW to use MPI.
+  
+         FFTW is available for free at the `FFTW website <http://www.fftw.org/>`_.
+         To configure and compile it, follow the steps described in the HDF5 sidebar above.  
+         You may wish to add the ``--enable-mpi --disable-fortran`` options to the ``configure`` command.
+
+    #. **MPI** is an API for doing parallel processing.
+         XMDS2 can use MPI to parallelise simulations on multi-processor/multi-core computers, or clusters of computers.
+         Many supercomputing systems come with MPI libraries pre-installed.
+         The `Open MPI <http://www.open-mpi.org/>`_ project has free distributions of this library available.
+		 
+	 If you intend to take advantage of XMDS2's multi-processing features, you must install MPI, and configure FFTW3 to use it.
+
+
+
+#. There are a range of optional installs.  We recommend that you install them all if possible:
+
+    #. A Matrix library like `ATLAS <http://math-atlas.sourceforge.net/>`_, Intel's `MKL <http://software.intel.com/en-us/intel-mkl/>`_ or the `GNU Scientific library (GSL) <http://www.gnu.org/software/gsl/>`_ 
+         These libraries allow efficient implementation of transform spaces other than Fourier space.
+         Mac OS X comes with its own (fast) matrix library.
+    
+    #. **numpy** is a tool that XMDS2 uses for automated testing.
+         It can be installed with ``sudo easy_install numpy``. 
+         
+         Mac OS X 10.5 and later come with numpy.
+         
+    #. **lxml** is used to validate the syntax of scripts passed to XMDS2. 
+         If you have root access, this can be installed with the command ``sudo easy_install lxml``
+
+         You will need to have 'libxml2' and 'libxslt' installed (via your choice of package manager) to install lxml.  
+         Sufficient versions are preinstalled on Mac OS X 10.6.
+
+         If you don't have root access or want to install into your home directory, use:
+            ``easy_install --prefix=~ lxml``
+
+    #. **h5py** is needed for checking the results of XMDS2 tests that generate HDF5 output.
+           h5py requires numpy version 1.0.3 or later. 
+           
+           Upgrading `h5py <http://h5py.alfven.org/>`_ on Mac OS X is best done with the source of the package, as the easy_install option can get confused with multiple numpy versions.
+           (Mac OS X Snow Leopard comes with version 1.2.1). 
+           After downloading the source, execute ``python ./setup.py build`` in the source directory, and then ``python ./setup.py install`` to install it.  
+
+#. Install XMDS2 into your python path by running (in the xmds-2.1.4/ directory):
+    ``sudo ./setup.py develop``
+
+    If you want to install it into your home directory, type ``./setup.py develop --prefix=~``
+    
+    This step requires access to the net, as it downloads any dependent packages.  If you are behind a firewall, you may need to set your HTTP_PROXY environment variable in order to do this.
+
+    * Developer only instructions: 
+        The Cheetah templates (\*.tmpl) must be compiled into python.
+        To do this, run ``make`` in the xmds-2.1.4/ directory.
+
+    * Developer-only instructions: 
+        If you have 'numpy' installed, test XMDS2 by typing ``./run_tests.py`` in the xmds-2.1.4/ directory.
+        The package 'numpy' is one of the optional packages, with installation instructions below.
+       
+    * Developer-only instructions: 
+        To build the user documentation, you first need to install sphinx, either via your package manager or:
+        ``sudo easy_install Sphinx``
+
+        Then, to build the documentation, in the xmds-2.1.4/admin/userdoc-source/ directory run: ``make html``
+
+        If this results in an error, you may need to run ``sudo ./setup.py develop``
+
+        The generated html documentation will then be found at xmds-2.1.4/documentation/index.html
+		
+#. Configure XMDS2 by typing ``xmds2 --reconfigure``.  If XMDS2 is unable to find a library, you can tell XMDS2 where these libraries are located by adding ``include`` and ``lib`` search paths using the ``--include-path`` and ``--lib-path`` options.  For example, if FFTW3 is installed in ``/apps/fftw3`` with headers in ``/apps/fftw3/include/`` and the libraries in ``/apps/fftw3/lib``, (re)configure XMDS2 by typing:
+
+	* ``xmds2 --reconfigure --include-path /apps/fftw3/include --lib-path /apps/fftw3/lib``.
+	
+	If you need to use additional compiler or link flags for XMDS2 to use certain libraries, set the ``CXXFLAGS`` or ``LINKFLAGS`` environment variables before calling ``xmds2 --reconfigure``.  For example, to pass the compiler flag ``-pedantic`` and the link flag ``-lm``, use:
+	
+	* ``CXXFLAGS="-pedantic" LINKFLAGS="-lm" xmds2 --reconfigure``.
+
+**Congratulations!** You should now have a fully operational copy of xmds2 and xsil2graphics2.  You can test your copy using examples from the "xmds-2.1.4/examples" directory, and follow the worked examples in the :ref:`QuickStartTutorial` and :ref:`WorkedExamples`.
+
+
+
diff --git a/documentation/_sources/introduction.txt b/documentation/_sources/introduction.txt
new file mode 100644
index 0000000..d1a3169
--- /dev/null
+++ b/documentation/_sources/introduction.txt
@@ -0,0 +1,31 @@
+Introduction
+============
+
+Welcome to **XMDS2** (codenamed `xpdeint`), which is an all-new version of :ref:`XMDS<XMDSHistory>`.  Prepare for fast, easily-extended simulations with minimal code error.
+
+**Description:**   The purpose of XMDS2 is to simplify the process of creating simulations that solve systems of initial-value first-order partial and ordinary differential equations. Instead of going through the error-prone process of writing by hand thousands of lines of code, XMDS2 enables many problems to be described in a simple XML format. From this XML description XMDS2 writes a C++ simulation that solves the problem using fast algorithms. Anecdotally, the code generated by XMDS2  [...]
+
+XMDS2 can be used to simulate almost any set of (coupled) (partial) (stochastic) differential equations in any number of dimensions.  It can input and output data in a range of data formats, produce programs that can take command-line arguments, and produce parallelised code suitable for either modern computer architectures or distributed clusters.
+
+If this is your first time with XMDS, then an ideal place to start is the :ref:`QuickStartTutorial`, where we will show you how to write a basic simulation.  :ref:`Installation` instructions should get you up and running and able to start playing with the large library of examples provided. The impatient will probably have good luck browsing the examples library included with the source, and the :ref:`WorkedExamples` in this documentation for something that looks like their intended simulation.
+
+If you are upgrading from **XMDS version 1.x**, then after following the installation instructions (:ref:`Installation`), you might want to have a quick read of the note for upgraders (:ref:`UpgradeFromXMDS1`).  The syntax of the XML scripts has changed, but hopefully you will find the new scripts very intuitive.
+
+Detailed advice on input/output issues, and ways to code more complicated simulations can be found in :ref:`AdvancedTopics`.
+
+XMDS2 should be cited as `Comput. Phys. Commun. 184, 201-208 (2013) <http://dx.doi.org/10.1016/j.cpc.2012.08.016>`_.
+
+.. _XMDSHistory:
+
+**History:**   **XMDS** was created in 1997 by Peter Drummond and Greg Collecutt, who conceived of the idea of using an XML-based code generator to simplify the process of integrating systems of equations with arbitrary dimension [#f1]_.  The first version was written in C, and featured a very flexible, strongly convergent stochastic algorithm: the :ref:`semi-implicit algorithm<SI>` [#f2]_.  Released under a public licence, it began to receive attention across several research groups.  O [...]
+    
+In 2003, the increased scope of the package prompted a complete rewrite by Greg Collecutt (using C++), which lead to **XMDS 1.0**.  It was placed on sourceforge, and over a dozen developers contributed from 2003-2007 to help XMDS address a wider range of problems with a range of modern algorithms and support for parallel supercomputing.  The documentation and installation method was improved enabling the software to be used in a wider context, and XMDS gained many users from across the w [...]
+    
+In 2008 a second complete rewrite was undertaken, largely by Graham Dennis (using Cheetah templates in python), leading to the current version **XMDS2**.  This restructuring of the internal treatment of XML elements and the generated code allowed a new range of extensions to be explored.  These included possibilities such as integrating multiple fields with different dimensionality, a more general set of differential equations that can be solved efficiently, and multiple choices of trans [...]
+
+
+.. rubric:: Footnotes
+
+.. [#f1] G.R.Collecutt and P.D.Drummond, `Xmds: eXtensible multi-dimensional simulator`, Comput. Phys. Commun. **142**, 219 (2001).
+
+.. [#f2] M.J.Werner and P.D.Drummond, `Robust algorithms for solving stochastic partial differential equations`, J. Comput. Phys. **132**, 312 (1997).
\ No newline at end of file
diff --git a/documentation/_sources/licensing.txt b/documentation/_sources/licensing.txt
new file mode 100644
index 0000000..5eae5ee
--- /dev/null
+++ b/documentation/_sources/licensing.txt
@@ -0,0 +1,10 @@
+.. _Licensing:
+
+Licensing
+=========
+
+XMDS2 is licensed under the GPL version 2 license, which can be found in the COPYING file in the root directory of your XMDS install. You can also find it here: http://www.gnu.org/licenses/
+
+We encourage people to submit patches to us that extend XMDS2's functionality and fix bugs. If you do send us a patch, we do not require copyright assignment, but please include a statement saying you agree to license your code under the GPL v2 license.
+
+
diff --git a/documentation/_sources/news.txt b/documentation/_sources/news.txt
new file mode 100644
index 0000000..78d9e78
--- /dev/null
+++ b/documentation/_sources/news.txt
@@ -0,0 +1,100 @@
+.. _News:
+
+News
+-----
+
+XMDS 2.1.4 "Well if this isn't nice, I don't know what is" (September 27, 2013)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The XMDS 2.1.4 update contains many new improvements and bugfixes:
+
+* *xsil2graphics2* now supports all output formats for MATLAB, Octave and Python.  The scripts generated for MATLAB/Octave are compatible with both.
+* Fix a bug when :ref:`nonlocally<ReferencingNonlocal>` referencing a :ref:`dimension alias<DimensionAliases>` with subsampling in *sampling_group* blocks or in some situations when MPI is used.  This bug caused incorrect elements of the vector to be accessed.
+* Correct the Fourier basis for dimensions using Hermite-Gauss transforms.  Previously 'kx' was effectively behaving as '-kx'.
+* Improve the performance of 'nx' <--> 'kx' Hermite-Gauss transforms.
+* Stochastic error checking with runtime noise generation now works correctly.  Previously different random numbers were generated for the full-step paths and the half-step paths.
+* Documentation updates.
+
+XMDS 2.1.3 "Happy Mollusc" (June 7, 2013)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The XMDS 2.1.3 update is a bugfix release that includes the following improvements:
+
+* XMDS will work when MPI isn't installed (but only for single-process simulations).
+* Support for GCC 4.8
+* The number of paths used by the multi-path driver can now be specified at run-time (using *<validation kind="run-time">*)
+* Other bug fixes
+
+XMDS 2.1.2 "Happy Mollusc" (October 15, 2012)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The XMDS 2.1.2 update has many improvements:
+
+* Named filters.  You can now specify a name for a filter block and call it like a function if you need to execute it conditionally.  See the documentation for the *<filter>* block for more information.
+* New *chunked_output* feature.  XMDS can now output simulation results as it goes, reducing the memory requirement for simulations that generate significant amounts of output.  See the documentation for more details.
+* Improved OpenMP support
+* The EX operator is now faster in the common case (but you should still prefer IP when possible)
+* If seeds are not provided for a *noise_vector*, they are now generated at simulation run-time, so different executions will give different results.  The generated noises can still be found in the output .xsil files enabling results to be reproduced if desired.
+* Advanced feature: Dimensions can be accessed non-locally with the index of the lattice point.  This removes the need in hacks to manually access XMDS's underlying C arrays.  This is an advanced feature and requires a little knowledge of XMDS's internal grid representation.  See the advanced topics documentation for further details.
+* Fixed adaptive integrator order when noises were used in vector initialisation
+* Fix the Spherical Bessel basis.  There were errors in the definition of this basis which made it previously unreliable.
+* Other bug fixes
+
+XMDS 2.1 "Happy Mollusc" (June 14, 2012)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+XMDS 2.1 is a significant upgrade with many improvements and bug fixes since 2.0. We also now have installers for Linux and Mac OS X, so you no longer have to build XMDS from source! See :ref:`here<Installation>` for details about the installers.
+
+Existing users should note that this release introduces a more concise syntax for moment groups.  You can now use::
+
+    <sampling_group initial_sample="yes" basis="x y z">
+        ...
+    </sampling_group>
+
+Instead of::
+
+    <group>
+        <sampling initial_sample="yes" basis="x y z">
+            ...
+        </sampling>
+    </group>
+
+Another syntax change is that the initial basis of a vector should be specified with *initial_basis* instead of *initial_space*.
+
+In both cases, although the old syntax is not described in the documentation, it is still supported, so existing scripts will work without any changes.
+
+
+Other changes in XMDS 2.1 include:
+
+* The *lattice* attribute for dimensions can now be specified at run-time.  Previously only the minimum and maximum values of the domain could be specified at run-time.  See :ref:`here<Validation>` for details.
+* *noise_vectors* can now be used in non-uniform dimensions (e.g. dimensions using the Bessel transform for cylindrical symmetry).
+* "loose" *geometry_matching_mode* for HDF5 vector initialisation.  This enables extending the simulation grid from one simulation to the next, or coarsening or refining a grid when importing.
+* *vectors* can now be initialised by integrating over dimensions of other vectors.  *computed_vectors* always supported this, now *vectors* do too.
+* Update to latest version of waf, which is used for compiling simulations and detecting FFTW, HDF5, etc. This should lead to fewer waf-related problems.
+* Bug fixes.
+
+
+XMDS 2.0 "Shiny!" (September 13, 2010)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+XMDS 2.0 is a major upgrade which has been rewritten from the ground up to make it easier for us to apply new features. And there are many. XMDS 2.0 is faster and far more versatile than previous versions, allowing the efficient integration of almost any initial value problem on regular domains.
+
+The feature list includes:
+
+* Quantities of different dimensionalities. So you can have a 1D potential and a 3D wavefunction.
+* Integrate more than one vector (in more than one geometry), so you can now simultaneously integrate a PDE and a coupled ODE (or coupled PDEs of different dimensions).
+* Non-Fourier transformations including the Bessel basis, Spherical Bessel basis and the Hermite-Gauss (harmonic oscillator) basis.
+* The ability to have more than one kind of noise (gaussian, poissonian, etc) in a simulation.
+* Integer-valued dimensions with non-local access. You can have an array of variables and access different elements of that array.
+* Significantly better error reporting. When errors are found when compiling the script they will almost always be reported with the corresponding line of your script, instead of the generated source.
+* *IP*/*EX* operators are separate from the integration algorithm, so you can have both *IP* and *EX* operators in a single integrate block. Also, *EX* operators can act on arbitrary code, not just vector components. (e.g. *L[phi*phi]*).
+* Cross propagation in the increasing direction of a given dimension or in the decreasing dimension. And you can have more than one cross-propagator in a given integrator (going in different directions or dimensions).
+* Faster Gaussian noises.
+* The ability to calculate spatial correlation functions.
+* OpenMP support.
+* MPI support.
+* Output moment groups use less memory when there isn't a *post_processing* element.
+* Generated source is indented correctly.
+* An *xmds1*-like script file format.
+* *xmds1*-like generated source.
+* All of the integrators from *xmds1* (*SI*, *RK4*, *ARK45*, *RK9*, *ARK89*).
diff --git a/documentation/_sources/optimisation_hints.txt b/documentation/_sources/optimisation_hints.txt
new file mode 100644
index 0000000..912214d
--- /dev/null
+++ b/documentation/_sources/optimisation_hints.txt
@@ -0,0 +1,171 @@
+Optimisation Hints
+===================
+
+There are a variety of things you can do to make your simulations run faster.
+
+Geometry and transform-based tricks
+-----------------------------------
+
+Simpler simulation geometries
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Consider symmetry, can you use ``dct`` transforms or ``bessel`` transforms? Do you really need that many points? How big does your grid need to be? Could absorbing boundary conditions help?
+
+Tricks for Bessel and Hermite-Gauss transforms
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Dimensions using matrix transforms should be first for performance reasons.  Unless you're using MPI, in which case XMDS can work it out for the first two dimensions.  Ideally, XMDS would sort it out in all cases, but it's not that smart yet.
+
+Reduce code complexity
+----------------------
+Avoid transcendental functions like :math:`\sin(x)` or :math:`\exp(x)` in inner loops. Not all operations are made equal, use multiplication over division.
+
+Use the Interaction Picture (IP) operator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Just do it. Only use the EX operator when you have to. If you must use the EX operator, consider making it ``constant="no"``. It uses less memory.
+When you use the IP operator, make sure you know what it's doing.  Do not pre- or post-multiply that term in your equations.
+
+When using the IP operator, check if your operator is purely real or purely imaginary.  If real, (e.g. ``L = -0.5*kx * kx;``), then add the attribute ``type="real"`` to the ``<operator kind="ip">`` tag.  If purely imaginary, use ``type="imaginary"``.  This optimisation saves performing the part of the complex exponential that is unnecessary.
+
+Consider writing the evolution in spectral basis
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Evolution equations do not need to be written in the position basis.  If your equations are diagonal in the spectral basis, then it makes more sense to compute the time derivative terms in that basis.  For example, if you have the system
+
+.. math::
+    \frac{d\psi_1(x)}{dt} &= i \frac{\hbar}{2M} \frac{d^2\psi_1(x)}{dx^2} - i \Omega \psi_2(x)\\
+    \frac{d\psi_2(x)}{dt} &= i \frac{\hbar}{2M} \frac{d^2\psi_2(x)}{dx^2} - i \Omega \psi_1(x)
+
+then this is diagonal in the Fourier basis where it takes the form
+
+.. math::
+    \frac{d\psi_1(k_x)}{dt} &= -i \frac{\hbar k_x^2}{2M} \psi_1(k_x) - i \Omega \psi_2(k_x)\\
+    \frac{d\psi_2(k_x)}{dt} &= -i \frac{\hbar k_x^2}{2M} \psi_2(k_x) - i \Omega \psi_1(k_x)
+
+
+The first term in each evolution equation can be solved exactly with an IP operator, and the second term is diagonal in Fourier space.  This can be written in XMDS as:
+
+.. code-block:: xpdeint
+
+    <operators>
+      <integration_vectors basis="kx">wavefunction</integration_vectors>
+      <operator kind="ip" type="imaginary" >
+        <operator_names>Lxx</operator_names>
+        <![CDATA[
+          Lxx = -i*0.5*hbar_M*(kx*kx);
+        ]]>
+      </operator>
+      <![CDATA[
+
+        dpsi0_dt = Lxx[psi0] - i*Omega*psi1;
+        dpsi1_dt = Lxx[psi1] - i*Omega*psi0;
+          
+      ]]>
+    </operators>
+
+Although the ``dpsi0_dt`` code reads the same in position and Fourier space, it is the ``basis=kx`` attribute on ``<integration_vectors>`` that causes the evolution code to be executed in Fourier space.  
+
+A final optimisation is to cause the integration code itself to operate in Fourier space.  By default, all time stepping (i.e. :math:`f(t + \Delta t) = f(t) + f'(t) \Delta t` for forward-Euler integration) occurs in the position space.  As the derivative terms can be computed in Fourier space, it is faster to also to the time stepping in Fourier space too.  This then means that no Fourier transforms will be needed at all during this integrate block (except as needed by sampling).  To cau [...]
+
+The fully optimised code then reads:
+
+.. code-block:: xpdeint
+
+    <integrate algorithm="ARK45" interval="1" tolerance="1e-6" home_space="k">
+      <samples> 10 </samples>
+      <operators>
+        <integration_vectors basis="kx">wavefunction</integration_vectors>
+        <operator kind="ip" type="imaginary" >
+          <operator_names>Lxx</operator_names>
+          <![CDATA[
+            Lxx = -i*0.5*hbar_M*(kx*kx);
+          ]]>
+        </operator>
+        <![CDATA[
+
+          dpsi0_dt = Lxx[psi0] - i*Omega*psi1;
+          dpsi1_dt = Lxx[psi1] - i*Omega*psi0;
+          
+        ]]>
+      </operators>
+    </integrate>
+
+This code will not use any Fourier transforms during an ordinary time-stepping, and will be much faster than if the code were written without the ``home_space`` and ``basis`` attributes.
+
+Don't recalculate things you don't have to
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Use ``computed_vectors`` appropriately.
+
+
+Compiler and library tricks
+---------------------------
+
+Faster compiler
+^^^^^^^^^^^^^^^
+If you're using an Intel CPU, then you should consider using their compiler, icc. They made the silicon, and they also made a compiler that understands how their chips work significantly better than the more-portable GCC.
+
+Faster libraries
+^^^^^^^^^^^^^^^^
+Intel MKL is faster than ATLAS, which is faster than GSL CBLAS. If you have a Mac, then Apple's vecLib is plenty fast.
+
+Auto-vectorisation
+^^^^^^^^^^^^^^^^^^
+Auto-vectorisation is a compiler feature that makes compilers generate more efficient code that can execute the same operation on multiple pieces of data simultaneously. To use this feature, you need to add the following to the ``<features>`` block at the start of your simulation:
+
+.. code-block:: xpdeint
+    
+    <auto_vectorise />
+
+This will make xpdeint generate code that is more friendly to compiler's auto-vectorisation features so that more code can be vectorised. It will also add the appropriate compiler options to turn on your compiler's auto-vectorisation features. For auto-vectorisation to increase the speed of your simulations, you will need a compiler that supports it such as gcc 4.2 or later, or Intel's C compiler, ``icc``.
+
+OpenMP
+^^^^^^
+`OpenMP <http://openmp.org>`_ is a set of compiler directives to make it easier to use threads (different execution contexts) in programs. Using threads in your simulation does occur some overhead, so for the speedup to outweigh the overhead, you must have a reasonably large simulation grid. To add these compiler directives to the generated simulations, add the tag ``<openmp />`` in the ``<features>`` block. This can be used in combination with the auto-vectorisation feature above. Note  [...]
+
+If you are using the OpenMP feature and are using `FFTW <http://www.fftw.org>`_-based transforms (Discrete Fourier/Cosine/Sine Transforms), you should consider using threads with your FFT's by adding the following to the ``<features>`` block at the start of your simulation:
+
+.. code-block:: xpdeint
+    
+    <fftw threads="2" />
+
+Replace the number of threads in the above code by the number of threads that you want to use.
+
+Parallelisation with MPI
+^^^^^^^^^^^^^^^^^^^^^^^^
+Some simulations are so large or take so much time that it is not reasonable to run them on a single CPU on a single machine. Fortunately, the `Message Passing Interface <http://www.mpi-forum.org/>`_ was developed to enable different computers working on the same program to exchange data. You will need a MPI package installed to be abel to use this feature with your simulations. One popular implementation of MPI is `OpenMPI <http://www.open-mpi.org>`_.
+
+
+Atom-optics-specific hints
+--------------------------
+
+Separate out imaginary-time calculation code
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When doing simulations that require the calculation of the groundstate (typically via the imaginary time algorithm), typically the groundstate itself does not need to be changed frequently as it is usually the dynamics of the simulation that have the interesting physics. In this case, you can save having to re-calculate groundstate every time by having one script (call it ``groundstate.xmds``) that saves the calculated groundstate to a file using a breakpoint, and a second simulation tha [...]
+
+The file format used in this example is `HDF5 <http://www.hdfgroup.org/HDF5/>`_, and you will need the HDF5 libraries installed to use this example. The alternative is to use the deprecated ``binary`` format, however to load ``binary`` format data ``xmds``, the predecessor to ``xpdeint`` must be installed. Anyone who has done this before will tell you that installing it isn't a pleasant experience, and so HDF5 is the recommended file format.
+
+If your wavefunction vector is called ``'wavefunction'``, then to save the groundstate to the file ``groundstate_break.h5`` in the HDF5 format, put the following code immediately after the integrate block that calculates your groundstate:
+
+.. code-block:: xpdeint
+
+    <breakpoint filename="groundstate_break" format="hdf5">
+      <dependencies>wavefunction</dependencies>
+    </breakpoint>
+
+In addition to the ``groundstate_break.h5`` file, an XSIL wrapper ``groundstate_break.xsil`` will also be created for use with :ref:`xsil2graphics2`.
+
+To load this groundstate into your evolution script, the declaration of your ``'wavefunction'`` vector in your evolution script should look something like
+
+.. code-block:: xpdeint
+
+    <vector name="wavefunction">
+      <components>phi1 phi2</components>
+      <initialisation kind="hdf5">
+        <filename>groundstate_break.h5</filename>
+      </initialisation>
+    </vector>
+
+Note that the groundstate-finder doesn't need to have all of the components that the evolution script needs. For example, if you are considering the evolution of a two-component BEC where only one component has a population in the groundstate, then your groundstate script can contain only the ``phi1`` component, while your evolution script can contain both the ``phi1`` component and the ``phi2`` component. Note that the geometry of the script generating the groundstate and the evolution  [...]
+
+Use an energy or momentum offset
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This is just the interaction picture with a constant term in the Hamiltonian. If your state is going to rotate like :math:`e^{i(\omega + \delta\omega)t}`, then transform your equations to remove the :math:`e^{i \omega t}` term. Likewise for spatial rotations, if one mode will be moving on average with momentum :math:`\hbar k`, then transform your equations to remove that term. This way, you may be able to reduce the density of points you need in that dimension. Warning: don't forget to c [...]
diff --git a/documentation/_sources/reference_elements.txt b/documentation/_sources/reference_elements.txt
new file mode 100644
index 0000000..056d2a5
--- /dev/null
+++ b/documentation/_sources/reference_elements.txt
@@ -0,0 +1,1339 @@
+.. raw:: html
+
+  <style> .attributes-code {color:#0000BB; font-family:'monospace'; font-style:italic} </style>
+
+.. raw:: html
+
+  <style> .attributes-standard {color:#0000BB; font-family:'monospace'; font-style:italic; font-size:smaller} </style>
+
+.. raw:: html
+
+  <style> .smaller-font {font-size:smaller} </style>
+
+.. role:: attributes-code
+.. role:: attributes-standard
+.. role:: smaller-font
+
+.. _ReferenceElements:
+
+*********************
+XMDS2 script elements
+*********************
+
+This section outlines all the elements and options available in an XMDS2 script.  This is very much a **work in progress**, beginning with placeholders in most cases, as we have prioritised the tutorials for new users.  One of the most productive ways that non-developer veterans can contribute to the project is to help develop this documentation.
+
+
+
+
+.. _SimulationElement:
+
+Simulation element
+==================
+
+The ``<simulation>`` element is the single top level element in an XMDS2 simulation, and contains all the other elements.  All XMDS scripts must contain exactly one simulation element, and it must have the ``xmds-version="2"`` attribute defined.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <!-- Rest of simulation goes here -->
+    </simulation>
+
+
+
+
+.. _NameElement:
+
+Name element
+============
+
+The name of your simulation. This element is optional, but recommended. If it is set, it will be the name of the executable file generated from this script. It will also be the name of the output file (with an appropriate extension) if the ``filename`` attribute is not given a value in the ``<output>`` element.
+
+Example syntax::
+
+    <name> funky_solver </name>
+
+
+.. _AuthorElement:
+
+Author element
+==============
+
+The author(s) of this script. This element is optional, but can be useful if you need to find the person who has written an incomprehensible script and thinks comments are for the weak.
+
+Example syntax::
+
+    <author> Ima Mollusc </author>
+
+
+.. _DescriptionElement:
+
+Description element
+===================
+
+A description of what the simulation does. Optional, but recommended, in case you (or someone else) has to revist the script at some distant point in the future.
+
+Example syntax::
+
+    <description>
+      Calculate the 3D ground state of a Rubidium BEC in a harmonic magnetic trap assuming
+      cylindrical symmetry about the z axis and reflection symmetry about z=0.
+      This permits us to use the cylindrical Bessel functions to expand the solution transverse
+      to z and a cosine series to expand the solution along z.
+    </description>
+
+
+
+.. _FeaturesElement:
+
+Features Elements
+=================
+
+
+Features elements are where simulation-wide options are specified. The ``<features>`` element wraps one or more elements describing features. There are many possible feature elements. Currently, a full list of the features supported is:
+
+    * :ref:`arguments <ArgumentsElement>`
+    * :ref:`auto_vectorise <Autovectorise>`
+    * :ref:`benchmark <Benchmark>`
+    * :ref:`bing <Bing>`
+    * :ref:`cflags <CFlags>`
+    * :ref:`chunked_output <ChunkedOutput>`
+    * :ref:`diagnostics <Diagnostics>`
+    * :ref:`error_check <ErrorCheck>`
+    * :ref:`halt_non_finite <HaltNonFinite>`
+    * :ref:`fftw <FFTW>`
+    * :ref:`globals <Globals>`
+    * :ref:`OpenMP <OpenMP>`
+    * :ref:`precision <Precision>`
+    * :ref:`validation <Validation>`
+
+Example syntax::
+
+    <simulation xmds-version="2">
+      <features>
+        <bing />
+        <precision> double </precision>
+        ...
+      </features>
+    </simulation>
+
+
+.. _ArgumentsElement:
+
+Arguments Element
+-----------------
+
+The ``<arguments>`` element is optional, and allows defining variables that can be passed to the simulation at run time. These variables are then globally accessible throughout the simulation script. Each of the variables must be defined in an ``<argument>`` element (see below). The variables can then be passed to the simulation executable as options on the command line. For example, one could define the variables ``size``, ``number``, and ``pulse_shape`` ::
+
+    <name> arguments_test </name>
+    <features>
+      <arguments>
+        <argument name="size" type="real" default_value="20.0"/>
+        <argument name="number" type="integer" default_value="7"/>
+        <argument name="pulse_shape" type="string" default_value="gaussian"/>
+      </arguments>
+    </features>
+
+When ``XMDS2`` is run on this script the executable ``arguments_test`` is created. The values of ``size``, ``number``, and ``pulse_shape`` can then be set to whatever is desired at runtime via
+
+::
+
+  ./arguments_test --size=1.3 --number=2 --pulse_shape=lorentzian
+
+It is also possible to include an optional ``CDATA`` block inside the ``<arguments>`` block. This code will run after the arguments have been initialised with the values passed from the command line. This code block could be used, for example, to sanity check the parameters passed in, or for assigning values to global variables based on those parameters.  Any references to variables defined in an ``<argument>`` element should be made here rather than in the :ref:`Globals<globals>` elemen [...]
+
+    <features>
+      <globals>
+        <![CDATA[
+          real atom_kick;
+        ]]>
+      <globals>
+      <arguments>
+        <argument name="bragg_order" type="integer" default_value="2"/>
+        <![CDATA[
+          atom_kick = bragg_order * 2*M_PI / 780e-9;
+        ]]>
+      </arguments>
+    </features>
+
+.. _ArgumentElement:
+
+Argument element
+~~~~~~~~~~~~~~~~
+
+
+Each ``<argument>`` element describes one variable that can be passed to the simulation at runtime via the command line. There are three mandatory attributes: ``name``, ``type``, and ``default_value``. ``name`` is the name by which you can refer to that variable later in the script, as well as the name of the command line parameter. ``type`` defines the data type of the variable, and ``default_value`` is the value to which the variable is set if it is not given a value on the command line.
+
+
+.. _AutoVectorise:
+
+Auto_vectorise element
+----------------------
+
+The ``<auto_vectorise />`` feature attempts to activate automatic vectorisation for large loops, if it is available in the compiler.  This should make some simulations go faster.
+
+
+.. _Benchmark:
+
+Benchmark
+---------
+
+The ``<benchmark />`` feature includes a timing routine in the generated code, so that it is possible to see how long the simulations take to run.
+
+
+.. _Bing:
+
+Bing
+----
+
+The ``<bing />`` feature causes the simulation to make an invigorating sound when the simulation finishes executing.
+
+
+.. _CFlags:
+
+C Flags
+-------
+
+The ``<cflags>`` feature allows extra flags to be passed to the compiler.  This can be useful for optimisation, and also using specific external libraries.  The extra options to be passed are defined with a 'CDATA' block.  The compile options can be made visible by running XMDS2 either with the "-v" (verbose) option, or the "-g" (debug) option.
+
+Example syntax::
+
+    <cflags>
+        <![CDATA[
+            -O4
+        ]]>
+    </cflags>
+
+
+.. _ChunkedOutput:
+
+Chunked Output
+--------------
+
+By default, XMDS2 keeps the contents of all output moment groups in memory until the end of the simulation when they are written to the output file.  This can be a problem if your simulation creates a very large amount of output.  ``<chunked_output />`` causes the simulation to save the output data in chunks as the simulation progresses.  For some simulations this can significantly reduce the amount of memory required.  The amount of data in a chunk can be specified with the ``size`` att [...]
+
+Limitations (XMDS will give you an error if you violate any of these):
+
+* This feature cannot be used with the ASCII output file format due to limitations in the file format.
+* This feature cannot be used with the ``multi-path`` drivers because all sampling data is required to compute the mean and standard error statistics.
+* Neither is this feature compatible with the ``error_check`` feature as that relies on all sampling data being available to compute the error.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <features>
+            <chunked_output size="5MB" />
+        </features>
+    </simulation>
+
+.. _Diagnostics:
+
+Diagnostics
+-----------
+
+The ``<diagnostics />`` feature causes a simulation to output more information as it executes.  This should be useful when a simulation is dying / giving bad results to help diagnose the cause.  Currently, it largely outputs step error information.
+
+
+
+.. _ErrorCheck:
+
+Error Check
+-----------
+
+
+It's often important to know whether you've got errors.  This feature runs each integration twice: once with the specified error tolerance or defined lattice spacing in the propagation dimension, and then again with half the lattice spacing, or an equivalently lower error tolerance.  Each component of the output then shows the difference between these two integrations as an estimate of the error.  This feature is particularly useful when integrating stochastic equations, as it treats the [...]
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <features>
+            <error_check />
+        </features>
+    </simulation>
+
+
+.. _HaltNonFinite:
+
+Halt_Non_Finite
+---------------
+
+The ``<halt_non_finite />`` feature is used to stop computations from continuing to run after the vectors stop having numerical values.  This can occur when a number is too large to represent numerically, or when an illegal operation occurs.  Processing variables with non-numerical values is usually much slower than normal processing, and the results are meaningless.  Of course, there is a small cost to introducing a run-time check, so this feature is optional.
+
+
+.. _FFTW:
+
+fftw element
+------------
+
+The ``<fftw \>`` feature can be used to pass options to the `Fast Fourier Transform library <http://fftw.org>`_ used by XMDS.  This library tests algorithms on each architecture to determine the fastest method of solving each problem.  Typically this costs very little overhead, as the results of all previous tests are stored in the directory "~/.xmds/wisdom".  The level of detail for the search can be specified using the ``plan`` attribute, which can take values of ``"estimate"``, ``"mea [...]
+
+Example syntax::
+
+    <fftw plan="patient" threads="3" />
+
+
+.. _Globals:
+
+Globals
+-------
+
+The globals feature places the contents of a 'CDATA' block near the top of the generated program.  Amongst other things, this is useful for defining variables that are then accessible throughout the entire program.
+
+Example syntax::
+
+    <globals>
+      <![CDATA[
+        const real omegaz = 2*M_PI*20;
+        long Nparticles = 50000;
+
+        /* offset constants */
+        real frequency = omegaz/2/M_PI;
+      ]]>
+    </globals>
+
+
+.. _OpenMP:
+
+OpenMP
+------
+
+The ``<openmp />`` feature instructs compatible compilers to parallelise key loops using the `OpenMP API <http://www.openmp.org>`_ standard.  By default the simulation will use all available CPUs.  The number of threads used can be restricted by specifying the number of threads in the script with ``<openmp threads="2"/>``, or by setting the ``OMP_NUM_THREADS`` environment variable at run-time like so::
+
+	OMP_NUM_THREADS=2 ./simulation_name
+
+
+.. _Precision:
+
+Precision
+-----------
+
+This specifies the precision of the XMDS2 ``real`` and ``complex`` datatypes, as well as the precision used when computing transforms. Currently two values are accepted: ``single`` and ``double``. If this feature isn't specified, XMDS2 defaults to using double precision for its variables and internal calculations.
+
+Single precision has approximately 7.2 decimal digits of accuracy, with a minimum value of 1.4×10\ :superscript:`-45` and a maximum of 3.8×10\ :superscript:`34`. Double precision has approximately 16 decimal digits of accuracy, a minimum value of 4.9×10\ :superscript:`-324` and a maximum value of 1.8×10\ :superscript:`308`.
+
+Using single precision can be attractive, as it can be more than twice as fast, depending on whether a simulation is CPU bound, memory bandwidth bound, MPI bound or bottlenecked elsewhere, although in some situations you may see no speed-up at all. Caution should be exercised, however. Keep in mind how many timesteps your simulation requires, and take note of the tolerance you have set per step, to see if the result will lie within your acceptable total error - seven digit precision isn' [...]
+
+Also note that when using an adaptive step integrator, setting a tolerance close to limits of the precision can lead to very slow performance.
+
+A further limitation is that not all the combinations of random number generators and probability distributions that are supported in double precision are supported in single precision. For example, the ``solirte`` generator does not support single precision gaussian distributions. ``dsfmt``, however, is one of the fastest generators, and does support single precision.
+
+WARNING: Single precision mode has not been tested anywhere near as thoroughly as the default double precision mode, and there is a higher chance you will run into bugs.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <features>
+            <precision> single </precision>
+        </features>
+    </simulation>
+
+
+.. _Validation:
+
+Validation
+----------
+
+XMDS2 makes a large number of checks in the code generation process to verify that the values for all parameters are safe choices.  Sometimes we wish to allow these parameters to be specified by variables.  This opens up many possibilities, but requires that any safety checks for parameters be performed during the execution of the program itself.  The ``<validation>`` feature activates that option, with allowable attributes being "run-time", "compile-time" and "none".
+
+As an example, one may wish to define the number of grid points and the range of the grid at run-time rather than explicitly define them in the XMDS2 script. To accomplish this, one could do the following::
+
+    <name> validation_test </name>
+    <features>
+      <validation kind="run-time" />
+      <arguments>
+        <argument name="xmin" type="real" default_value="-1.0"/>
+        <argument name="xmax" type="real" default_value="1.0"/>
+        <argument name="numGridPoints" type="integer" default_value="128"/>
+      </arguments>
+    </features>
+
+    <geometry>
+      <propagation_dimension> t </propagation_dimension>
+      <transverse_dimensions>
+        <dimension name="x" lattice="numGridPoints"  domain="(xmin, xmax)" />
+      </transverse_dimensions>
+   </geometry>
+
+and then run the resulting executable with::
+
+  ./validation_test --xmin=-2.0 --xmax=2.0 --numGridPoints=64
+
+This approach means that when XMDS2 is parsing the script it is unable to tell, for example, if the number of sampling points requested is less than or equal to the lattice size. Consequently it will create an executable with "numGridPoints" as an internal variable, and make the check at run-time, when it knows the value of "numGridPoints" rather than at compile time, when it doesn't.
+
+.. _DriverElement:
+
+Driver Element
+==============
+
+The driver element controls the overall management of the simulation, including how many paths of a stochastic simulation are to be averaged, and whether or not it is to be run using distributed memory parallelisation.  If it is not included, then the simulation is performed once without using MPI parallelisation.  If it is included, it must have a ``name`` attribute.
+
+The ``name`` attribute can have values of "none" (which is equivalent to the default option of not specifying a driver), "distributed-mpi", "multi-path" or "mpi-multi-path".
+
+Choosing the ``name="distributed-mpi"`` option allows a single integration over multiple processors.  The resulting executable can then be run according to your particular implementation of MPI.  The FFTW library only allows MPI processing of multidimensional vectors, as otherwise shared memory parallel processing requires too much inter-process communication to be efficient.  Maximally efficient parallelisation occurs where evolution is entirely local in one transverse dimension (see :r [...]
+
+The ``name="multi-path"`` option is used for stochastic simulations, which are typically run multiple times and averaged.  It requires a ``paths`` attribute with the number of iterations of the integration to be averaged.  The output will report the averages of the desired samples, and the standard error in those averages.  
+The ``name="mpi-multi-path"`` option integrates separate paths on different processors, which is typically a highly efficient process.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <driver name="distributed-mpi" />
+            <!-- or -->
+        <driver name="multi-path" paths="10" />
+            <!-- or -->
+        <driver name="mpi-multi-path" paths="1000" />
+    </simulation>
+
+.. _GeometryElement:
+
+Geometry Element
+================
+
+.. _PropagationDimensionElement:
+
+The ``<geometry>`` element describes the dimensions used in your simulation, and is required.  The only required element inside is the ``<propagation_dimension>`` element, which defines the name of the dimension along which your simulation will integrate.  Nothing else about this dimension is specified, as requirements for the lattice along the integration dimension is specified by the ``<integrate>`` blocks themselves, as described in section :ref:`IntegrateElement`.
+
+.. _TransverseDimensionsElement:
+
+.. _DimensionElement:
+
+If there are other dimensions in your problem, they are called "transverse dimensions", and are described in the ``<transverse_dimensions>`` element.  Each dimension is then described in its own ``<dimension>`` element.  A transverse dimension must have a unique name defined by a ``name`` attribute.  If it is not specified, the type of dimension will default to "real", otherwise it can be specified with the ``type`` attribute.  Allowable types (other than "real") are "long", "int", and " [...]
+
+Each transverse dimension must specify how many points or modes it requires, and the range over which it is defined.  This is done by the ``lattice`` and ``domain`` attributes respectively.  The ``lattice`` attribute is an integer, and is optional for integer dimensions, where it can be defined implicitly by the domain.  The ``domain`` attribute is specified as a pair of numbers (e.g. ``domain="(-17,3)"``) defining the minimum and maximum of the grid.
+
+Any dimension can have a number of aliases.  These act exactly like copies of that dimension, but must be included explicitly in the definition of subsequent vectors (i.e. they are not included in the default list of dimensions for a new vector).  The list of aliases for a dimension are included in an ``aliases`` attribute.  They are useful for non-local reference of variables.  See ``groundstate_gaussian.xmds`` and ``2DMultistateSE.xmds`` as examples.
+
+Integrals over a dimension can be multiplied by a common prefactor, which is specified using the ``volume_prefactor`` attribute.  For example, this allows the automatic inclusion of a factor of two due to a reflection symmetry by adding the attribute ``volume_prefactor="2"``.  In very specific cases, you may wish to refer to volume elements explicitly.  This will lead to grid-dependent behaviour, which is sometimes required in certain stochastic field simulations, for example.  In this c [...]
+    
+If you are using the ``distributed-mpi`` driver to parallelise the simulation, place the dimension you wish to split over multiple processors first.  The most efficient parallelisation would involve distributing a dimension with only local evolution, as the different memory blocks would not need to communicate.  Nonlocal evolution that is local in Fourier space is the second preference, as the Fourier transform can also be successfully parallelised with minimum communication.  
+
+.. _Transforms:
+
+Each transverse dimension can be associated with a transform.  This allows the simulation to manipulate vectors defined on that dimension in the transform space.  The default is Fourier space (with the associated transform being the discrete Fourier transform, or "dft"), but others can be specified with the ``transform`` attribute.  The other options are "none", "dst", "dct", "bessel", "spherical-bessel" and "hermite-gauss".  Using the right transform can dramatically improve the speed o [...]
+
+An advanced feature discussed further in :ref:`DimensionAliases` are dimension aliases, which are specified by the ``aliases`` attribute.  This feature is useful for example, when calculating correlation functions.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <!-- A real-valued dimension from -1.5 to 1.5 -->
+                <dimension name="x" lattice="128" domain="(-1.5, 1.5)" />
+                
+                <!-- An integer-valued dimension with the 6 values -2, -1, 0, 1, 2, 3 -->
+                <dimension name="j"               domain="(-2,3)" type="integer" />
+                
+                <!-- A real-valued dimension using the bessel transform for a radial coordinate -->
+                <dimension name="r" lattice="64" domain="(0, 5)"  transform="bessel" volume_prefactor="2.0*M_PI" />
+            </transverse_dimensions>
+        </geometry>
+    </simulation>
+
+
+.. _dft_Transform:
+
+The "dft" transform
+-------------------
+
+The "dft" transform is performed using the the normal discrete Fourier transform, which means that it enforces periodic boundary conditions on vectors defined on that dimension.  Another implication is that it can only be used with complex-valued vectors.  The discrete Fourier transform is almost exactly the same as a standard Fourier transform.  The standard Fourier transform is
+
+.. math::
+
+    \mathcal{F}\left[f(x)\right](k) = \frac{1}{\sqrt{2\pi}}\int_{x_\text{min}}^{x_\text{max}} f(x) e^{-i k x} dx
+
+The discrete Fourier transform has no information about the domain of the lattice, so the XMDS2 transform is equivalent to
+
+.. math::
+    \tilde{\mathcal{F}}\left[f(x)\right](k) &= \frac{1}{\sqrt{2\pi}}\int_{x_\text{min}}^{x_\text{max}} f(x) e^{-i k (x+ x_\text{min})} dx \\
+    &= e^{-i x_\text{min} k} \mathcal{F}\left[f(x)\right](k)
+
+The standard usage in an XMDS simulation involves moving to Fourier space, applying a transformation, and then moving back.  For this purpose, the two transformations are entirely equivalent as the extra phase factor cancels.  However, when fields are explicitly defined in Fourier space, care must be taken to include this phase factor explicitly.  See section :ref:`Convolutions` in the Advanced Topics section.
+
+When a dimension uses the "dft" transform, then the Fourier space variable is defined as the name of the dimension prefixed with a "k".  For example, the dimensions "x", "y", "z" and "tau" will be referenced in Fourier space as "kx","ky", "kz" and "ktau".  
+
+Fourier transforms allow easy calculation of derivatives, as the n\ :sup:`th` derivative of a field is proportional to the n\ :sup:`th` moment of the field in Fourier space:
+
+.. math::
+    \mathcal{F}\left[\frac{\partial^n f(x)}{\partial x^n}\right](k_x) = \left(i \;k_x\right)^n \mathcal{F}\left[f(x)\right](k_x)
+
+This identity can be used to write the differential operator :math:`\mathcal{L} = \frac{\partial}{\partial x}` as an ``IP`` or ``EX`` operator as ``L = i*kx;`` (see :ref:`OperatorsElement` for more details).
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <!-- transform="dft" is the default, omitting it wouldn't change anything -->
+                <dimension name="x" lattice="128" domain="(-1.5, 1.5)" transform="dft" />
+            </transverse_dimensions>
+        </geometry>
+    </simulation>
+
+
+The "dct" transform
+-------------------
+
+The "dct" (discrete cosine transform) is a Fourier-based transform that implies different boundary conditions for associated vectors.  XMDS uses the type-II DCT, often called "the DCT", and its inverse, which is also called the type-III DCT.  This transform assumes that any vector using this dimension is both periodic, and also even around a specific point within each period.  The grid is therefore only defined across a half period in order to sample each unique point once, and can there [...]
+
+As the DCT transform can be defined on real data rather only complex data, it can also be superior to DFT-based spectral methods for simulations of real-valued fields where boundary conditions are artificial.
+
+XMDS labels the cosine transform space variables the same as for :ref:`Fourier transforms<dft_Transform>` and all the even derivatives can be calculated the same way.  Odd moments of the cosine-space variables are in fact *not* related to the corresponding odd derivatives by an inverse cosine transform.
+
+Discrete cosine transforms allow easy calculation of even-order derivatives, as the 2n\ :sup:`th` derivative of a field is proportional to the 2n\ :sup:`th` moment of the field in DCT-space:
+
+.. math::
+    \mathcal{F}_\text{DCT}\left[\frac{\partial^{2n} f(x)}{\partial x^{2n}}\right](k_x) = (-k_x^2)^{n}\; \mathcal{F}_\text{DCT}\left[f(x)\right](k_x)
+
+This identity can be used to write the differential operator :math:`\mathcal{L} = \frac{\partial^2}{\partial x^2}` as an ``IP`` or ``EX`` operator as ``L = -kx*kx;`` (see :ref:`OperatorsElement` for more details).
+
+For problems where you are defining the simulation domain over only half of the physical domain to take advantage of reflection symmetry, consider using ``volume_prefactor="2.0"`` so that all volume integrals are over the entire physical domain, not just the simulation domain. i.e. integrals would be over -1 to 1 instead of 0 to 1 if the domain was specified as ``domain="(0,1)"``.
+
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <dimension name="x" lattice="128" domain="(-1.5, 1.5)" transform="dct" />
+                    <!-- Or to cause volume integrals to be multiplied by 2 -->
+                <dimension name="y" lattice="128" domain="(0, 1)" transform="dct" volume_prefactor="2.0" />
+            </transverse_dimensions>
+        </geometry>
+    </simulation>
+
+
+The "dst" transform
+-------------------
+
+The "dst" (discrete sine transform) is a counterpart to the DCT transform.  XMDS uses the type-II DST and its inverse, which is also called the type-III DST.  This transform assumes that fields are periodic in this dimension, but also that they are also odd around a specific point within each period.  The grid is therefore only defined across a half period in order to sample each unique point once, and can therefore be of any shape where all the even derivatives are zero at each boundary.  
+
+The DST transform can be defined on real-valued vectors.  As odd-valued functions are zero at the boundaries, this is a natural transform to use when implementing zero Dirichlet boundary conditions.
+
+XMDS labels the sine transform space variables the same as for :ref:`Fourier transforms<dft_Transform>` and all the even derivatives can be calculated the same way.  Odd moments of the sine-space variables are in fact *not* related to the corresponding odd derivatives by an inverse sine transform.
+
+Discrete sine transforms allow easy calculation of even-order derivatives, as the 2n\ :sup:`th` derivative of a field is proportional to the 2n\ :sup:`th` moment of the field in DST-space:
+
+.. math::
+    \mathcal{F}_\text{DST}\left[\frac{\partial^{2n} f(x)}{\partial x^{2n}}\right](k_x) = (-k_x^2)^{n}\; \mathcal{F}_\text{DST}\left[f(x)\right](k_x)
+
+This identity can be used to write the differential operator :math:`\mathcal{L} = \frac{\partial^2}{\partial x^2}` as an ``IP`` or ``EX`` operator as ``L = -kx*kx;`` (see :ref:`OperatorsElement` for more details).
+
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <dimension name="x" lattice="128" domain="(0, 1.5)" transform="dst" />
+            </transverse_dimensions>
+        </geometry>
+    </simulation>
+
+
+.. _BesselTransform:
+
+The "bessel" transform
+----------------------
+
+Just as the Fourier basis is useful for finding derivatives in Euclidean geometry, the basis of Bessel functions is useful for finding certain common operators in cylindrical co-ordinates.  In particular, we use the Bessel functions of the first kind, :math:`J_m(u)`.  The relevant transform is the Hankel transform:
+
+.. math::
+    F_m(k) = \mathcal{H}_m \left[f\right](k) = \int_0^\infty r f(r) J_m(k r) dr
+    
+which has the inverse transform:
+
+.. math::
+    f(r) = \mathcal{H}^{-1}_m \left[F_m\right](r) = \int_0^\infty k F_m(k) J_m(k r) dk
+    
+This transform pair has the useful property that the Laplacian in cylindrical co-ordinates is diagonal in this basis:
+
+.. math::
+    \nabla^2 \left(f(r) e^{i m \theta}\right) &= \left(\frac{\partial^2 f}{\partial r^2} +\frac{1}{r}\frac{\partial f}{\partial r} -\frac{m^2}{r^2} f \right) e^{i m \theta} = \left\{\mathcal{H}^{-1}_m \left[(-k^2) F_m(k)\right](r) \right\} e^{i m \theta}
+    
+XMDS labels the variables in the transformed space with a prefix of 'k', just as for :ref:`Fourier transforms<dft_Transform>`.  The order :math:`m` of the transform is defined by the ``order`` attribute in the ``<dimension>`` element, which must be assigned as a non-negative integer.  If the order is not specified, it defaults to zero which corresponds to the solution being independent of the angular coordinate :math:`\theta`.  
+
+It can often be useful to have a different sampling in normal space and Hankel space.  Reducing the number of modes in either space dramatically speeds simulations.  To set the number of lattice points in Hankel space to be different to the number of lattice points for the field in its original space, use the attribute ``spectral_lattice``.  The Bessel space lattice is chosen such that the boundary condition at the edge of the domain is zero.  This ensures that all of the Bessel modes ar [...]
+
+Hankel transforms allow easy calculation of the Laplacian of fields with cylindrical symmetry.  Applying the operator ``L = -kr*kr`` in Hankel space is therefore equivalent to applying the operator
+
+.. math::
+    \mathcal{L} = \left(\frac{\partial^2}{\partial r^2} +\frac{1}{r}\frac{\partial}{\partial r} -\frac{m^2}{r^2} \right)
+    
+in coordinate space.
+
+In non-Euclidean co-ordinates, integrals have non-unit volume elements.  For example, in cylindrical co-ordinates with a radial co-ordinate 'r', integrals over this dimension have a volume element :math:`r dr`.  When performing integrals along a dimension specified by the "bessel" transform, the factor of the radius is included implicitly.  If you are using a geometry with some symmetry, it is common to have prefactors in your integration.  For example, for a two-dimensional volume in cy [...]
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <dimension name="r" lattice="128" domain="(0, 3)" transform="bessel" volume_prefactor="2*M_PI" />
+            </transverse_dimensions>
+        </geometry>
+    </simulation>
+
+
+
+The "spherical-bessel" transform
+--------------------------------
+
+When working in spherical coordinates, it is often useful to use the spherical Bessel functions :math:`j_l(x)=\sqrt{\frac{\pi}{2x}}J_{l+\frac{1}{2}}(x)` as a basis.  These are eigenfunctions of the radial component of Laplace's equation in spherical coordinates:
+
+.. math::
+    \nabla^2 \left[j_l(k r)\; Y^m_l(\theta, \phi)\right] &= \left[\frac{\partial^2 }{\partial r^2} +\frac{2}{r}\frac{\partial }{\partial r} -\frac{l(l+1)}{r^2}\right] j_l(k r) \; Y^m_l(\theta, \phi) = -k^2 j_l(k r)\; Y^m_l(\theta, \phi)
+
+Just as the Bessel basis above, the transformed dimensions are prefixed with a 'k', and it is possible (and usually wise) to use the ``spectral_lattice`` attribute to specify a different lattice size in the transformed space.  Also, the spacing of these lattices are again chosen in a non-uniform manner to Gaussian quadrature methods for spectrally accurate transforms.  Finally, the ``order`` attribute can be used to specify the order :math:`l` of the spherical Bessel functions used.  
+
+If we denote the transformation to and from this basis by :math:`\mathcal{SH}`, then we can write the useful property:
+
+.. math::
+    \frac{\partial^2 f}{\partial r^2} +\frac{2}{r}\frac{\partial f}{\partial r} -\frac{l (l+1)}{r^2} = \mathcal{SH}^{-1}_l \left[(-k^2) F_l(k)\right](r)
+
+Spherical Bessel transforms allow easy calculation of the Laplacian of fields with spherical symmetry. Applying the operator ``L = -kr*kr`` in Spherical Bessel space is therefore equivalent to applying the operator
+
+.. math::
+    \mathcal{L} = \left( \frac{\partial^2}{\partial r^2} +\frac{2}{r}\frac{\partial}{\partial r} -\frac{l (l+1)}{r^2} \right)
+    
+in coordinate space.  
+
+In non-Euclidean co-ordinates, integrals have non-unit volume elements.  For example, in spherical co-ordinates with a radial co-ordinate 'r', integrals over this dimension have a volume element :math:`r^2 dr`.  When performing integrals along a dimension specified by the "spherical-bessel" transform, the factor of the square of the radius is included implicitly.  If you are using a geometry with some symmetry, it is common to have prefactors in your integration.  For example, for a thre [...]
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <dimension name="r" lattice="128" domain="(0, 3)" transform="spherical-bessel" volume_prefactor="4*M_PI" />
+            </transverse_dimensions>
+        </geometry>
+    </simulation>
+
+
+
+The "hermite-gauss" transform
+-----------------------------
+
+The "hermite-gauss" transform allows transformations to and from the basis of Hermite functions :math:`\psi_n(x)`:
+
+.. math::
+    \psi_n(x) = \left(2^n n! \sigma \sqrt{\pi}\right)^{-1/2} e^{-x^2/2\sigma^2} H_n(\sigma x)
+    
+where the functions :math:`H_n(x)` are the Hermite polynomials:
+
+.. math::
+    H_n(x) &= (-1)^n e^{x^2} \frac{d^n}{dx^n} \left(e^{-x^2}\right)
+    
+which are eigenfunctions of the Schroedinger equation for a harmonic oscillator:
+
+.. math::
+    - \frac{\hbar^2}{2 m} \frac{\partial^2 \psi_n}{\partial x^2} + \frac{1}{2} m \omega^2 x^2 \psi_n(x) = \hbar \omega\left(n+\frac{1}{2}\right) \psi_n(x),
+
+with :math:`\sigma = \sqrt{\frac{\hbar}{m \omega}}`.
+    
+This transform is different to the others in that it requires a ``length_scale`` attribute rather than a ``domain`` attribute, as the range of the lattice will depend on the number of basis functions used. The ``length_scale`` attribute defines the scale of the domain as the standard deviation :math:`\sigma` of the lowest order Hermite function :math:`\psi_0(x)`:
+
+.. math::
+    \psi_0(x) = (\sigma^2 \pi)^{-1/4} e^{-x^2/2 \sigma^2}
+
+When a dimension uses the "hermite-gauss" transform, then the variable indexing the basis functions is defined as the name of the dimension prefixed with an "n".  For example, when referencing the basis function indices for the dimensions "x", "y", "z" and "tau", use the variable "nx", "ny", "nz" and "ntau".  
+
+Applying the operator ``L = nx + 0.5`` in Hermite space is therefore equivalent to applying the operator
+
+.. math::
+   \mathcal{L} = \left(- \frac{\sigma^2}{2}\frac{\partial^2}{\partial x^2} + \frac{1}{2 \sigma^2} x^2 \right)
+    
+in coordinate space.  
+
+The Hermite-Gauss transform permits one to work in energy-space for the harmonic oscillator.  The normal Fourier transform of "hermite-gauss" dimensions can also be referenced using the dimension name prefixed with a "k".  See the examples ``hermitegauss_transform.xmds`` and ``hermitegauss_groundstate.xmds`` for examples.
+
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <dimension name="r" lattice="128" length_scale="1.0" transform="hermite-gauss" />
+            </transverse_dimensions>
+        </geometry>
+    </simulation>
+
+
+
+
+.. _VectorElement:
+
+Vector Element
+==============
+
+Vectors are arrays of data, defined over any subset of the transverse dimensions defined in your :ref:`GeometryElement`.  These dimensions are listed in the attribute ``dimensions``, which can be an empty string if you wish the vector to not be defined on any dimensions.  If you do not include a ``dimensions`` attribute then the vector defaults to being a function of all transverse dimensions, not including any aliases.  Vectors are used to store static or dynamic variables, but you do n [...]
+
+Each ``<vector>`` element has a unique name, defined by a ``name`` attribute.  It is either complex-valued (the default) or real-valued, which can be specified using the ``type="real"`` attribute.
+
+.. _ComponentsElement:
+
+A vector contains a list of variables, each defined by name in the ``<components>`` element.  The name of each component is the name used to reference it later in the simulation.
+
+Vectors are initialised at the beginning of a simulation, either from code or from an input file.  The basis choice for this initialisation defaults to the normal space as defined in the ``<geometry>`` element, but any transverse dimension can be initialised in their transform basis by specifying them in an ``initial_basis`` attribute.  The ``initial_basis`` attribute lists dimensions either by their name as defined by the ``<geometry>`` element, or by their transformed name.  For exampl [...]
+
+.. _InitialisationElement:
+
+When initialising the vector within the XMDS script, the appropriate code is placed in a 'CDATA' block inside an ``<initialisation>`` element.  This code is in standard C-syntax, and should reference the components of the vector by name.  XMDS defines a few useful :ref:`shorthand macros<XMDSCSyntax>` for this C-code.  If you wish to initialise all the components of the vector as zeros, then it suffices simply to add the attribute ``kind="zero"`` or to omit the ``<initialisation>`` elemen [...]
+    
+.. _ReferencingNonlocal:
+
+While the default XMDS behaviour is to reference all variables locally, any vector can be referenced non-locally.  The notation for referencing the value of a vector 'phi' with a dimension 'j' at a value of 'j=jk' is ``phi(j => jk)``.  Multiple non-local dimensions are addressed by adding the references in a list, e.g. ``phi(j => jk, x => y)``.  See ``2DMultistateSE.xmds`` for an example.
+
+Dimensions can only be accessed non-locally if one of the following conditions is true:
+
+* The dimension is an ``integer`` dimension,
+* The dimension is accessed with an :ref:`alias <DimensionAliases>` of that dimension. For example, ``phi(x => y)`` if the dimension ``x`` has ``y`` as an alias, or vice-versa.
+* The dimension is a Fourier transform dimension (``dft``), used in the spectral basis (i.e. ``kx`` for an ``x`` dimension) and it is accessed with the negative of that dimension.  For example ``phi(kx => -kx)``.
+* The dimension is uniformly spaced (i.e. corresponds to the spatial basis of a dimension with a transform of ``dft``, ``dct``, ``dst`` or ``none``), the dimension is symmetric about zero and it is accessed with the negative of the dimension name.  For example ``phi(x => -x)`` for a dimension with domain of ``(-1.2, 1.2)``.
+* The dimension is uniformly spaced (i.e. corresponds to the spatial basis of a dimension with a transform of ``dft``, ``dct``, ``dst`` or ``none``), and it is accessed with the lower limit of that dimension.  For example, ``phi(x => -1.2)`` for a dimension with a domain of ``(-1.2, 1.2)``.  Note that the dimension must be accessed with the exact characters used in the definition of the domain.  For the previous example ``phi(x => -1.20)`` does not satisfy this condition.
+* **Advanced behaviour**: The value of a variable at an arbitrary point can be accessed via the integer index for that dimension. For example ``phi(x_index => 3)`` accesses the value of ``phi`` at the grid point with index 3.  As ``x_index`` is zero-based, this will be the *fourth* grid point.  It is highly recommended that the :ref:`diagnostics <Diagnostics>` feature be used when writing simulations using this feature.  Once the simulation has been tested, ``<diagnostics>`` can be turne [...]
+
+
+Note that a dimension cannot be accessed non-locally in ``distributed-mpi`` simulations if the simulation is distributed across that dimension.
+
+.. _FilenameElement:
+
+If you wish to initialise from a file, then you can choose to initialise from an hdf5 file using ``kind="hdf5"`` in the ``<initialisation>`` element, and then supply the name of the input file with the ``filename`` element.  This is a standard data format which can be generated from XMDS, or from another program.  An example for generating a file in another program for input into XMDS is detailed in the Advanced topic: :ref:`Importing`.
+
+When initialising from a file, the default is to require the lattice of the transverse dimensions to exactly match the lattice defined by XMDS.  There is an option to import data defined on a subset or superset of the lattice points.  Obviously, the dimensionality of the imported field still has to be correct.  This option is activated by defining the attribute ``geometry_matching_mode="loose"``.  The default option is defined as ``geometry_matching_mode="strict"``.  A requirement of the [...]
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <dimension name="x" lattice="128" domain="(-1, 1)" />
+            </transverse_dimensions>
+        </geometry>
+    
+        <!-- A one-dimensional vector with dimension 'x' -->
+        <vector name="wavefunction" initial_basis="x" type="complex">
+            <components> phi </components>
+            <initialisation>
+                <![CDATA[
+                    // 'cis(x)' is cos(x) + i * sin(x)
+                    phi = exp(-0.5 * x * x) * cis(40 * x);
+                ]]>
+            </initialisation>
+        </vector>
+        
+        <!-- A zero-dimensional real vector with components u and v -->
+        <vector name="zero_dim" dimensions="" type="real">
+            <components>
+                u v
+            </components>
+            <initialisation kind="hdf5">
+                <filename>data.h5</filename>
+            </initialisation>
+        </vector>
+    </simulation>
+
+
+
+.. _Dependencies:
+
+The dependencies element
+------------------------
+
+Often a vector, computed vector, filter, integration operator or output group will reference the values in one or more other vectors, computed vectors or noise vectors.  These dependencies are defined via a ``<dependencies>`` element, which lists the names of the vectors.  The components of those vectors will then be available for use in the 'CDATA' block, and can be referenced by their name.  
+
+For a vector, the basis of the dependent vectors, and therefore the basis of the dimensions available in the 'CDATA' block, are defined by the ``initial_basis`` of the vector.  For a ``<computed_vector>``, ``<filter>`` ``<integration_vector>``, or moment group vector, the basis of the dependencies can be specified by a ``basis`` attribute in the ``<dependencies>`` element.  For example, ``basis="x ny kz"``.
+
+Any transverse dimensions that appear in the ``<dependencies>`` element that do not appear in the ``dimensions`` attribute of the vector are integrated out.  For integer dimensions, this is simply an implicit sum over the dimension.  For real-valued dimensions, this is an implicit integral over the range of that dimension.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <dimension name="x" lattice="128" domain="(-1, 1)" />
+                <dimension name="y" lattice="10" domain="(-3, 2)" transform="dct" />
+            </transverse_dimensions>
+        </geometry>
+    
+        <!-- A one-dimensional vector with dimension 'x' -->
+        <vector name="wavefunction" dimensions="x" initial_basis="x" type="complex">
+            <components> phi </components>
+            <initialisation>
+                <!-- 
+                    The initialisation of the vector 'wavefunction' depends on information
+                    in the 'two_dim' vector.  The vector two_dim is DCT-transformed into the
+                    (x, ky) basis, and the ky dimension is implicitly integrated over in the
+                    following initialisation code
+                  -->
+                <dependencies basis="x ky">two_dim</dependencies>
+                <![CDATA[
+                    // 'cis(x)' is cos(x) + i * sin(x)
+                    phi = exp(-0.5 * x * x + v) * cis(u * x);
+                ]]>
+            </initialisation>
+        </vector>
+        
+        <!-- A two-dimensional real vector with components u and v -->
+        <vector name="two_dim" type="real">
+            <components>
+                u v
+            </components>
+            <initialisation kind="hdf5">
+                <filename>data.h5</filename>
+            </initialisation>
+        </vector>
+    </simulation>
+
+
+
+.. _ComputedVectorElement:
+
+Computed Vector Element
+=======================
+
+.. _EvaluationElement:
+
+Computed vectors are arrays of data much like normal ``<vector>`` elements, but they are always calculated as they are referenced, so they cannot be initialised from file.  It is defined with a ``<computed_vector>`` element, which has a ``name`` attribute, optional ``dimensions`` and ``type`` attributes, and a ``<components>`` element, just like a ``<vector>`` element.  Instead of an <:ref:`initialisation<InitialisationElement>`> element, it has an ``<evaluation>`` element that serves th [...]
+
+As it is not being stored, a ``<computed_vector>`` does not have or require an ``initial_basis`` attribute, as it will be transformed into an appropriate basis for the element that references it.  The basis for its evaluation will be determined entirely by the ``basis`` attribute of the ``<dependencies>`` element.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <dimension name="x" lattice="128" domain="(-1, 1)" />
+            </transverse_dimensions>
+        </geometry>
+    
+        <!-- A one-dimensional vector with dimension 'x' -->
+        <vector name="wavefunction" type="complex">
+            <components> phi </components>
+            <initialisation>
+                <![CDATA[
+                    // 'cis(x)' is cos(x) + i * sin(x)
+                    phi = exp(-0.5 * x * x) * cis(40 * x);
+                ]]>
+            </initialisation>
+        </vector>
+        
+        <!-- A zero-dimensional real computed vector with components Ncalc -->
+        <computed_vector name="zero_dim" dimensions="" type="real">
+            <components>
+                Ncalc
+            </components>
+            <evaluation>
+                <dependencies>wavefunction</dependencies>
+                <![CDATA[
+                    // Implicitly integrating over the dimension 'x'
+                    Ncalc = mod2(phi);
+                ]]>
+            </evaluation>
+        </computed_vector>
+    </simulation>
+
+
+
+.. _NoiseVectorElement:
+
+Noise Vector Element
+====================
+
+Noise vectors are used like computed vectors, but when they are evaluated they generate arrays of random numbers of various kinds.  They do not depend on other vectors, and are not initialised by code.  They are defined by a ``<noise_vector>`` element, which has a ``name`` attribute, and optional ``dimensions``, ``initial_basis`` and ``type`` attributes, which work identically as for normal vectors.  
+
+The choice of pseudo-random number generator (RNG) can be specified with the ``method`` attribute, which has options "posix" (the default), "mkl", "solirte" and "dsfmt".  It is only possible to use any particular method if that library is available.  Although "posix" is the default, it is also the slowest, and produces the lowest quality random numbers (although this is typically not a problem).  "mkl" refers to the Intel Math Kernel Library, and is only available if installed.  "solirte [...]
+
+The random number generators can be provided with a seed using the ``seed`` attribute, which should typically consist of a list of three integers.  All RNGs require positive integers as seeds.  It is possible to use the :ref:`<validation kind="run-time"/><Validation>` feature to use passed variables as seeds.  It is advantageous to use fixed seeds rather than timer-based seeds, as the :ref:`<error_check><ErrorCheck>` element can test for strong convergence if the same seeds are used for  [...]
+
+The different types of noise vectors are defined by a mandatory ``kind`` attribute, which must take the value of 'gauss', 'gaussian', 'wiener', 'poissonian','jump' or 'uniform'.  
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+                <dimension name="x" lattice="128" domain="(-1, 1)" />
+            </transverse_dimensions>
+        </geometry>
+    
+        <!-- 
+            A one-dimensional complex wiener noise vector.
+            This noise is appropriate for using in the complex
+            random-walk equation of motion:
+                dz_dt = eta;
+        -->
+        <noise_vector name="noise" kind="wiener">
+            <components>
+                eta
+            </components>
+        </vector>
+    </simulation>
+
+
+.. _uniformNoise:
+
+Uniform noise
+-------------
+
+Uniform noises defined over any transverse dimensions are simply uniformly distributed random numbers between zero and one.  This noise is an example of a "static" noise, i.e. one suitable for initial conditions of a field.  If it were included in the equations of motion for a field, then the effect of the noise would depend on the lattice spacing of the propagation dimension.  XMDS therefore does not allow this noise type to be used in integration elements.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <noise_vector name="drivingNoise" dimensions="x" kind="uniform" type="complex" method="dsfmt" seed="314 159 276">
+          <components>Eta</components>
+        </noise_vector>
+    </simulation>
+
+
+.. _gaussianNoise:
+
+Gaussian noise
+--------------
+
+Noise generated with the "gaussian" method is gaussian distributed with zero mean.  For a real-valued noise vector, the variance at each point is the inverse of the volume element of the transverse dimensions in the vector.  This volume element for a single transverse dimension is that used to perform integrals over that dimension.  For example, it would include a factor of :math:`r^2` for a dimension "r" defined with a ``spherical-bessel`` transform.  It can be non-uniform for dimension [...]
+
+This lattice-dependent variance is typical in most applications of partial differential equations with stochastic initial conditions, as the physical quantity is the variance of the field over some finite volume, which does not change if the variance at each lattice site varies as described above.
+
+For complex-valued noise vector, the real and imaginary parts of the noise are independent, and each have half the variance of a real-valued noise.  This means that the modulus squared of a complex-valued noise vector has the same variance as a real-valued noise vector at each point.
+
+Gaussian noise vectors are an example of a "static" noise, i.e. one suitable for initial conditions of a field.  If they were included in the equations of motion for a field, then the effect of the noise would depend on the lattice spacing of the propagation dimension.  XMDS therefore does not allow this noise type to be used in integration elements.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <noise_vector name="initialNoise" dimensions="x" kind="gauss" type="real" method="posix" seed="314 159 276">
+          <components>fuzz</components>
+        </noise_vector>
+    </simulation>
+
+
+.. _wienerNoise:
+
+Wiener noise
+------------
+
+Noise generated with the "wiener" method is gaussian distributed with zero mean and the same variance as the static "gaussian" noise defined above, multiplied by a factor of the lattice step in the propagation dimension.  This means that these noise vectors can be used to define Wiener noises for standard stochastic ordinary or partial differential equations.  Most integrators in XMDS effectively interpret these noises as Stratonovich increments.
+
+As a dynamic noise, a Wiener process is not well-defined except in an ``integrate`` element.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <noise_vector name="diffusion" dimensions="x" kind="wiener" type="real" method="solirte" seed="314 159 276">
+          <components>dW</components>
+        </noise_vector>
+    </simulation>
+
+
+.. _poissionianNoise:
+
+Poissonian noise
+----------------
+
+A noise vector using the "poissonian" method generates a random variable from a Poissonian distribution.  While the the Poisson distribution is integer-valued, the variable will be cast as a real number.  The rate of the Poissonian distribution is defined by the ``mean`` or ``mean-density`` attributes.  These are are synonyms, and must be defined as positive real numbers.  For Poissonian noises defined over real-valued transverse dimensions, the rate is given by the product of this ``mea [...]
+
+Poissonian noise vectors are an example of a "static" noise, i.e. one suitable for initial conditions of a field.  If they were included in the equations of motion for a field, then the effect of the noise would depend on the lattice spacing of the propagation dimension.  XMDS therefore does not allow this noise type to be used in integration elements.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <noise_vector name="initialDistribution" dimensions="x" kind="poissonian" type="real" mean-density="2.7" method="solirte" seed="314 159 276">
+          <components>Pdist</components>
+        </noise_vector>
+    </simulation>
+
+
+.. _jumpNoise:
+
+Jump noise
+----------
+
+A noise vector using the "jump" method is the dynamic version of the poissonian noise method, and must have the ``mean-rate`` attribute specified as a positive real number.  The variable at each point is chosen from a Poissonian distribution with a mean equal to the product of three variables: the ``mean-rate`` attribute; the volume of the element as defined by its transverse dimensions (including their ``volume_prefactor`` attributes); and the step size in the propagation dimension.  No [...]
+
+It is common to wish to vary the mean rate of a jump process, which means that the ``mean-rate`` attribute must be a variable or a piece of code.  These cannot be verified to be a positive real number at compile time, so they must be used with the :ref:`<validation><Validation>` feature with either the ``kind="none"`` or ``kind="run-time"`` attributes.
+
+As a dynamic noise, a jump process is not well-defined except in an ``integrate`` element.
+
+Example syntax::
+
+    <simulation xmds-version="2">
+        <noise_vector name="initialDistribution" dimensions="" kind="jump" type="real" mean-rate="2.7" method="solirte" seed="314 159 276">
+          <components>dN</components>
+        </noise_vector>
+    </simulation>
+
+
+
+.. _SequenceElement:
+
+Sequence Element
+================
+
+All processing of vectors happens in sequence elements.  Each simulation must have exactly one main sequence element, but it can then contain any number of nested sequence elements.  A sequence element can contain any number of ``<sequence>``, :ref:`<filter><FilterElement>`, :ref:`<integrate><IntegrateElement>` and/or :ref:`<breakpoint><BreakpointElement>` elements, which are executed in the order they are written.  A sequence can be repeated a number of times by using the ``cycles`` att [...]
+    
+Example syntax::
+
+    <simulation xmds-version="2">
+        <sequence cycles="2">
+            <sequence>  ... </sequence>
+            <filter> ... </filter>
+            <integrate> ...</integrate>
+        </sequence>
+    </simulation>    
+
+.. _FilterElement:
+
+Filter element
+==============
+
+A ``<filter>`` element can be placed inside a ``<sequence>`` element or an :ref:`<integrate><IntegrateElement>` element.  It contains a 'CDATA' block and an optional :ref:`<dependencies><Dependencies>` element, which may give access to variables in other ``<vector>``, ``<computed_vector>`` or ``<noise_vector>`` elements.  The code inside the 'CDATA' block is executed over the combined tensor product space of the dependencies, or simply once if there is no dependencies element.  This elem [...]
+    
+Sometimes it is desirable to apply a filter conditionally.  The most efficient way of doing this is to call the function from the piece of code that contains the conditional statement (likely another ``<filter>`` element) rather than embed the conditional function in the filter itself, as the latter method can involve the conditional statement being evaluated multiple times over the transverse dimensions.  For this reason, it is possible to give a filter a ``name`` attribute, and the fil [...]
+    
+One of the common uses of a filter element is to apply discontinuous changes to the vectors and variables of the simulation.
+
+Example syntax::
+
+    <sequence>
+        <filter>
+          <![CDATA[
+            printf("Hello world from the first filter segment!  This filter rather wastefully calls the second one.\n");
+            fname();
+          ]]>
+        </filter>
+
+        <filter name="fname">
+           <dependencies>normalisation wavefunction</dependencies>
+           <![CDATA[
+             phi *= sqrt(Nparticles/Ncalc);
+           ]]>
+        </filter>
+    </sequence>
+
+
+.. _IntegrateElement:
+
+Integrate element
+=================
+
+The ``<integrate>`` element is at the heart of most XMDS simulations.  It is used to integrate a set of (potentially stochastic) first-order differential equations for one or more of the vectors defined using the ``<vector>`` element along the propagation dimension.  At the beginning of the simulation, the value of the propagation dimension is set to zero, and the vectors are initialised as defined in the :ref:`<vector><VectorElement>` element.  As successive sequence elements change the [...]
+    
+The length of the integration is defined by the ``interval`` attribute, which must be a positive real number.  An ``<integrate>`` element must have an ``algorithm`` attribute defined, which defines the integration method.  Current methods include :ref:`SI <SI>`, :ref:`SIC <SI>`, :ref:`RK4 <RK4>`, :ref:`RK9 <RK4>`, :ref:`ARK45 <ARK45>`, and :ref:`ARK89 <ARK45>`.  Fixed step algorithms require a ``steps`` attribute, which must be a positive integer that defines the number of (evenly spaced [...]
+
+.. _SamplesElement:
+
+The optional ``<samples>`` element is used to track the evolution of one or more vectors or variables during an integration.  This element must contain a non-negative integer for each :ref:`<sampling_group><SamplingGroupElement>` element defined in the simulation's :ref:`<output><OutputElement>` element.  The list of integers then defines the number of times that the moments defined in those groups will be sampled.  For a fixed step algorithm, each non-zero number of samples must be a fa [...]
+    
+The vectors to be integrated and the form of the differential equations are defined in the :ref:`<operators><OperatorsElement>` element (or elements).  Filters to be applied each step can be defined with optional :ref:`<filters><FiltersElement>` elements.  
+    
+Computed vectors can be defined with the ``<computed_vector>`` element.  These act exactly like a globally defined :ref:`ComputedVectorElement`, but are only available within the single ``<integrate>`` element.
+
+Example syntax::
+
+    <integrate algorithm="ARK89" interval="1e-4" steps="10000" tolerance="1e-8">
+      <samples>20</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            phi *= sqrt(Nparticles/Ncalc);   // Correct normalisation of the wavefunction
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*hbar/M*ky*ky;
+          ]]>
+        </operator>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] - (V1 + Uint/hbar*mod2(phi))*phi;
+        ]]>
+        <integration_vectors>wavefunction</integration_vectors>
+      </operators>
+    </integrate>
+
+.. _OperatorsElement:
+
+Operators and operator elements
+-------------------------------
+
+An :ref:`<integrate><IntegrateElement>` element must contain one or more ``<operators>`` elements, which define both which vectors are to be integrated, and their derivative in the propagation dimension.  When all vectors to be integrated have the same dimensionality, they can all be defined within a single ``<operators>`` element, and when vectors with different dimension are to be integrated, each set of vectors with the same dimensionality should be placed in separate ``<operators>``  [...]
+    
+.. _IntegrationVectorsElement:
+
+Within each ``<operators>`` element, the vectors that are to be integrated are listed by name in the ``<integration_vectors>`` element, and the differential equations are written in a 'CDATA' block.   The derivative of each component of the integration vectors must be defined along the propagation dimension.  For example, if the integration vectors have components 'phi' and 'beta', and the propagation dimension is labelled 'tau', then the 'CDATA' block must define the variables 'dphi_dta [...]
+    
+When noise vectors are referenced, equations with Wiener noises should be written as though the equations are in differential form, as described in the worked examples :ref:`Kubo` and :ref:`Fibre`.  Jump-based Poisson noises will also be written in an equivalent form, as modelled by the example ``photodetector.xmds``.
+    
+By default, the name of each component references the local value of the vector, but :ref:`nonlocal variables<ReferencingNonlocal>` can be accessed using the standard syntax.  However, typically the most common (and most efficient) method of referencing nonlocal variables is to reference variables that are local in the :ref:`transformed space<Transforms>` for a given transverse dimension.  This is done using ``<operator>`` elements.
+    
+.. _OperatorElement:
+
+There are three kinds of ``<operator>`` elements.  The first is denoted with a ``kind="functions"`` attribute, and contains a 'CDATA' block that will be executed in the order that it is defined.  This is useful when you wish to calculate functions that do not depend on the transverse dimensions.  Defining these along with the main equations of motion causes them to be recalculated separately for each point.  The second kind of ``<operator>`` element is used to define an operation in a tr [...]
+
+Example syntax::
+
+    <operator kind="functions">
+      <![CDATA[
+      f = cos(t);
+      ]]>
+    </operator>
+    
+.. _OperatorNamesElement:
+
+The second kind of operator element defines a list of operators in an ``<operator_names>`` element.  The basis of these operators defaults to the transform space unless a different basis is specified using the ``basis`` attribute.  These operators must then be defined in a 'CDATA' block, using any :ref:`dependencies<Dependencies>` as normal.  If the operators constant across the integration, then the attribute ``constant="yes"`` should be set, otherwise the ``constant="no"`` attribute en [...]
+
+Operators of this second kind have the ``kind="IP"`` or ``kind="EX"`` attribute, standing for 'interaction picture' and 'explicit' operators respectively.  Explicit operators can be used in all situations, and simply construct and calculate a new vector of the form in the square brackets.  IP operators use less memory and can improve speed by allowing larger timesteps, but have two important restrictions.  **Use of IP operators without understanding these restrictions can lead to incorre [...]
+
+Example syntax::
+
+    <operator kind="ex" constant="yes">
+      <operator_names>T</operator_names>
+      <![CDATA[
+        T = -0.5*hbar/M*ky*ky;
+      ]]>
+    </operator>
+
+The third kind of operator element is used to define an integration along a transverse dimension.  This kind of evolution is called "cross-propagation", and is described briefly in the examples 'tla.xmds', 'tla_sic.xmds' and 'sine_cross.xmds'.  This class of equations have a subset of vectors that have an initial condition on one side of a transverse dimension, and a differential equation defined in that dimension, and as such, this kind of operator element has much of the structure of a [...]
+    
+An operator element with the ``kind="cross_propagation"`` attribute must specify the transverse dimension along which the integration would proceed with the ``propagation_dimension`` attribute.  It must also specify its own :ref:`<integration_vectors><IntegrationVectorsElement>` element, its own ``<operators>`` elements (of the second kind), and may define an optional :ref:`<dependencies><Dependencies>` element.  The algorithm to be used for the transverse integration is specified by the [...]
+    
+.. _BoundaryConditionElement:
+
+The boundary conditions are specified by a ``<boundary_conditions>`` element, which requires the ``kind="left"`` or ``kind="right"`` attribute to specify on which side of the grid that the boundary conditions are specified.  The boundary conditions for the ``<integration_vectors>`` are then specified in a 'CDATA' block, which may refer to vectors in an optional :ref:`<dependencies><Dependencies>` element that can be contained in the ``<boundary_conditions>`` element.
+
+Example syntax::
+
+    <operator kind="cross_propagation" algorithm="RK4" propagation_dimension="t">
+      <integration_vectors>cross</integration_vectors>
+      <dependencies>constants</dependencies>
+      <boundary_condition kind="left">
+        <![CDATA[
+          v = 1.0;
+          w = 1.0;
+        ]]>
+      </boundary_condition>
+  
+      <operator kind="ip" constant="yes">
+        <operator_names>L</operator_names>
+        <![CDATA[
+          L = i;
+        ]]>
+      </operator>
+  
+      <![CDATA[
+        dv_dt = i*v;
+        dw_dt = L[w]; 
+      ]]>
+    </operator>
+
+
+.. _Algorithms:
+
+Algorithms
+----------
+
+The stability, efficiency and even convergence of a numerical integration can depend on the method.  Due to the varying properties of different sets of equations, it is impossible to define the best method for all equations, so XMDS provides an option to use different algorithms.  These include fixed step algorithms, which divide the integration region into equal steps, and adaptive stepsize algorithms, which attempt to estimate the error in the simulation in order to choose an appropria [...]
+
+For the purposes of the descriptions below, we will assume that we are considering the following set of coupled differential equations for the vector of variables :math:`\mathbf{x}(t)`:
+
+.. math::
+
+    \frac{d x_j}{dt} = f_j(\mathbf{x}(t),t)
+
+.. _SI:
+
+SI and SIC algorithms
+~~~~~~~~~~~~~~~~~~~~~
+
+The SI algorithm is a semi-implicit fixed-step algorithm that finds the increment of the vector by solving
+
+.. math::
+
+    x_j(t+\Delta t) = x_j(t) + f_j\left(\mathbf{x}(t+\frac{\Delta t}{2}),t+\frac{\Delta t}{2}\right) \;\Delta t
+
+using a simple iteration to find the values of the vector at the midpoint of the step self-consistently.  The number of iterations can be set using the ``iterations`` attribute, and it defaults to ``iterations="3"``.  The choice of ``iterations="1"`` is therefore fully equivalent to the Euler algorithm, where
+
+.. math::
+
+    x_j(t+\Delta t) = x_j(t) + f_j\left(\mathbf{x}(t),t\right) \;\Delta t.
+
+The Euler algorithm is the only safe algorithm for direct integration of :ref:`jump-based Poisson processes<jumpNoise>`.  Efficient numerical solution of those types of equations is best done via a process of triggered filters, which will be described in the :ref:`AdvancedTopics` section.  Integrating using the Euler algorithm computes the Ito integral, as opposed to the Stratonovich integral, which all the other algorithms compute.
+    
+When SI integration is used in conjunction with SI cross-propagation, a slight variant of the SI algorithm can be employed where the integration in both directions is contained within the iteration process.  This is activated by using ``algorithm="SIC"`` rather than ``algorithm="SI"``.
+
+The SI algorithm is correct to second order in the step-size for deterministic equations, and first order in the step-size for Stratonovich stochastic equations with Wiener noises.  This makes it the highest order stochastic algorithm in XMDS, although there are many sets of equations that integrate more efficiently with lower order algorithms.  When called with the ``iterations="1"`` option (the Euler algorithm), it is correct to first order in the step-size for deterministic equations, [...]
+
+
+.. _RK4:
+
+Runge-Kutta algorithms
+~~~~~~~~~~~~~~~~~~~~~~
+
+Runge-Kutta algorithms are the workhorse of numerical integration, and XMDS employs two fixed step versions: ``algorithm="RK4"``, which is correct to fourth-order in the step size, and ``algorithm="RK9"``, which is correct to ninth order in the step size.  It must be strongly noted that a higher order of convergence does not automatically mean a superior algorithm.  RK9 requires several times the memory of the RK4 algorithm, and each step requires significantly more computation.
+
+All Runge-Kutta algorithms are convergent for Stratonovich stochastic equations at the order of the square root of the step-size.  This 'half-order' convergence may seem very weak, but for some classes of stochastic equation this improves up to one half of the deterministic order of convergence.  Also, the convergence of some stochastic equations is limited by the 'deterministic part', which can be improved dramatically by using a higher order Runge-Kutta method.
+
+
+.. _ARK45:
+
+Adaptive Runge-Kutta algorithms
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Fixed step integrators can encounter two issues.  First, as the equations or parameters of a simulation are changed, the minimum number of steps required to integrate it may change.  This means that the convergence must be re-tested multiple times for each set of parameters, as overestimating the number of steps required to perform an integration to a specified error tolerance can be very inefficient. Second, even if the minimum acceptable number of steps required is known for a given si [...]
+algorithms get around this problem by testing the convergence during the integration, and adjusting the step-size until it reaches some target tolerance.
+
+XMDS employs two adaptive step-size algorithms based on 'embedded Runge-Kutta' methods.  These are Runge-Kutta methods that can output multiple variables that have different convergence.  The difference between the higher-order and the lower-order solutions gives an estimate of the error in each step, which can then be used to estimate an appropriate size for the next step.  We use ``algorthim="ARK45"``, which contains fourth and fifth order solutions, and ``algorthim=ARK89``, which cont [...]
+
+All adaptive stepsize algorithms require a ``tolerance`` attribute, which must be a positive real number that defines the allowable error per step.  It is also possible to specify a ``max_iterations`` attribute, which is a positive integer that stops the integrator from trying too many times to find an acceptable stepsize.  The integrator will abort with an error if the number of attempts for a single step exceeds the maximum specified with this attribute.
+
+As all Runge-Kutta solutions have equal order of convergence for stochastic equations, *if the step-size is limited by the stochastic term then the step-size estimation is entirely unreliable*.  Adaptive Runge-Kutta algorithms are therefore not appropriate for stochastic equations.
+
+
+.. _FiltersElement:
+
+Filters element
+---------------
+
+:ref:`Filter elements<FilterElement>` are used inside :ref:`sequence elements<SequenceElement>` to execute arbitrary code, or make discontinuous changes in the vectors.  Sometimes it is desirable to perform a filter element at the beginning or end of each step in an integration.  This can be done by placing ``<filter>`` elements in a ``<filters>`` element within the ``<integrate>`` element.  The ``<filters>`` element specifies whether the filters are to be executed at the end of each ste [...]
+is then executed in the order found in the ``<filters>`` element.
+
+Example syntax::
+
+    <integrate algorithm="ARK45" interval="100000.0" steps="10000000" tolerance="1e-8">
+      <samples>5000 100</samples>
+      <filters where="step end">
+        <filter>
+            <dependencies>vector1 vector2</dependencies>
+            <![CDATA[
+                x = 1;
+                y *= ynorm;
+                ]]>
+        </filter>
+      </filters>
+
+      <operators>
+        <integration_vectors>vector1</integration_vectors>
+        <![CDATA[
+        dx_dt = alpha;
+        dy_dt = beta*y;
+        ]]>
+      </operators>
+    </integrate>
+
+
+.. _BreakpointElement:
+
+Breakpoint element
+==================
+
+The ``<breakpoint>`` element is used to output the full state of one or more vectors.  Unlike sampled output, it executes immediately rather than at the end of a program, and can therefore be used to examine the current state of an ongoing simulation.  The vectors to be output are defined via a :ref:`<dependencies><Dependencies>` element, and the basis is chosen by the ``basis`` attribute supplied to that ``<dependencies>`` element, as usual.  A single ``<breakpoint>`` element must only  [...]
+
+Example syntax::
+
+    <breakpoint filename="groundstate_break.xsil" format="hdf5">
+      <dependencies basis="ky">wavefunction</dependencies>
+    </breakpoint>
+
+.. _OutputElement:
+
+Output element
+==============
+
+The ``<output>`` element describes the output of the program.  It is often inefficient to output the complete state of all vectors at all times during a large simulation, so the purpose of this function is to define subsets of the information required for output.  Each different format of information is described in a different ``<sampling_group>`` element inside the output element.  The ``<output>`` element may contain any number of ``<sampling_group>`` elements.  The format of the outp [...]
+
+The ``<samples>`` inside ``<integrate>`` elements defines a string of integers, with exactly one for each ``<sampling_group>`` element.  During that integration, the variables described in each ``<sampling_group>`` element will be sampled and stored that number of times.  
+
+
+.. _SamplingGroupElement:
+
+Sampling Group Element
+----------------------
+
+A ``<sampling_group>`` element defines a set of variables that we wish to output, typically they are functions of some subset of vectors.  The names of the desired variables are listed in a ``<moments>`` element, just like the ``<components>`` element of a vector.  They are defined with a ':ref:`CDATA<XMDSCSyntax>`' block, accessing any components of vectors and computed vectors that are defined in a :ref:`<dependencies><Dependencies>` element, also just like a vector.  :ref:`Computed ve [...]
+    
+The basis of the output is specified by the ``basis`` attribute.  This overrides any basis specification in the ``<dependencies>`` element.  Because we often wish to calculate these vectors on a finer grid than we wish to output, it is possible to specify that the output on a subset of the points defined for any transverse dimension.  This is done by adding a number in parentheses after that dimension in the basis string, e.g. ``basis="x y(32) kz(64)"``.  If the number is zero, then that [...]
+    
+The ``initial_sample`` attribute, which must be "yes" or "no", determines whether the moment group will be sampled before any integration occurs.
+
+Example syntax::
+
+    <output format="hdf5" filename="SimOutput.xsil">
+      <sampling_group basis="x y" initial_sample="yes">
+        <computed_vector name="filter3" dimensions="" type="complex">
+          <components>sparemomentagain</components>
+          <evaluation>
+            <dependencies basis="kx ky">integrated_u main</dependencies>
+            <![CDATA[
+              sparemomentagain = mod2(u);
+            ]]>
+          </evaluation>
+        </computed_vector>
+        <operator kind="ex" constant="no">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <moments>amp ke</moments>
+        <dependencies>main filter1</dependencies>
+        <![CDATA[
+          amp = mod2(u + moment);
+          ke = mod2(L[u]);
+        ]]>
+      </sampling_group>
+
+      <sampling_group basis="kx(0) ky(64)" initial_sample="yes">
+        <moments>Dens_P </moments>
+        <dependencies>fields </dependencies>
+        <![CDATA[
+          Dens_P = mod2(psi);
+        ]]>
+      </sampling_group>
+    </output>
+
+
+.. _XMDSCSyntax:
+
+XMDS-specific C syntax
+======================
+
+Sampling complex numbers can be written more efficiently using:
+
+.. code-block:: xpdeint
+
+      <![CDATA[
+        _SAMPLE_COMPLEX(W);
+      ]]>
+
+which is short for
+
+.. code-block:: xpdeint
+
+      <![CDATA[
+        WR = W.Re();
+        WI = W.Im();
+      ]]>
+
+Various properties of dimensions are available.  For example, for a dimension called ``x``:
+
+* The number of points is accessible with the variable ``_lattice_x``,
+* The minimum range of that dimension is ``_min_x``,
+* The maximum range of that dimension is ``_max_x``,
+* The step size of a dimension is ``dx``, and if it is constant, also available using ``_dx``, but note that the latter does not include the effect of any ``volumePrefix`` you may have set!
diff --git a/documentation/_sources/reference_index.txt b/documentation/_sources/reference_index.txt
new file mode 100644
index 0000000..bc1fd43
--- /dev/null
+++ b/documentation/_sources/reference_index.txt
@@ -0,0 +1,15 @@
+Reference section
+=================
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+   
+   reference_installation_and_configuration
+ 
+   reference_usefulXMLSyntax
+
+   reference_schema
+
+   reference_elements
diff --git a/documentation/_sources/reference_installation_and_configuration.txt b/documentation/_sources/reference_installation_and_configuration.txt
new file mode 100644
index 0000000..ad55368
--- /dev/null
+++ b/documentation/_sources/reference_installation_and_configuration.txt
@@ -0,0 +1,38 @@
+.. _ReferenceConfigurationInstallationRuntime:
+
+Configuration, installation and runtime options
+===============================================
+
+Running the 'xmds2' program with the option '--help', gives several options that can change its behaviour at runtime.  These include:
+  * '-o' or '--output', which overrides the name of the output file to be generated
+  * '-n' or '--no-compile', which generates the C code for the simulation, but does not try to compile it
+  * '-v' or '--verbose', which gives verbose output about compilation flags.
+  * '-g' or '--debug', which compiles the simulation in debug mode (compilation errors refer to lines in the source, not the .xmds file). This option implies '-v'. This option is mostly useful when debugging XMDS code generation.
+  * '--waf-verbose', which makes ``waf`` be very verbose when configuring XMDS or compiling simulations.  This option is intended for developer use only to aid in diagnosing problems with ``waf``.
+
+It also has commands to configure XMDS2 and recheck the installation.  If your program requires extra paths to compile, you can configure XMDS2 to include those paths by default.  Simply use the command
+
+.. code-block:: bash
+
+    $ xmds2 --configure --include-path /path/to/include --lib-path /path/to/lib 
+
+Alternatively, you can set the ``CXXFLAGS`` or ``LINKFLAGS`` environment variables before calling ``xmds2 --reconfigure``.  For example, to pass the compiler flag ``-pedantic`` and the link flag ``-lm`` using the bash shell, use:
+
+.. code-block:: bash
+
+    $ export CXXFLAGS="-pedantic"
+    $ export LINKFLAGS="-lm" 
+    $ xmds2 --reconfigure``
+    
+This method can also be used to change the default compilers for standard and parallel processing, using the CXX and MPICXX flags respectively.
+
+Running XMDS2 with the '--configure' option also searches for packages that have been installed since you last installed or configured XMDS2.  If you wish to run 'xmds2 --configure' with the same extra options as last time, simply use the command:
+
+.. code-block:: bash
+
+    $ xmds2 --reconfigure
+
+A detailed log of the checks is saved in the file '~/.xmds/waf_configure/config.log'.  This can be used to identify issues with packages that XMDS2 is not recognised, but you think that you have successfully installed on your system.
+
+
+
diff --git a/documentation/_sources/reference_schema.txt b/documentation/_sources/reference_schema.txt
new file mode 100644
index 0000000..88b3421
--- /dev/null
+++ b/documentation/_sources/reference_schema.txt
@@ -0,0 +1,157 @@
+.. _ReferenceSchema:
+
+****************
+XMDS2 XML Schema
+****************
+
+
+There are many, many XML tags that can make up an XMDS2 script. Most of them are optional, or have default values if not specified. It is, however, useful to know which elements are possible, and their position and relationship to other elements in the script. Shown below is the full XML tree for XMDS2, which shows all possible elements and their position in the tree. An ellipsis (...) outside an element indicates the element above can be repeated indefinitely, and an ellipsis inside an  [...]
+
+The syntax <element /> can be used for lowest-level elements that have attributes but no content, and are shorthand for <element> </element>. This shorthand notation can also be used for elements which can only contain the content "yes" or "no"; in this case the presence of <element /> is equivalent to <element> yes </element>, and the absence of such an element is equivalent to <element> no </element>
+
+The possible attributes and attribute values for each element are not shown; see the individual entries in the Reference section for details.
+
+
+.. parsed-literal::
+
+    <?xml version="1.0" encoding="UTF-8"?>
+    <:ref:`simulation <SimulationElement>` xmds-version="2">
+      <:ref:`name <NameElement>`> <:ref:`/name <NameElement>`>
+      <:ref:`author <AuthorElement>`> <:ref:`author <AuthorElement>`>
+      <:ref:`description <DescriptionElement>`> <:ref:`/description <DescriptionElement>`>
+      
+      <:ref:`features <FeaturesElement>`>
+        <:ref:`arguments <ArgumentsElement>`>
+          <:ref:`argument <ArgumentElement>` />
+          <:ref:`argument <ArgumentElement>` />
+          ...
+        <:ref:`/arguments <ArgumentsElement>`>
+        <:ref:`auto_vectorise <AutoVectorise>` />
+        <:ref:`benchmark <Benchmark>` />
+        <:ref:`bing <Bing>` />
+        <:ref:`cflags <CFlags>`> <:ref:`/cflags <CFlags>`>
+        <:ref:`chunked_output <ChunkedOutput>` />
+        <:ref:`diagnostics <Diagnostics>` />
+        <:ref:`error_check <ErrorCheck>` />
+        <:ref:`halt_non_finite <HaltNonFinite>` />
+        <:ref:`fftw <FFTW>` />
+        <:ref:`globals <Globals>`> <:ref:`/globals <Globals>`>
+        <:ref:`openmp <OpenMP>` />
+        <:ref:`precision <Precision>`> <:ref:`/precision <Precision>`>
+        <:ref:`validation <Validation>` />
+      <:ref:`/features <FeaturesElement>`>
+
+      <:ref:`driver <DriverElement>` />
+  
+      <:ref:`geometry <GeometryElement>`>
+        <:ref:`propagation_dimension <PropagationDimensionElement>`> <:ref:`/propagation_dimension <PropagationDimensionElement>`>
+        <:ref:`transverse_dimensions <TransverseDimensionsElement>`>
+          <:ref:`dimension <DimensionElement>` />
+          <:ref:`dimension <DimensionElement>` />
+          ...
+        <:ref:`/transverse_dimensions <TransverseDimensionsElement>`>
+      <:ref:`/geometry <GeometryElement>`>
+  
+      <:ref:`vector <VectorElement>`>
+        <:ref:`components <ComponentsElement>`> <:ref:`/components <ComponentsElement>`>
+        <:ref:`initialisation <InitialisationElement>`>
+          <:ref:`dependencies <Dependencies>`> <:ref:`/dependencies <Dependencies>`>
+          <:ref:`filename <FilenameElement>`>
+          <![:ref:`CDATA <InitialisationElement>` [
+          ]]>
+        <:ref:`/initialisation <InitialisationElement>`>
+      <:ref:`/vector <VectorElement>`>
+
+      <:ref:`vector <VectorElement>`> ... <:ref:`/vector <VectorElement>`>
+      <:ref:`vector <VectorElement>`> ... <:ref:`/vector <VectorElement>`>
+      ...
+
+      <:ref:`computed_vector <ComputedVectorElement>`>
+        <:ref:`components <ComponentsElement>`> <:ref:`/components <ComponentsElement>`>
+        <:ref:`evaluation <EvaluationElement>`>
+          <:ref:`dependencies <Dependencies>`> <:ref:`/dependencies <Dependencies>`>
+          <![:ref:`CDATA <InitialisationElement>` [
+          ]]>
+        <:ref:`/evaluation <EvaluationElement>`>
+      <:ref:`/computed_vector <ComputedVectorElement>`>
+
+      <:ref:`computed_vector <ComputedVectorElement>`> ... <:ref:`/computed_vector <ComputedVectorElement>`>
+      <:ref:`computed_vector <ComputedVectorElement>`> ... <:ref:`/computed_vector <ComputedVectorElement>`>
+      ...
+
+      <:ref:`noise_vector <NoiseVectorElement>`>
+        <:ref:`components <ComponentsElement>`> <:ref:`/components <ComponentsElement>`>
+      <:ref:`/noise_vector <NoiseVectorElement>`>
+
+      <:ref:`noise_vector <NoiseVectorElement>`> ... <:ref:`/noise_vector <NoiseVectorElement>`>
+      <:ref:`noise_vector <NoiseVectorElement>`> ... <:ref:`/noise_vector <NoiseVectorElement>`>
+      ...
+
+      <:ref:`sequence <SequenceElement>`>
+
+        <:ref:`filter <FilterElement>`>
+          <:ref:`dependencies <Dependencies>`> <:ref:`/dependencies <Dependencies>`>
+          <![:ref:`CDATA <XMDSCSyntax>` [
+          ]]>
+        <:ref:`/filter <FilterElement>`>
+
+        <:ref:`integrate <IntegrateElement>`>
+          <:ref:`samples <SamplesElement>`> <:ref:`/samples <SamplesElement>`>
+
+          <:ref:`computed_vector <ComputedVectorElement>`> ... <:ref:`/computed_vector <ComputedVectorElement>`>
+
+          <:ref:`filters <FiltersElement>`>
+            <:ref:`filter <FilterElement>`> ... <:ref:`/filter <FilterElement>`>
+            <:ref:`filter <FilterElement>`> ... <:ref:`/filter <FilterElement>`>
+            ...
+          <:ref:`/filters <FiltersElement>`>
+      
+          <:ref:`operators <OperatorsElement>`>
+
+            <:ref:`operator <OperatorElement>`>
+              <:ref:`boundary_condition <BoundaryConditionElement>`>
+                <:ref:`dependencies <Dependencies>`> <:ref:`/dependencies <Dependencies>`>
+                <![:ref:`CDATA <XMDSCSyntax>` [
+                ]]>
+              <:ref:`/boundary_condition <BoundaryConditionElement>`>
+              <:ref:`operator_names <OperatorNamesElement>`> <:ref:`/operator_names <OperatorNamesElement>`>
+              <:ref:`dependencies <Dependencies>`> <:ref:`/dependencies <Dependencies>`>
+              <![:ref:`CDATA <XMDSCSyntax>` [
+              ]]>
+            <:ref:`/operator <OperatorElement>`>
+
+            <:ref:`operator <OperatorElement>`> ... <:ref:`/operator <OperatorElement>`>
+            <:ref:`operator <OperatorElement>`> ... <:ref:`/operator <OperatorElement>`>
+            ...
+
+            <:ref:`integration_vectors <IntegrationVectorsElement>`> <:ref:`/integration_vectors <IntegrationVectorsElement>`>
+            <:ref:`dependencies <Dependencies>`> <:ref:`/dependencies <Dependencies>`>
+            <![:ref:`CDATA <XMDSCSyntax>` [
+            ]]>
+
+          <:ref:`/operators <OperatorsElement>`>
+
+        <:ref:`/integrate <IntegrateElement>`>
+    
+        <:ref:`breakpoint <BreakpointElement>`>
+          <:ref:`dependencies <Dependencies>`> <:ref:`/dependencies <Dependencies>`>
+        <:ref:`/breakpoint <BreakpointElement>`>
+
+      <:ref:`/sequence <SequenceElement>`>
+  
+      <:ref:`output <OutputElement>`>
+        <:ref:`sampling_group <SamplingGroupElement>`>
+          <:ref:`dependencies <Dependencies>`> <:ref:`/dependencies <Dependencies>`>
+          <:ref:`moments <SamplingGroupElement>`> <:ref:`/moments <SamplingGroupElement>`>
+          <:ref:`operator <OperatorElement>`> ... <:ref:`/operator <OperatorElement>`>       
+          <![:ref:`CDATA <XMDSCSyntax>` [
+          ]]>
+        <:ref:`/sampling_group <SamplingGroupElement>`>
+
+        <:ref:`sampling_group <SamplingGroupElement>`> ... <:ref:`/sampling_group <SamplingGroupElement>`>
+        <:ref:`sampling_group <SamplingGroupElement>`> ... <:ref:`/sampling_group <SamplingGroupElement>`>
+        ...
+
+      <:ref:`/output <OutputElement>`>
+
+    <:ref:`/simulation <SimulationElement>`>
diff --git a/documentation/_sources/reference_usefulXMLSyntax.txt b/documentation/_sources/reference_usefulXMLSyntax.txt
new file mode 100644
index 0000000..faf663d
--- /dev/null
+++ b/documentation/_sources/reference_usefulXMLSyntax.txt
@@ -0,0 +1,24 @@
+.. _ReferenceUsefulXMLSyntax:
+
+Useful XML Syntax
+=================
+
+Standard XML placeholders can be used to simplify some scripts.  For example, the following (abbreviated) code ensures that the limits of a domain are symmetric.
+
+.. code-block:: xmds2
+
+    <?xml version="1.0" encoding="UTF-8"?>
+    <!DOCTYPE simulation [
+    <!ENTITY Npts    "64">
+    <!ENTITY L      "3.0e-5">
+    ]>
+      <simulation xmds-version="2">
+      
+        . . .
+        
+        <geometry>
+            <propagation_dimension> t </propagation_dimension>
+            <transverse_dimensions>
+              <dimension name="x" lattice="&Npts;"  domain="(-&L;, &L;)" />
+            </transverse_dimensions>
+         </geometry>
diff --git a/documentation/_sources/tutorial.txt b/documentation/_sources/tutorial.txt
new file mode 100644
index 0000000..ff5d1fd
--- /dev/null
+++ b/documentation/_sources/tutorial.txt
@@ -0,0 +1,258 @@
+.. _QuickStartTutorial:
+
+Quickstart Tutorial
+===================
+
+In this tutorial, we will create an XMDS2 script to solve the Lorenz Attractor, an example of a dynamical system that exhibits chaos. The equations describing this problem are 
+
+.. math::
+    \frac{dx}{dt} &= \sigma (y - x)\\
+    \frac{dy}{dt} &= x (\rho - z) - y\\
+    \frac{dz}{dt} &= xy - \beta z
+
+where we will solve with the parameters :math:`\sigma=10`, :math:`\rho=28`, :math:`\beta = \frac{8}{3}` and the initial condition :math:`x(0) = y(0) = z(0) = 1`.
+
+Below is a script that solves this problem (it's also saved as examples/lorenz.xmds in your XMDS2 directory). Don't worry if it doesn't make sense yet, soon we'll break it down into easily digestible parts.
+
+.. code-block:: xpdeint
+    
+    <?xml version="1.0" encoding="UTF-8"?>
+    <simulation xmds-version="2">
+      <name>lorenz</name>
+      
+      <!-- While not strictly necessary, the following two tags are handy. -->
+      <author>Graham Dennis</author>
+      <description>
+        The Lorenz Attractor, an example of chaos.
+      </description>
+      
+      <!-- 
+      This element defines some constants.  It can be used for other 
+      features as well, but we will go into that in more detail later.
+      -->
+      <features>
+        <globals>
+            <![CDATA[
+            real sigma = 10.0;
+            real b = 8.0/3.0;
+            real r = 28.0;
+            ]]>
+         </globals>
+       </features>
+       
+      <!-- 
+      This part defines all of the dimensions used in the problem,
+      in this case, only the dimension of 'time' is needed.
+      -->
+      <geometry>
+        <propagation_dimension> t </propagation_dimension>
+      </geometry>
+      
+      <!-- A 'vector' describes the variables that we will be evolving. -->
+      <vector name="position" type="real">
+        <components>
+          x y z
+        </components>
+        <initialisation>
+          <![CDATA[
+          x = y = z = 1.0;
+          ]]>
+        </initialisation>
+      </vector>
+      
+      <sequence>
+        <!--
+        Here we define what differential equations need to be solved
+        and what algorithm we want to use.
+        -->
+        <integrate algorithm="ARK89" interval="20.0" tolerance="1e-7">
+          <samples>5000</samples>
+          <operators>
+            <integration_vectors>position</integration_vectors>
+            <![CDATA[
+            dx_dt = sigma*(y-x);
+            dy_dt = r*x - y - x*z;
+            dz_dt = x*y - b*z;
+            ]]>
+          </operators>
+        </integrate>
+      </sequence>
+      
+      <!-- This part defines what data will be saved in the output file -->
+      <output format="hdf5" filename="lorenz.xsil">
+        <sampling_group initial_sample="yes">
+          <moments>xR yR zR</moments>
+          <dependencies>position</dependencies>
+          <![CDATA[
+            xR = x;
+            yR = y;
+            zR = z;
+          ]]>
+        </sampling_group>
+      </output>
+    </simulation>
+
+You can compile and run this script with **XMDS2**. To compile the script, just pass the name of the script as an argument to **XMDS2**.
+
+    .. code-block:: none
+
+        $ xmds2 lorenz.xmds
+        xmds2 version 2.1 "Happy Mollusc" (r2680)
+        Copyright 2000-2012 Graham Dennis, Joseph Hope, Mattias Johnsson
+                            and the xmds team
+        Generating source code...
+        ... done
+        Compiling simulation...
+        ... done. Type './lorenz' to run.
+
+Now we can execute the generated program 'lorenz'.
+
+    .. code-block:: none
+
+        $ ./lorenz 
+        Sampled field (for moment group #1) at t = 0.000000e+00
+        Sampled field (for moment group #1) at t = 4.000000e-03
+        Current timestep: 4.000000e-03
+        Sampled field (for moment group #1) at t = 8.000000e-03
+        Current timestep: 4.000000e-03
+
+        ... many lines omitted ...
+
+        Current timestep: 4.000000e-03
+        Sampled field (for moment group #1) at t = 1.999600e+01
+        Current timestep: 4.000000e-03
+        Sampled field (for moment group #1) at t = 2.000000e+01
+        Current timestep: 4.000000e-03
+        Segment 1: minimum timestep: 9.997900e-06 maximum timestep: 4.000000e-03
+          Attempted 7386 steps, 0.00% steps failed.
+        Generating output for lorenz
+
+The program generated by **XMDS2** has now integrated your equations and produced two files.  The first is the XML file "lorenz.xsil", which contains the all the information used to generate the simulation (including the XMDS2 code) and the metadata description of the output.  The second file is named "lorenz.h5", which is a `HDF5 <http://www.hdfgroup.org/HDF5>`_ file containing all of the output data.   You can analysing these files yourself, or import them into your favourite visualisa [...]
+
+    .. code-block:: none
+
+        $ xsil2graphics2 -e lorenz.xsil 
+        xsil2graphics2 from xmds2 version 2.1 "Happy Mollusc" (r2680)
+        Generating output for Mathematica 6+.
+        Writing import script for 'lorenz.xsil' to 'lorenz.nb'.
+
+This has now generated the file 'lorenz.nb', which is a Mathematica notebook that loads the output data of the simulation.  Loading it into Mathematica allows us to plot the points {xR1, yR1, zR1}:
+
+    .. code-block:: none
+
+        ll = Transpose[{xR1, yR1, zR1}];
+        ListPointPlot3D[ll]
+
+.. image:: images/lorenz.*
+    :align: center
+
+...and we see the lobes of the strange attractor.  Now let us examine the code that produced this simulation.
+
+First, we have the top level description of the code.
+
+.. code-block:: xpdeint
+
+    <?xml version="1.0" encoding="UTF-8"?>
+    <simulation xmds-version="2">
+      <name>lorenz</name>
+      
+      <!-- While not strictly necessary, the following two tags are handy. -->
+      <author>Graham Dennis</author>
+      <description>
+        The Lorenz Attractor, an example of chaos.
+      </description>
+
+One of the advantages of an XML format is that these tags are almost entirely self-explanatory.  XMDS2 files follow full XML syntax, so elements can be commented out using the ``<!--`` and ``-->`` brackets, and we have an example of that here. 
+
+The first line, ``<?xml ...>``, just specifies the encoding and XML version. It is optional, but its presence helps some text editors perform the correct syntax highlighting.
+
+The ``<simulation>`` element is mandatory, and encloses the entire simulation script.
+
+The ``<name>`` element is optional, but recommended. It defines the name of the executable program that will be generated, as well as the default name of the output data files (although this can be over-ridden in the ``<output>`` element if desired). If ``<name>`` is not present, it will default to the filename of the script.
+
+The next element we have used can be skipped entirely if you wish to use the default set of features and you don't want to define any global constants for your simulation.  
+
+.. code-block:: xpdeint
+    
+      <features>
+        <globals>
+            <![CDATA[
+            real sigma = 10.0;
+            real b = 8.0/3.0;
+            real r = 28.0;
+            ]]>
+         </globals>
+       </features>
+
+The ``<features>`` element can be used to choose a large number of features that will be discussed later, but here we have only used it to define a ``<globals>`` element.  This element contains a block of text with ``<![CDATA[`` at the start and ``]]>`` at the end.  These 'CDATA' blocks  are used in several places in an XMDS script, and define a block of text that will be pasted directly into the generated C-code.  They must therefore be formatted in legal C-syntax, and any legal C-synta [...]
+
+The next element is the essential ``<geometry>`` element.
+
+.. code-block:: xpdeint
+    
+      <geometry>
+        <propagation_dimension> t </propagation_dimension>
+      </geometry>
+
+This element is used to define all the dimensions in the problem.  We only require the time dimension, which we are labelling 't', so this is a trivial example.  We will discuss transverse dimensions in more detail in the next worked example (:ref:`NonLinearSchrodingerEquation`), where we deal with the integration of a partial differential equation rather than ordinary differential equations.
+
+Next, we have the ``<vector>`` element.
+
+.. code-block:: xpdeint
+    
+      <vector name="position" type="real">
+        <components>
+          x y z
+        </components>
+        <initialisation>
+          <![CDATA[
+          x = y = z = 1.0;
+          ]]>
+        </initialisation>
+      </vector>
+
+We can define multiple vectors, but here we only need the variables that we wish to integrate.  We named this vector "position", as it defines the position in phase space.  These variables are real-valued (as opposed to, say, complex numbers), so we define ``type="real"``.  The ``<components>`` element defines the names of the elements of this vector, which we have called 'x', 'y' and 'z'.  Finally, we provide the initial values of the variables in a CDATA block within the ``<initialisat [...]
+
+Now we come to the heart of the simulation, where we define the evolution of our vector.  This evolution is held in the ``<sequence>`` element, which contains an ordered sequence of actions upon any defined vectors.  Vectors can be altered with a ``<filter>`` element, or integrated in the propagation dimension with an ``<integrate>`` element.
+
+.. code-block:: xpdeint
+    
+      <sequence>
+        <integrate algorithm="ARK89" interval="20.0" tolerance="1e-7">
+          <samples>5000</samples>
+          <operators>
+            <integration_vectors>position</integration_vectors>
+            <![CDATA[
+            dx_dt = sigma*(y-x);
+            dy_dt = r*x - y - x*z;
+            dz_dt = x*y - b*z;
+            ]]>
+          </operators>
+        </integrate>
+      </sequence>
+
+Here our sequence consists of a single ``<integrate>`` element.  It contains several important pieces of information.  At the heart, the ``<operators>`` element contains the equations of motion as described above, written in a very human-readable fashion.  It also contains an ``<integration_vectors>`` element, which defines which vectors are used in this integrate block.  We have only one vector defined in this simulation, so it is a trivial choice here.  
+
+All integrate blocks must define which algorithm is to be used - in this case the 8th (embedded 9th) order adaptive Runge-Kutta method, called "ARK89".  The details of different algorithms will be described later (FIXME: Link!), but for now all we need to know is that this algorithm requires a tolerance, and that smaller means more accurate, so we'll make it :math:`10^{-7}` by setting ``tolerance="1.0e-7"``.  Finally, any integration will proceed a certain length in the propagation dimen [...]
+
+The ``<samples>`` element says that the values of the output groups will be sampled 5000 times during this interval.  The nature of the output is defined in the last element in the simulation: the ``<output>`` element.
+
+.. code-block:: xpdeint
+    
+  <output format="hdf5" filename="lorenz.xsil">
+    <sampling_group initial_sample="yes">
+      <moments>xR yR zR</moments>
+      <dependencies>position</dependencies>
+      <![CDATA[
+        xR = x;
+        yR = y;
+        zR = z;
+      ]]>
+    </sampling_group>
+  </output>
+
+The two top-level arguments in the ``<output>`` element are "format" and "filename".  Here we define the output filename, although it would have defaulted to this value.  We also choose the format to be HDF5, which is why the simulation resulted in the binary file "lorenz.h5" as well as "lorenz.xsil".  If we had instead said ``format="ascii"``, then all of the output data would have been written in text form in "lorenz.xsil".
+
+The ``<output>`` element can contain any non-zero number of ``<sampling_group>`` elements, which specify the entire output of the program.  They allow for subsampling, integration of some or all of the transverse dimensions, and/or conversion of some dimensions into Fourier space, but these will be described in more detail in the following examples.  We have a ``<dependencies>`` element that specifies which vectors are needed for this output.  We specify the list of output variables with [...]
+
+And that's it.  This is quite a large framework to integrate three coupled ordinary differential equations, but the advantage of using XMDS2 is that vastly more complicated simulations can be performed without increasing the length or complexity of the XMDS2 script significantly.  The :ref:`WorkedExamples` section will provide more complicated examples with stochastic equations and partial differential equations.  If you are moved to solve your own problem using XMDS2, then perhaps the m [...]
diff --git a/documentation/_sources/upgrade.txt b/documentation/_sources/upgrade.txt
new file mode 100644
index 0000000..23af03c
--- /dev/null
+++ b/documentation/_sources/upgrade.txt
@@ -0,0 +1,10 @@
+.. _UpgradeFromXMDS1:
+
+Upgrading From XMDS 1.X
+=======================
+
+While **XMDS2** is a complete rewrite of the **XMDS** project, much of the syntax has remained very similar.  That said, your code will have to be rewritten as an XMDS2 program.  We recommend that you work through the :ref:`QuickStartTutorial` and perhaps the :ref:`WorkedExamples` sections, and then you should be good to go.
+
+The main news when switching to XMDS2 is the long list of new things you can do.  If it's an initial value problem, XMDS2 has a good chance of being able to solve it.
+
+We have made the decision to call the executables "xmds2" and "xsil2graphics2" so that you can keep using your old installation in parallel with the new version.
\ No newline at end of file
diff --git a/documentation/_sources/worked_examples.txt b/documentation/_sources/worked_examples.txt
new file mode 100644
index 0000000..243e668
--- /dev/null
+++ b/documentation/_sources/worked_examples.txt
@@ -0,0 +1,1359 @@
+.. _WorkedExamples:
+
+Worked Examples
+===============
+
+One of the best ways to learn XMDS2 is to see several illustrative examples.  Here are a set of example scripts and explanations of the code, which will be a good way to get started.  As an instructional aid, they are meant to be read sequentially, but the adventurous could try starting with one that looked like a simulation they wanted to run, and adapt for their own purposes.
+
+   :ref:`NonLinearSchrodingerEquation` (partial differential equation)
+   
+   :ref:`Kubo` (stochastic differential equations)
+
+   :ref:`Fibre` (stochastic partial differential equation using parallel processing)
+
+   :ref:`IntegerDimensionExample` (integer dimensions)
+
+   :ref:`WignerArguments` (two dimensional PDE using parallel processing, passing arguments in at run time)
+
+   :ref:`GroundStateBEC` (PDE with continual renormalisation - computed vectors, filters, breakpoints)
+
+   :ref:`HermiteGaussGroundStateBEC` (Hermite-Gaussian basis)
+   
+   :ref:`2DMultistateSE` (combined integer and continuous dimensions with matrix multiplication, aliases)
+
+All of these scripts are available in the included "examples" folder, along with more examples that demonstrate other tricks.  Together, they provide starting points for a huge range of different simulations.
+
+.. _NonLinearSchrodingerEquation:
+
+The nonlinear Schrödinger equation
+----------------------------------
+
+This worked example will show a range of new features that can be used in an **XMDS2** script, and we will also examine our first partial differential equation.  We will take the one dimensional nonlinear Schrödinger equation, which is a common nonlinear wave equation.  The equation describing this problem is:
+
+.. math::
+    \frac{\partial \phi}{\partial \xi} = \frac{i}{2}\frac{\partial^2 \phi}{\partial \tau^2} - \Gamma(\tau)\phi+i|\phi|^2 \phi
+
+where :math:`\phi` is a complex-valued field, and :math:`\Gamma(\tau)` is a :math:`\tau`-dependent damping term.  Let us look at an XMDS2 script that integrates this equation, and then examine it in detail.
+
+.. code-block:: xpdeint
+
+    <simulation xmds-version="2">
+      <name>nlse</name>
+
+      <author>Joe Hope</author>
+      <description>
+        The nonlinear Schrodinger equation in one dimension, 
+        which is a simple partial differential equation.  
+        We introduce several new features in this script.
+      </description>
+
+      <features>
+          <benchmark />
+          <bing />
+          <fftw plan="patient" />
+          <openmp />
+          <auto_vectorise />
+          <globals>
+              <![CDATA[
+              const double energy = 4;
+              const double vel = 0.3;
+              const double hwhm = 1.0;
+              ]]>
+           </globals>
+         </features>
+
+      <geometry>
+          <propagation_dimension> xi </propagation_dimension>
+          <transverse_dimensions>
+            <dimension name="tau" lattice="128"  domain="(-6, 6)" />
+          </transverse_dimensions>
+       </geometry>
+
+      <vector name="wavefunction" type="complex" dimensions="tau">
+        <components> phi </components>
+        <initialisation>
+          <![CDATA[
+          const double w0 = hwhm*sqrt(2/log(2));
+          const double amp = sqrt(energy/w0/sqrt(M_PI/2));
+          phi = amp*exp(-tau*tau/w0/w0)*exp(i*vel*tau);
+          ]]>
+        </initialisation>
+      </vector>
+
+      <vector name="dampingVector" type="real">
+        <components> Gamma </components>
+        <initialisation>
+          <![CDATA[
+          Gamma=1.0*(1-exp(-pow(tau*tau/4.0/4.0,10)));
+          ]]>
+        </initialisation>
+      </vector>
+
+      <sequence>
+        <integrate algorithm="ARK45" interval="20.0" tolerance="1e-7">
+          <samples>10 100 10</samples>
+          <operators>
+            <integration_vectors>wavefunction</integration_vectors>
+            <operator kind="ex" constant="yes">
+              <operator_names>Ltt</operator_names>
+              <![CDATA[
+                Ltt = -i*ktau*ktau*0.5;
+              ]]>
+            </operator>
+            <![CDATA[
+            dphi_dxi = Ltt[phi] - phi*Gamma + i*mod2(phi)*phi;
+            ]]>
+            <dependencies>dampingVector</dependencies>
+          </operators>
+        </integrate>
+      </sequence>
+
+      <output>
+        <sampling_group basis="tau" initial_sample="yes">
+          <moments>density</moments>
+          <dependencies>wavefunction</dependencies>
+          <![CDATA[
+            density = mod2(phi);
+          ]]>
+        </sampling_group>
+        
+        <sampling_group basis="tau(0)" initial_sample="yes">
+          <moments>normalisation</moments>
+          <dependencies>wavefunction</dependencies>
+          <![CDATA[
+            normalisation = mod2(phi);
+          ]]>
+        </sampling_group>
+        
+        <sampling_group basis="ktau(32)" initial_sample="yes">
+          <moments>densityK</moments>
+          <dependencies>wavefunction</dependencies>
+          <![CDATA[
+            densityK = mod2(phi);
+          ]]>
+        </sampling_group>
+
+      </output>
+    </simulation>
+
+Let us examine the new items in the ``<features>`` element that we have demonstrated here.  The existence of the ``<benchmark>`` element causes the simulation to be timed.  The ``<bing>`` element causes the computer to make a sound upon the conclusion of the simulation.  The ``<fftw>`` element is used to pass options to the `FFTW libraries for fast Fourier transforms <http://fftw.org>`_, which are needed to do spectral derivatives for the partial differential equation.  Here we used the  [...]
+
+Finally, we use two tags to make the simulation run faster.  The ``<auto_vectorise>`` element switches on several loop optimisations that exist in later versions of the GCC compiler.  The ``<openmp>`` element turns on threaded parallel processing using the OpenMP standard where possible.  These options are not activated by default as they only exist on certain compilers.  If your code compiles with them on, then they are recommended.
+
+Let us examine the ``<geometry>`` element.
+
+.. code-block:: xpdeint
+
+      <geometry>
+          <propagation_dimension> xi </propagation_dimension>
+          <transverse_dimensions>
+            <dimension name="tau" lattice="128"  domain="(-6, 6)" />
+          </transverse_dimensions>
+       </geometry>
+
+This is the first example that includes a transverse dimension.  We have only one dimension, and we have labelled it "tau".  It is a continuous dimension, but only defined on a grid containing 128 points (defined with the lattice variable), and on a domain from -6 to 6.  The default is that transforms in continuous dimensions are fast Fourier transforms, which means that this dimension is effectively defined on a loop, and the "tau=-6" and "tau=6" positions are in fact the same.  Other t [...]
+
+Two vector elements have been defined in this simulation.  One defines the complex-valued wavefunction "phi" that we wish to evolve.  We define the transverse dimensions over which this vector is defined by the ``dimensions`` tag in the description.  By default, it is defined over all of the transverse dimensions in the ``<geometry>`` element, so even though we have omitted this tag for the second vector, it also assumes that the vector is defined over all of tau.  
+
+The second vector element contains the component "Gamma" which is a function of the transverse variable tau, as specified in the equation of motion for the field.  This second vector could have been avoided in two ways.  First, the function could have been written explicitly in the integrate block where it is required, but calculating it once and then recalling it from memory is far more efficient.  Second, it could have been included in the "wavefunction" vector as another component, bu [...]
+
+The ``<integrate>`` element for a partial differential equation has some new features:
+
+.. code-block:: xpdeint
+
+        <integrate algorithm="ARK45" interval="20.0" tolerance="1e-7">
+          <samples>10 100 10</samples>
+          <operators>
+            <integration_vectors>wavefunction</integration_vectors>
+            <operator kind="ex" constant="yes">
+              <operator_names>Ltt</operator_names>
+              <![CDATA[
+                Ltt = -i*ktau*ktau*0.5;
+              ]]>
+            </operator>
+            <![CDATA[
+            dphi_dxi = Ltt[phi] - phi*Gamma + i*mod2(phi)*phi;
+            ]]>
+            <dependencies>dampingVector</dependencies>
+          </operators>
+        </integrate>
+
+There are some trivial changes from the tutorial script, such as the fact that we are using the ARK45 algorithm rather than ARK89.  Higher order algorithms are often better, but not always.  Also, since this script has multiple output groups, we have to specify how many times each of these output groups are sampled in the ``<samples>`` element, so there are three numbers there.  Besides the vectors that are to be integrated, we also specify that we want to use the vector "dampingVector"  [...]
+
+The equation of motion as written in the CDATA block looks almost identical to our desired equation of motion, except for the term based on the second derivative, which introduces an important new concept.  Inside the ``<operators>`` element, we can define any number of operators.  Operators are used to define functions in the transformed space of each dimension, which in this case is Fourier space.  The derivative of a function is equivalent to multiplying by :math:`i*k` in Fourier spac [...]
+
+Operators can be explicit (``kind="ex"``) or in the interaction picture (``kind="ip"``).  The interaction picture can be more efficient, but it restricts the possible syntax of the equation of motion.  Safe utilisation of interaction picture operators will be described later, but for now let us emphasise that **explicit operators should be used** unless the user is clear what they are doing.  That said, **XMDS2** will generate an error if the user tries to use interaction picture operato [...]
+
+The output of a partial differential equation offers more possibilities than an ordinary differential equation, and we examine some in this example.
+
+For vectors with transverse dimensions, we can sample functions of the vectors on the full lattice or a subset of the points.  In the ``<sampling_group>`` element, we must add a string called "basis" that determines the space in which each transverse dimension is to be sampled, optionally followed by the number of points to be sampled in parentheses.  If the number of points is not specified, it will default to a complete sampling of all points in that dimension.  If a non-zero number of [...]
+
+.. code-block:: xpdeint
+
+      <sampling_group basis="tau" initial_sample="yes">
+        <moments>density</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          density = mod2(phi);
+        ]]>
+      </sampling_group>
+
+The first output group samples the mod square of the vector "phi" over the full lattice of 128 points.
+
+If the lattice parameter is set to zero points, then the corresponding dimension is integrated.
+
+.. code-block:: xpdeint
+
+       <sampling_group basis="tau(0)" initial_sample="yes">
+         <moments>normalisation</moments>
+         <dependencies>wavefunction</dependencies>
+         <![CDATA[
+           normalisation = mod2(phi);
+         ]]>
+       </sampling_group>
+
+This second output group samples the normalisation of the wavefunction :math:`\int d\tau |\phi(\tau)|^2` over the domain of :math:`\tau`.  This output requires only a single real number per sample, so in the integrate element we have chosen to sample it many more times than the vectors themselves.
+
+Finally, functions of the vectors can be sampled with their dimensions in Fourier space.
+
+.. code-block:: xpdeint
+
+        <sampling_group basis="ktau(32)" initial_sample="yes">
+          <moments>densityK</moments>
+          <dependencies>wavefunction</dependencies>
+          <![CDATA[
+            densityK = mod2(phi);
+          ]]>
+        </sampling_group>
+
+The final output group above samples the mod square of the Fourier-space wavefunction phi on a sample of 32 points.
+
+
+.. _Kubo:
+
+Kubo Oscillator
+---------------
+
+This example demonstrates the integration of a stochastic differential equation.  We examine the Kubo oscillator, which is a complex variable whose phase is evolving according to a Wiener noise.  In a suitable rotating frame, the equation of motion for the variable is
+
+.. math::
+    \frac{dz}{dt} = i z \;\eta
+
+where :math:`\eta(t)` is the Wiener differential, and we interpret this as a Stratonovich equation.  In other common notation, this is sometimes written:
+
+.. math::
+    dz = i z \;\circ dW
+
+Most algorithms employed by XMDS require the equations to be input in the Stratonovich form.  Ito differential equations can always be transformed into Stratonovich euqations, and in this case the difference is equivalent to the choice of rotating frame.  This equation is solved by the following XMDS2 script:
+
+.. code-block:: xpdeint
+
+    <simulation xmds-version="2">
+      <name>kubo</name>
+      <author>Graham Dennis and Joe Hope</author>
+      <description>
+        Example Kubo oscillator simulation
+      </description>
+  
+      <geometry>
+        <propagation_dimension> t </propagation_dimension>
+      </geometry>
+  
+      <driver name="multi-path" paths="10000" />
+  
+      <features>
+        <error_check />
+        <benchmark />
+      </features>
+
+      <noise_vector name="drivingNoise" dimensions="" kind="wiener" type="real" method="dsfmt" seed="314 159 276">
+        <components>eta</components>
+      </noise_vector>
+  
+      <vector name="main" type="complex">
+        <components> z </components>
+        <initialisation>
+          <![CDATA[
+            z = 1.0;
+          ]]>
+        </initialisation>
+      </vector>
+  
+      <sequence>
+        <integrate algorithm="SI" interval="10" steps="1000">
+          <samples>100</samples>
+          <operators>
+            <integration_vectors>main</integration_vectors>
+            <dependencies>drivingNoise</dependencies>
+            <![CDATA[
+              dz_dt = i*z*eta;
+            ]]>
+          </operators>
+        </integrate>
+      </sequence>
+
+      <output>
+        <sampling_group initial_sample="yes">
+          <moments>zR zI</moments>
+          <dependencies>main</dependencies>
+          <![CDATA[
+            zR = z.Re();
+            zI = z.Im();
+          ]]>
+        </sampling_group>
+      </output>
+    </simulation>
+
+The first new item in this script is the ``<driver>`` element.  This element enables us to change top level management of the simulation.  Without this element, XMDS2 will integrate the stochastic equation as described.  With this element and the option ``name="multi-path"``, it will integrate it multiple times, using different random numbers each time.  The output will then contain the mean values and standard errors of your output variables.  The number of integrations included in the  [...]
+
+In the ``<features>`` element we have included the ``<error_check>`` element.  This performs the integration first with the specified number of steps (or with the specified tolerance), and then with twice the number of steps (or equivalently reduced tolerance).  The output then includes the difference between the output variables on the coarse and the fine grids as the 'error' in the output variables.  This error is particularly useful for stochastic integrations, where algorithms with a [...]
+
+We define the stochastic elements in a simulation with the ``<noise_vector>`` element.  
+
+.. code-block:: xpdeint
+
+    <noise_vector name="drivingNoise" dimensions="" kind="wiener" type="real" method="dsfmt" seed="314 159 276">
+     <components>eta</components>
+    </noise_vector>
+  
+This defines a vector that is used like any other, but it will be randomly generated with particular statistics and characteristics rather than initialised.  The name, dimensions and type tags are defined just as for normal vectors.  The names of the components are also defined in the same way.  The noise is defined as a Wiener noise here (``kind = "wiener"``), which is a zero-mean Gaussian random noise with an average variance equal to the discretisation volume (here it is just the step [...]
+
+We may also define a noise method to choose a non-default pseudo random number generator, and a seed for the random number generator.  Using a seed can be very useful when debugging the behaviour of a simulation, and many compilers have pseudo-random number generators that are superior to the default option (posix).
+
+The integrate block is using the semi-implicit algorithm (``algorithm="SI"``), which is a good default choice for stochastic problems, even though it is only second order convergent for deterministic equations.  More will be said about algorithm choice later, but for now we should note that adaptive algorithms based on Runge-Kutta methods are not guaranteed to converge safely for stochastic equations.  This can be particularly deceptive as they often succeed, particularly for almost any  [...]
+
+We include elements from the noise vector in the equation of motion just as we do for any other vector.  The default SI and Runge-Kutta algorithms converge to the *Stratonovich* integral.  Ito stochastic equations can be converted to Stratonovich form and vice versa.
+
+Executing the generated program 'kubo' gives slightly different output due to the "multi-path" driver.
+
+.. code-block:: none
+
+            $ ./kubo
+            Beginning full step integration ...
+            Starting path 1
+            Starting path 2
+
+            ... many lines omitted ...
+
+            Starting path 9999
+            Starting path 10000
+            Beginning half step integration ...
+            Starting path 1
+            Starting path 2
+
+            ... many lines omitted ...
+
+            Starting path 9999
+            Starting path 10000
+            Generating output for kubo
+            Maximum step error in moment group 1 was 4.942549e-04
+            Time elapsed for simulation is: 2.71 seconds
+
+The maximum step error in each moment group is given in absolute terms.  This is the largest difference between the full step integration and the half step integration.  While a single path might be very stochastic:
+
+.. figure:: images/kuboSingle.*
+    :align: center
+    
+    The mean value of the real and imaginary components of the z variable for a single path of the simulation.
+    
+The average over multiple paths can be increasingly smooth.  
+
+.. figure:: images/kubo10000.*
+    :align: center
+
+    The mean and standard error of the z variable averaged over 10000 paths, as given by this simulation.  It agrees within the standard error with the expected result of :math:`\exp(-t/2)`.
+
+
+.. _Fibre:
+
+Fibre Noise
+-----------
+
+This simulation is a stochastic partial differential equation, in which a one-dimensional damped field is subject to a complex noise. This script can be found in ``examples/fibre.xmds``.
+
+.. math::
+    \frac{\partial \psi}{\partial t} = -i \frac{\partial^2 \psi}{\partial x^2} -\gamma \psi+\beta \frac{1}{\sqrt{2}}\left(\eta_1(x)+i\eta_2(x)\right)
+    
+where the noise terms :math:`\eta_j(x,t)` are Wiener differentials and the equation is interpreted as a Stratonovich differential equation.  On a finite grid, these increments have variance :math:`\frac{1}{\Delta x \Delta t}`.
+
+.. code-block:: xpdeint
+    
+    <simulation xmds-version="2">
+      <name>fibre</name>
+      <author>Joe Hope and Graham Dennis</author>
+      <description>
+        Example fibre noise simulation
+      </description>
+  
+      <geometry>
+        <propagation_dimension> t </propagation_dimension>
+        <transverse_dimensions>
+          <dimension name="x" lattice="64"  domain="(-5, 5)" />
+        </transverse_dimensions>
+      </geometry>
+  
+      <driver name="mpi-multi-path" paths="8" />
+  
+      <features>
+        <auto_vectorise />
+        <benchmark />
+        <error_check />
+        <globals>
+          <![CDATA[
+          const real ggamma = 1.0;
+          const real beta = sqrt(M_PI*ggamma/10.0);
+          ]]>
+        </globals>
+      </features>
+  
+      <noise_vector name="drivingNoise" dimensions="x" kind="wiener" type="complex" method="dsfmt" seed="314 159 276">
+        <components>Eta</components>
+      </noise_vector>
+  
+      <vector name="main" initial_basis="x" type="complex">
+        <components>phi</components>
+        <initialisation>
+          <![CDATA[
+            phi = 0.0;
+          ]]>
+        </initialisation>
+      </vector>
+  
+      <sequence>
+        <integrate algorithm="SI" iterations="3" interval="2.5" steps="200000">
+          <samples>50</samples>
+          <operators>
+            <operator kind="ex" constant="yes">
+              <operator_names>L</operator_names>
+              <![CDATA[
+                L = -i*kx*kx;
+              ]]>
+            </operator>
+            <dependencies>drivingNoise</dependencies>
+            <integration_vectors>main</integration_vectors>
+            <![CDATA[
+              dphi_dt = L[phi] - ggamma*phi + beta*Eta;
+            ]]>
+          </operators>
+        </integrate>
+      </sequence>
+  
+      <output>
+        <sampling_group basis="kx" initial_sample="yes">
+          <moments>pow_dens</moments>
+          <dependencies>main</dependencies>
+          <![CDATA[
+            pow_dens = mod2(phi);
+          ]]>
+        </sampling_group>
+      </output>
+    </simulation>
+
+Note that the noise vector used in this example is complex-valued, and has the argument ``dimensions="x"`` to define it as a field of delta-correlated noises along the x-dimension.
+
+This simulation demonstrates the ease with which XMDS2 can be used in a parallel processing environment.  Instead of using the stochastic driver "multi-path", we simply replace it with "mpi-multi-path".  This instructs XMDS2 to write a parallel version of the program based on the widespread `MPI standard <http://www.open-mpi.org/>`_.  This protocol allows multiple processors or clusters of computers to work simultaneously on the same problem.  Free open source libraries implementing this [...]
+
+Executing this program is slightly different with the MPI option.  The details can change between MPI implementations, but as an example:
+
+.. code-block:: none
+
+        $xmds2 fibre.xmds
+        xmds2 version 2.1 "Happy Mollusc" (r2543)
+        Copyright 2000-2012 Graham Dennis, Joseph Hope, Mattias Johnsson
+                            and the xmds team
+        Generating source code...
+        ... done
+        Compiling simulation...
+        ... done. Type './fibre' to run.
+
+Note that different compile options (and potentially a different compiler) are used by XMDS2, but this is transparent to the user.  MPI simulations will have to be run using syntax that will depend on the MPI implementation.  Here we show the version based on the popular open source `Open-MPI <http://www.open-mpi.org/>`_ implementation.
+
+.. code-block:: none
+
+    $ mpirun -np 4 ./fibre
+    Found enlightenment... (Importing wisdom)
+    Planning for x <---> kx transform... done.
+    Beginning full step integration ...
+    Rank[0]: Starting path 1
+    Rank[1]: Starting path 2
+    Rank[2]: Starting path 3
+    Rank[3]: Starting path 4
+    Rank[3]: Starting path 8
+    Rank[0]: Starting path 5
+    Rank[1]: Starting path 6
+    Rank[2]: Starting path 7
+    Rank[3]: Starting path 4
+    Beginning half step integration ...
+    Rank[0]: Starting path 1
+    Rank[2]: Starting path 3
+    Rank[1]: Starting path 2
+    Rank[3]: Starting path 8
+    Rank[0]: Starting path 5
+    Rank[2]: Starting path 7
+    Rank[1]: Starting path 6
+    Generating output for fibre
+    Maximum step error in moment group 1 was 4.893437e-04
+    Time elapsed for simulation is: 20.99 seconds
+    
+In this example we used four processors.  The different processors are labelled by their "Rank", starting at zero.  Because the processors are working independently, the output from the different processors can come in a randomised order.  In the end, however, the .xsil and data files are constructed identically to the single processor outputs.
+
+The analytic solution to the stochastic averages of this equation is given by
+
+.. math::
+    \langle |\psi(k,t)|^2 \rangle = \exp(-2\gamma t)|\psi(k,0)|^2 +\frac{\beta^2 L_x}{4\pi \gamma} \left(1-\exp(-2\gamma t)\right)
+    
+where :math:`L_x` is the length of the x domain.  We see that a single integration of these equations is quite chaotic:
+
+.. figure:: images/fibreSingle.*
+    :align: center
+    
+    The momentum space density of the field as a function of time for a single path realisation.
+
+while an average of 1024 paths (change ``paths="8"`` to ``paths="1024"`` in the ``<driver>`` element) converges nicely to the analytic solution:
+
+.. figure:: images/fibre1024.*
+    :align: center
+    
+    The momentum space density of the field as a function of time for an average of 1024 paths.
+
+
+
+.. _IntegerDimensionExample:
+
+Integer Dimensions
+------------------
+
+This example shows how to handle systems with integer-valued transverse dimensions.  We will integrate the following set of equations
+
+.. math::
+    \frac{dx_j}{dt} = x_j \left(x_{j-1}-x_{j+1}\right)
+
+where :math:`x_j` are complex-valued variables defined on a ring, such that :math:`j\in \{0,j_{max}\}` and the :math:`x_{j_{max}+1}` variable is identified with the variable :math:`x_{0}`, and the variable :math:`x_{-1}` is identified with the variable :math:`x_{j_{max}}`.
+
+.. code-block:: xpdeint
+
+    <simulation xmds-version="2">
+      <name>integer_dimensions</name>
+      <author>Graham Dennis</author>
+      <description>
+        XMDS2 script to test integer dimensions.
+      </description>
+
+      <features>
+        <benchmark />
+        <error_check />
+        <bing />
+        <diagnostics /> <!-- This will make sure that all nonlocal accesses of dimensions are safe -->
+      </features>
+
+      <geometry>
+        <propagation_dimension> t </propagation_dimension>
+        <transverse_dimensions>
+          <dimension name="j" type="integer" lattice="5" domain="(0,4)" />
+        </transverse_dimensions>
+      </geometry>
+
+      <vector name="main" type="complex">
+        <components> x </components>
+        <initialisation>
+          <![CDATA[
+          x = 1.0e-3;
+          x(j => 0) = 1.0;
+          ]]>
+        </initialisation>
+      </vector>
+
+      <sequence>
+        <integrate algorithm="ARK45" interval="60" steps="25000" tolerance="1.0e-9">
+          <samples>1000</samples>
+          <operators>
+            <integration_vectors>main</integration_vectors>
+            <![CDATA[
+            long j_minus_one = (j-1) % _lattice_j;
+            if (j_minus_one < 0)
+              j_minus_one += _lattice_j;
+            long j_plus_one  = (j+1) % _lattice_j;
+            dx_dt(j => j) = x(j => j)*(x(j => j_minus_one) - x(j => j_plus_one));
+            ]]>
+          </operators>
+        </integrate>
+      </sequence>
+
+      <output>
+        <sampling_group basis="j" initial_sample="yes">
+          <moments>xR</moments>
+          <dependencies>main</dependencies>
+          <![CDATA[
+            xR = x.Re();
+          ]]>
+        </sampling_group>
+      </output>
+    </simulation>
+
+The first extra feature we have used in this script is the ``<diagnostics>`` element.  It performs run-time checking that our generated code does not accidentally attempt to access a part of our vector that does not exist.  Removing this tag will increase the speed of the simulation, but its presence helps catch coding errors.  
+
+The simulation defines a vector with a single transverse dimension labelled "j", of type "integer" ("int" and "long" can also be used as synonyms for "integer").  In the absence of an explicit type, the dimension is assumed to be real-valued.  The dimension has a "domain" argument as normal, defining the minimum and maximum values of the dimension's range.  The lattice element, if specified, is used as a check on the size of the domain, and will create an error if the two do not match.
+
+Integer-valued dimensions can be called non-locally.  Real-valued dimensions are typically coupled non-locally only through local operations in the transformed space of the dimension, but can be called non-locally in certain other situations as described in :ref:`the reference<ReferencingNonlocal>`.  The syntax for calling integer dimensions non-locally can be seen in the initialisation CDATA block:
+
+.. code-block:: xpdeint
+
+          x = 1.0e-3;
+          x(j => 0) = 1.0;
+
+where the syntax ``x(j => 0)`` is used to reference the variable :math:`x_0` directly.  We see a more elaborate example in the integrate CDATA block:
+
+.. code-block:: xpdeint
+
+            dx_dt(j => j) = x(j => j)*(x(j => j_minus_one) - x(j => j_plus_one));
+
+where the vector "x" is called using locally defined variables.  This syntax is chosen so that multiple dimensions can be addressed non-locally with minimal possibility for confusion.
+
+
+
+
+.. _WignerArguments:
+
+Wigner Function
+---------------
+
+This example integrates the two-dimensional partial differential equation
+
+.. math::
+    \begin{split}
+    \frac{\partial W}{\partial t} &= \Bigg[ \left(\omega + \frac{U_{int}}{\hbar}\left(x^2+y^2-1\right)\right) \left(x \frac{\partial}{\partial y} 
+    - y \frac{\partial}{\partial x}\right)\\
+    &\phantom{=\Bigg[} - \frac{U_{int}}{16 \hbar}\left(x\left(\frac{\partial^3}{\partial x^2 \partial y}
+    +\frac{\partial^3}{\partial y^3}\right)-y\left(\frac{\partial^3}{\partial y^2 \partial x}+\frac{\partial^3}{\partial x^3}\right)\right)\Bigg]W(x,y,t)
+    \end{split}
+
+with the added restriction that the derivative is forced to zero outside a certain radius.  This extra condition helps maintain the long-term stability of the integration. The script can be found in ``examples/wigner_arguments_mpi.xmds`` under your XMDS2 installation directory.
+
+.. code-block:: xpdeint
+
+    <simulation xmds-version="2">
+      <name>wigner</name>
+      <author>Graham Dennis and Joe Hope</author>
+      <description>
+        Simulation of the Wigner function for an anharmonic oscillator with the initial state
+        being a coherent state.
+      </description>
+      <features>
+        <benchmark />
+        <globals>
+          <![CDATA[
+            real Uint_hbar_on16;
+          ]]>
+        </globals>
+        <arguments>
+          <argument name="omega" type="real" default_value="0.0" />
+          <argument name="alpha_0"     type="real" default_value="3.0" />
+          <argument name="absorb"     type="real" default_value="8.0" />
+          <argument name="width" type="real" default_value="0.3" />
+          <argument name="Uint_hbar" type="real" default_value="1.0" />
+          <![CDATA[
+            /* derived constants */
+            Uint_hbar_on16 = Uint_hbar/16.0;
+          ]]>
+        </arguments>
+        <bing />
+        <fftw plan="patient" />
+        <openmp />
+      </features>
+
+      <driver name="distributed-mpi" />
+
+      <geometry>
+        <propagation_dimension> t </propagation_dimension>
+        <transverse_dimensions>
+          <dimension name="x" lattice="128"  domain="(-6, 6)" />
+          <dimension name="y" lattice="128"  domain="(-6, 6)" />
+        </transverse_dimensions>
+      </geometry>
+
+      <vector name="main" initial_basis="x y" type="complex">
+        <components> W </components>
+        <initialisation>
+          <![CDATA[
+            W = 2.0/M_PI * exp(-2.0*(y*y + (x-alpha_0)*(x-alpha_0)));
+          ]]>
+        </initialisation>
+      </vector>
+
+      <vector name="dampConstants" initial_basis="x y" type="real">
+        <components>damping</components>
+        <initialisation>
+          <![CDATA[
+          if (sqrt(x*x + y*y) > _max_x-width)
+            damping = 0.0;
+          else
+            damping = 1.0;
+          ]]>
+        </initialisation>
+      </vector>
+
+      <sequence>
+        <integrate algorithm="ARK89" tolerance="1e-7" interval="7.0e-4" steps="100000">
+          <samples>50</samples>
+          <operators>
+            <operator kind="ex" constant="yes">
+              <operator_names>Lx Ly Lxxx Lxxy Lxyy Lyyy</operator_names>
+              <![CDATA[
+                Lx = i*kx;
+                Ly = i*ky;
+                Lxxx = -i*kx*kx*kx;
+                Lxxy = -i*kx*kx*ky;
+                Lxyy = -i*kx*ky*ky;
+                Lyyy = -i*ky*ky*ky;
+              ]]>
+            </operator>
+            <integration_vectors>main</integration_vectors>
+            <dependencies>dampConstants</dependencies>
+            <![CDATA[
+            real rotation = omega + Uint_hbar*(-1.0 + x*x + y*y);
+
+            dW_dt = damping * ( rotation * (x*Ly[W] - y*Lx[W]) 
+                        - Uint_hbar_on16*( x*(Lxxy[W] + Lyyy[W]) - y*(Lxyy[W] + Lxxx[W]) )
+                    );
+            ]]>
+          </operators>
+        </integrate>
+      </sequence>
+
+      <output>
+        <sampling_group basis="x y" initial_sample="yes">
+          <moments>WR WI</moments>
+          <dependencies>main</dependencies>
+          <![CDATA[
+            _SAMPLE_COMPLEX(W);
+          ]]>
+        </sampling_group>
+      </output>
+    </simulation>
+
+This example demonstrates two new features of XMDS2.  The first is the use of parallel processing for a deterministic problem.  The FFTW library only allows MPI processing of multidimensional vectors.  For multidimensional simulations, the generated program can be parallelised simply by adding the ``name="distributed-mpi"`` argument to the ``<driver>`` element.  
+
+.. code-block:: xpdeint
+
+    $ xmds2 wigner_argument_mpi.xmds 
+    xmds2 version 2.1 "Happy Mollusc" (r2680)
+    Copyright 2000-2012 Graham Dennis, Joseph Hope, Mattias Johnsson
+                        and the xmds team
+    Generating source code...
+    ... done
+    Compiling simulation...
+    ... done. Type './wigner' to run.
+        
+To use multiple processors, the final program is then called using the (implementation specific) MPI wrapper:
+
+.. code-block:: xpdeint
+
+    $ mpirun -np 2 ./wigner
+    Planning for (distributed x, y) <---> (distributed ky, kx) transform... done.
+    Planning for (distributed x, y) <---> (distributed ky, kx) transform... done.
+    Sampled field (for moment group #1) at t = 0.000000e+00
+    Current timestep: 5.908361e-06
+    Sampled field (for moment group #1) at t = 1.400000e-05
+    Current timestep: 4.543131e-06
+    
+    ...
+
+The possible acceleration achievable when parallelising a given simulation depends on a great many things including available memory and cache.  As a general rule, it will improve as the simulation size gets larger, but the easiest way to find out is to test.  The optimum speed up is obviously proportional to the number of available processing cores.
+
+The second new feature in this simulation is the ``<arguments>`` element in the ``<features>`` block.  This is a way of specifying global variables with a given type that can then be input at run time.  The variables are specified in a self explanatory way
+
+.. code-block:: xpdeint
+
+        <arguments>
+          <argument name="omega" type="real" default_value="0.0" />
+            ...
+          <argument name="Uint_hbar" type="real" default_value="1.0" />
+        </arguments>
+        
+where the "default_value" is used as the valuable of the variable if no arguments are given.  In the absence of the generating script, the program can document its options with the ``--help`` argument:
+
+.. code-block:: none
+
+    $ ./wigner --help
+    Usage: wigner --omega <real> --alpha_0 <real> --absorb <real> --width <real> --Uint_hbar <real>
+
+    Details:
+    Option		Type		Default value
+    -o,  --omega	real 		0.0
+    -a,  --alpha_0	real 		3.0
+    -b,  --absorb	real 		8.0
+    -w,  --width	real 		0.3
+    -U,  --Uint_hbar	real 		1.0
+
+We can change one or more of these variables' values in the simulation by passing it at run time.
+
+.. code-block:: none
+
+    $ mpirun -np 2 ./wigner --omega 0.1 --alpha_0 2.5 --Uint_hbar 0
+    Found enlightenment... (Importing wisdom)
+    Planning for (distributed x, y) <---> (distributed ky, kx) transform... done.
+    Planning for (distributed x, y) <---> (distributed ky, kx) transform... done.
+    Sampled field (for moment group #1) at t = 0.000000e+00
+    Current timestep: 1.916945e-04
+    
+    ...
+    
+The values that were used for the variables, whether default or passed in, are stored in the output file (wigner.xsil).
+
+.. code-block:: xpdeint
+
+    <info>
+    Script compiled with XMDS2 version 2.1 "Happy Mollusc" (r2680)
+    See http://www.xmds.org for more information.
+
+    Variables that can be specified on the command line:
+      Command line argument omega = 1.000000e-01
+      Command line argument alpha_0 = 2.500000e+00
+      Command line argument absorb = 8.000000e+00
+      Command line argument width = 3.000000e-01
+      Command line argument Uint_hbar = 0.000000e+00
+    </info>
+    
+Finally, note the shorthand used in the output group
+
+.. code-block:: xpdeint
+
+      <![CDATA[
+        _SAMPLE_COMPLEX(W);
+      ]]>
+
+which is short for
+
+.. code-block:: xpdeint
+
+      <![CDATA[
+        WR = W.Re();
+        WI = W.Im();
+      ]]>
+ 
+
+.. _GroundStateBEC:
+
+Finding the Ground State of a BEC (continuous renormalisation)
+--------------------------------------------------------------
+
+This simulation solves another partial differential equation, but introduces several powerful new features in XMDS2.  The nominal problem is the calculation of the lowest energy eigenstate of a non-linear Schrödinger equation:
+
+.. math::
+    \frac{\partial \phi}{\partial t} = i \left[\frac{1}{2}\frac{\partial^2}{\partial y^2} - V(y) - U_{int}|\phi|^2\right]\phi
+
+which can be found by evolving the above equation in imaginary time while keeping the normalisation constant.  This causes eigenstates to exponentially decay at the rate of their eigenvalue, so after a short time only the state with the lowest eigenvalue remains.  The evolution equation is straightforward:
+
+.. math::
+    \frac{\partial \phi}{\partial t} = \left[\frac{1}{2}\frac{\partial^2}{\partial y^2} - V(y) - U_{int}|\phi|^2\right]\phi
+
+but we will need to use new XMDS2 features to manage the normalisation of the function :math:`\phi(y,t)`.  The normalisation for a non-linear Schrödinger equation is given by :math:`\int dy |\phi(y,t)|^2 = N_{particles}`, where :math:`N_{particles}` is the number of particles described by the wavefunction.  
+
+The code for this simulation can be found in ``examples/groundstate_workedexamples.xmds``:
+
+.. code-block:: xpdeint
+
+    <simulation xmds-version="2">
+      <name>groundstate</name>
+      <author>Joe Hope</author>
+      <description>
+        Calculate the ground state of the non-linear Schrodinger equation in a harmonic magnetic trap.
+        This is done by evolving it in imaginary time while re-normalising each timestep.
+      </description>
+
+      <features>
+        <auto_vectorise />
+        <benchmark />
+        <bing />
+        <fftw plan="exhaustive" />
+        <globals>
+          <![CDATA[
+            const real Uint = 2.0;
+            const real Nparticles = 5.0;
+          ]]>
+        </globals>
+      </features>
+
+      <geometry>
+        <propagation_dimension> t </propagation_dimension>
+        <transverse_dimensions>
+          <dimension name="y" lattice="256"  domain="(-15.0, 15.0)" />
+        </transverse_dimensions>
+      </geometry>
+
+      <vector name="potential" initial_basis="y" type="real">
+        <components> V1 </components>
+        <initialisation>
+          <![CDATA[
+            V1  = 0.5*y*y;
+          ]]>
+        </initialisation>
+      </vector>
+
+      <vector name="wavefunction" initial_basis="y" type="complex">
+        <components> phi </components>
+        <initialisation>
+          <![CDATA[
+            if (fabs(y) < 3.0) {
+              phi = 1.0;
+              // This will be automatically normalised later
+            } else {
+              phi = 0.0;
+            }
+                ]]>
+        </initialisation>
+      </vector>
+
+      <computed_vector name="normalisation" dimensions="" type="real">
+        <components> Ncalc </components>
+        <evaluation>
+          <dependencies basis="y">wavefunction</dependencies>
+          <![CDATA[
+            // Calculate the current normalisation of the wave function.
+            Ncalc = mod2(phi);
+          ]]>
+        </evaluation>
+      </computed_vector>
+
+      <sequence>
+          <filter>
+            <![CDATA[
+              printf("Hello world from a filter segment!\n");
+            ]]>
+          </filter>
+
+        <filter>
+            <dependencies>normalisation wavefunction</dependencies>
+          <![CDATA[
+            phi *= sqrt(Nparticles/Ncalc);
+          ]]>
+        </filter>
+
+        <integrate algorithm="ARK45" interval="1.0" steps="4000" tolerance="1e-10">
+          <samples>25 4000</samples>
+          <filters where="step end">
+            <filter>
+              <dependencies>wavefunction normalisation</dependencies>
+              <![CDATA[
+                // Correct normalisation of the wavefunction
+                phi *= sqrt(Nparticles/Ncalc);
+              ]]>
+            </filter>
+          </filters>
+          <operators>
+            <operator kind="ip" constant="yes">
+              <operator_names>T</operator_names>
+              <![CDATA[
+                T = -0.5*ky*ky;
+              ]]>
+            </operator>
+            <integration_vectors>wavefunction</integration_vectors>
+            <dependencies>potential</dependencies>
+            <![CDATA[
+              dphi_dt = T[phi] - (V1 + Uint*mod2(phi))*phi;
+            ]]>
+          </operators>
+        </integrate>
+
+        <breakpoint filename="groundstate_break.xsil">
+          <dependencies basis="ky">wavefunction </dependencies>
+        </breakpoint>
+
+      </sequence>
+
+      <output>
+        <sampling_group basis="y" initial_sample="yes">
+          <moments>norm_dens</moments>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            norm_dens = mod2(phi);
+          ]]>
+        </sampling_group>
+        
+        <sampling_group initial_sample="yes">
+          <moments>norm</moments>
+          <dependencies>normalisation</dependencies>
+          <![CDATA[
+            norm = Ncalc;
+          ]]>
+        </sampling_group>
+      </output>
+    </simulation>
+
+We have used the ``plan="exhasutive"`` option in the ``<fftw>`` element to ensure that the absolute fastest transform method is found.  Because the FFTW package stores the results of its tests (by default in the ~/.xmds/wisdom directory), this option does not cause significant computational overhead, except perhaps on the very first run of a new program.
+
+This simulation introduces the first example of a very powerful feature in XMDS2: the ``<computed_vector>`` element.  This has syntax like any other vector, including possible dependencies on other vectors, and an ability to be used in any element that can use vectors.  The difference is that, much like noise vectors, computed vectors are recalculated each time they are required.  This means that a computed vector can never be used as an integration vector, as its values are not stored.  [...]
+
+The difference between a computed vector and a stored vector is emphasised by the replacement of the ``<initialisation>`` element with an ``<evaluation>`` element.  Apart from the name, they have virtually identical purpose and syntax.  
+
+.. code-block:: xpdeint
+
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components> Ncalc </components>
+    <evaluation>
+      <dependencies basis="y">wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi);
+      ]]>
+    </evaluation>
+  </computed_vector>
+
+Here, our computed vector has no transverse dimensions and depends on the components of "wavefunction", so the extra transverse dimensions are integrated out.  This code therefore integrates the square modulus of the field, and returns it in the variable "Ncalc".  This will be used below to renormalise the "phi" field.  Before we examine that process, we have to introduce the ``<filter>`` element.
+
+The ``<filter>`` element can be placed in the ``<sequence>`` element, or inside ``<integrate>`` elements as we will see next.  Elements placed in the ``<sequence>`` element are executed in the order they are found in the .xmds file.  Filter elements place the included CDATA block directly into the generated program at the designated position.  If the element does not contain any dependencies, like in our first example, then the code is placed alone:
+
+.. code-block:: xpdeint
+
+    <filter>
+      <![CDATA[
+        printf("Hello world from a filter segment!\n");
+      ]]>
+    </filter>
+
+This filter block merely prints a string into the output when the generated program is run.  If the ``<filter>`` element contains dependencies, then the variables defined in those vectors (or computed vectors, or noise vectors) will be available, and the CDATA block will be placed inside loops that run over all the transverse dimensions used by the included vectors.  The second filter block in this example depends on both the "wavefunction" and "normalisation" vectors:
+
+.. code-block:: xpdeint
+
+    <filter>
+        <dependencies>normalisation wavefunction</dependencies>
+      <![CDATA[
+        phi *= sqrt(Nparticles/Ncalc);
+      ]]>
+    </filter>
+
+Since this filter depends on a vector with the transverse dimension "y", this filter will execute for each point in "y".  This code multiplies the value of the field "phi" by the factor required to produce a normalised function in the sense that  :math:`\int dy |\phi(y,t)|^2 = N_{particles}`.
+
+The next usage of a ``<filter>`` element in this program is inside the ``<integrate>`` element, where all filters are placed inside a ``<filters>`` element.
+
+.. code-block:: xpdeint
+
+    <filters where="step end">
+      <filter>
+        <dependencies>wavefunction normalisation</dependencies>
+        <![CDATA[
+          // Correct normalisation of the wavefunction
+          phi *= sqrt(Nparticles/Ncalc);
+        ]]>
+      </filter>
+    </filters>
+
+Filters placed in an integration block are applied each integration step.  The "where" flag is used to determine whether the filter should be applied directly before or directly after each integration step.  The default value for the where flag is ``where="step start"``, but in this case we chose "step end" to make sure that the final output was normalised after the last integration step.
+
+At the end of the sequence element we introduce the ``<breakpoint>`` element.  This serves two purposes.  The first is a simple matter of convenience.  Often when we manage our input and output from a simulation, we are interested solely in storing the exact state of our integration vectors.  A breakpoint element does exactly that, storing the components of any vectors contained within, taking all the normal options of the ``<output>`` element but not requiring any ``<sampling_group>`` e [...]
+
+.. code-block:: xpdeint
+
+    <breakpoint filename="groundstate_break.xsil">
+      <dependencies basis="ky">wavefunction</dependencies>
+    </breakpoint>
+
+If the filename argument is omitted, the output filenames are numbered sequentially.  Any given ``<breakpoint>`` element must only depend on vectors with identical dimensions.
+
+This program begins with a very crude guess to the ground state, but it rapidly converges to the lowest eigenstate.
+
+.. figure:: images/groundstateU2.*
+    :align: center
+    
+    The shape of the ground state rapidly approaches the lowest eigenstate.  For weak nonlinearities, it is nearly Gaussian.
+    
+.. figure:: images/groundstateU20.*
+    :align: center
+
+    When the nonlinear term is larger (:math:`U=20`), the ground state is wider and more parabolic.
+
+
+
+
+.. _HermiteGaussGroundStateBEC:
+
+Finding the Ground State of a BEC again
+---------------------------------------
+
+Here we repeat the same simulation as in the :ref:`GroundStateBEC` example, using a different transform basis.  While spectral methods are very effective, and Fourier transforms are typically very efficient due to the Fast Fourier transform algorithm, it is often desirable to describe nonlocal evolution in bases other than the Fourier basis.  The previous calculation was the Schrödinger equation with a harmonic potential and a nonlinear term.  The eigenstates of such a system are known a [...]
+
+.. math::
+    \left[-\frac{\hbar}{2 m}\frac{\partial^2}{\partial x^2} + \frac{1}{2}\omega^2 x^2\right]\phi_n(x) = E_n \phi_n(x)
+
+where
+
+.. math::
+    \phi_n(x,t) = \sqrt{\frac{1}{2^n n!}} \left(\frac{m \omega}{\hbar \pi}\right)^\frac{1}{4} e^{-\frac{m \omega x^2}{2\hbar}} H_n\left(\sqrt{\frac{m \omega}{\hbar}x}\right),\;\;\;\;\;\;E_n = \left(n+\frac{1}{2}\right) \omega
+
+where :math:`H_n(u)` are the physicist's version of the Hermite polynomials.  Rather than describing the derivatives as diagonal terms in Fourier space, we therefore have the option of describing the entire :math:`-\frac{\hbar}{2 m}\frac{\partial^2}{\partial x^2} + \frac{1}{2}\omega^2 x^2` term as a diagonal term in the hermite-Gaussian basis.  Here is an XMDS2 simulation that performs the integration in this basis. The following is a simplified version of the ``examples/hermitegauss_gro [...]
+
+.. code-block:: xpdeint
+
+    <simulation xmds-version="2">
+      <name>hermitegauss_groundstate</name>
+      <author>Graham Dennis</author>
+      <description>
+        Solve for the groundstate of the Gross-Pitaevskii equation using the hermite-Gauss basis.
+      </description>
+  
+      <features>
+        <benchmark />
+        <bing />
+        <validation kind="run-time" />
+        <globals>
+          <![CDATA[
+            const real omegaz = 2*M_PI*20;
+            const real omegarho = 2*M_PI*200;
+            const real hbar = 1.05457148e-34;
+            const real M = 1.409539200000000e-25;
+            const real g = 9.8;
+            const real scatteringLength = 5.57e-9;
+            const real transverseLength = 1e-5;
+            const real Uint = 4.0*M_PI*hbar*hbar*scatteringLength/M/transverseLength/transverseLength;
+            const real Nparticles = 5.0e5;
+        
+            /* offset constants */
+            const real EnergyOffset = 0.3*pow(pow(3.0*Nparticles/4*omegarho*Uint,2.0)*M/2.0,1/3.0); // 1D   
+          ]]>
+        </globals>
+      </features>
+  
+      <geometry>
+        <propagation_dimension> t </propagation_dimension>
+        <transverse_dimensions>
+          <dimension name="x" lattice="100" length_scale="sqrt(hbar/(M*omegarho))" transform="hermite-gauss" />
+        </transverse_dimensions>
+      </geometry>
+  
+      <vector name="wavefunction" initial_basis="x" type="complex">
+        <components> phi </components>
+        <initialisation>
+          <![CDATA[
+          phi = sqrt(Nparticles) * pow(M*omegarho/(hbar*M_PI), 0.25) * exp(-0.5*(M*omegarho/hbar)*x*x);
+          ]]>
+        </initialisation>
+      </vector>
+  
+      <computed_vector name="normalisation" dimensions="" type="real">
+        <components> Ncalc </components>
+        <evaluation>
+          <dependencies basis="x">wavefunction</dependencies>
+          <![CDATA[
+            // Calculate the current normalisation of the wave function.
+            Ncalc = mod2(phi);
+          ]]>
+        </evaluation>
+      </computed_vector>
+  
+      <sequence>
+        <integrate algorithm="ARK45" interval="1.0e-2" steps="4000"  tolerance="1e-10">
+          <samples>100 100</samples>
+          <filters>
+            <filter>
+              <dependencies>wavefunction normalisation</dependencies>
+              <![CDATA[
+                // Correct normalisation of the wavefunction
+                phi *= sqrt(Nparticles/Ncalc);
+              ]]>
+            </filter>
+          </filters>
+          <operators>
+            <operator kind="ip" constant="yes" type="real">
+              <operator_names>L</operator_names>
+              <![CDATA[
+                L = EnergyOffset/hbar - (nx + 0.5)*omegarho;
+              ]]>
+            </operator>
+            <integration_vectors>wavefunction</integration_vectors>
+            <![CDATA[
+              dphi_dt = L[phi] - Uint/hbar*mod2(phi)*phi;
+            ]]>
+          </operators>
+        </integrate>
+
+        <filter>
+            <dependencies>normalisation wavefunction</dependencies>
+          <![CDATA[
+            phi *= sqrt(Nparticles/Ncalc);
+          ]]>
+        </filter>
+    
+        <breakpoint filename="hermitegauss_groundstate_break.xsil" format="ascii">
+          <dependencies basis="nx">wavefunction</dependencies>
+        </breakpoint>
+      </sequence>
+  
+      <output>
+        <sampling_group basis="x" initial_sample="yes">
+          <moments>dens</moments>
+          <dependencies>wavefunction</dependencies>
+          <![CDATA[
+            dens = mod2(phi);
+          ]]>
+        </sampling_group>
+        <sampling_group basis="kx" initial_sample="yes">
+          <moments>dens</moments>
+          <dependencies>wavefunction</dependencies>
+          <![CDATA[
+            dens = mod2(phi);
+          ]]>
+        </sampling_group>
+      </output>
+    </simulation>
+
+The major difference in this simulation code, aside from the switch back from dimensionless units, is the new transverse dimension type in the ``<geometry>`` element.
+
+.. code-block:: xpdeint
+ 
+          <dimension name="x" lattice="100" length_scale="sqrt(hbar/(M*omegarho))" transform="hermite-gauss" />
+
+We have explicitly defined the "transform" option, which by defaults expects the Fourier transform.  The ``transform="hermite-gauss"`` option requires the 'mpmath' package installed, just as Fourier transforms require the FFTW package to be installed.  The "lattice" option details the number of hermite-Gaussian eigenstates to include, and automatically starts from the zeroth order polynomial and increases.  The number of hermite-Gaussian modes fully determines the irregular spatial grid  [...]
+
+The ``length_scale="sqrt(hbar/(M*omegarho))"`` option requires a real number, but since this script defines it in terms of variables, XMDS2 is unable to verify that the resulting function is real-valued at the time of generating the code.  XMDS2 will therefore fail to compile this program without the feature:
+
+.. code-block:: xpdeint
+
+        <validation kind="run-time" />
+
+which disables many of these checks at the time of writing the C-code.
+
+.. _2DMultistateSE:
+
+Multi-component Schrödinger equation
+------------------------------------
+
+This example demonstrates a simple method for doing matrix calculations in XMDS2.  We are solving the multi-component PDE
+
+.. math::
+    \frac{\partial \phi_j(x,y)}{\partial t} = \frac{i}{2}\left(\frac{\partial^2}{\partial x^2}+\frac{\partial^2}{\partial y^2}\right)\phi_j(x,y) - i U(x,y) \sum_k V_{j k}\phi_k(x,y)
+    
+where the last term is more commonly written as a matrix multiplication.  Writing this term out explicitly is feasible for a small number of components, but when the number of components becomes large, or perhaps :math:`V_{j k}` should be precomputed for efficiency reasons, it is useful to be able to perform this sum over the integer dimensions automatically.  This example show how this can be done naturally using a computed vector.  The XMDS2 script is as follows:
+
+.. code-block:: xpdeint
+
+        <simulation xmds-version="2">
+          <name>2DMSse</name>
+
+          <author>Joe Hope</author>
+          <description>
+            Schroedinger equation for multiple internal states in two spatial dimensions.
+          </description>
+
+          <features>
+              <benchmark />
+              <bing />
+              <fftw plan="patient" />
+              <openmp />
+              <auto_vectorise />
+             </features>
+
+          <geometry>
+              <propagation_dimension> t </propagation_dimension>
+              <transverse_dimensions>
+                  <dimension name="x" lattice="32"  domain="(-6, 6)" />
+                  <dimension name="y" lattice="32"  domain="(-6, 6)" />
+                  <dimension name="j" type="integer" lattice="2" domain="(0,1)" aliases="k"/>
+              </transverse_dimensions>
+           </geometry>
+
+          <vector name="wavefunction" type="complex" dimensions="x y j">
+            <components> phi </components>
+            <initialisation>
+              <![CDATA[
+              phi = j*sqrt(2/sqrt(M_PI/2))*exp(-(x*x+y*y)/4)*exp(i*0.1*x);
+              ]]>
+            </initialisation>
+          </vector>
+
+          <vector name="spatialInteraction" type="real" dimensions="x y">
+            <components> U </components>
+            <initialisation>
+              <![CDATA[
+              U=exp(-(x*x+y*y)/4);
+              ]]>
+            </initialisation>
+          </vector>
+
+          <vector name="internalInteraction" type="real" dimensions="j k">
+            <components> V </components>
+            <initialisation>
+              <![CDATA[
+              V=3*(j*(1-k)+(1-j)*k);
+              ]]>
+            </initialisation>
+          </vector>
+
+          <computed_vector name="coupling" dimensions="x y j" type="complex">
+            <components>
+              VPhi
+            </components>
+            <evaluation>
+              <dependencies basis="x y j k">internalInteraction wavefunction</dependencies>
+              <![CDATA[
+                // Calculate the current normalisation of the wave function.
+                VPhi = V*phi(j => k);
+              ]]>
+            </evaluation>
+          </computed_vector>
+
+          <sequence>
+            <integrate algorithm="ARK45" interval="2.0" tolerance="1e-7">
+              <samples>20 100</samples>
+              <operators>
+                <integration_vectors>wavefunction</integration_vectors>
+                <operator kind="ex" constant="yes">
+                  <operator_names>Ltt</operator_names>
+                  <![CDATA[
+                    Ltt = -i*(kx*kx+ky*ky)*0.5;
+                  ]]>
+                </operator>
+                <![CDATA[
+                dphi_dt = Ltt[phi] -i*U*VPhi;
+                ]]>
+                <dependencies>spatialInteraction coupling</dependencies>
+              </operators>
+            </integrate>
+          </sequence>
+
+          <output>
+            <sampling_group basis="x y j" initial_sample="yes">
+              <moments>density</moments>
+              <dependencies>wavefunction</dependencies>
+              <![CDATA[
+                density = mod2(phi);
+              ]]>
+            </sampling_group>
+            <sampling_group basis="x(0) y(0) j" initial_sample="yes">
+              <moments>normalisation</moments>
+              <dependencies>wavefunction</dependencies>
+              <![CDATA[
+                normalisation = mod2(phi);
+              ]]>
+            </sampling_group>
+          </output>
+        </simulation>
+
+The only truly new feature in this script is the "aliases" option on a dimension.  The integer-valued dimension in this script indexes the components of the PDE (in this case only two).  The  :math:`V_{j k}` term is required to be a square array of dimension of this number of components.  If we wrote the k-index of :math:`V_{j k}` using a separate ``<dimension>`` element, then we would not be enforcing the requirement that the matrix be square.  Instead, we note that we will be using mul [...]
+
+.. code-block:: xpdeint
+
+                  <dimension name="j" type="integer" lattice="2" domain="(0,1)" aliases="k"/>
+
+This means that we can use the index "k", which will have exactly the same properties as the "j" index.  This is used to define the "V" function in the "internalInteraction" vector.  Now, just as we use a computed vector to perform an integration over our fields, we use a computed vector to calculate the sum.
+
+.. code-block:: xpdeint
+
+        <computed_vector name="coupling" dimensions="x y j" type="complex">
+          <components>
+            VPhi
+          </components>
+          <evaluation>
+            <dependencies basis="x y j k">internalInteraction wavefunction</dependencies>
+            <![CDATA[
+              // Calculate the current normalisation of the wave function.
+              VPhi = V*phi(j => k);
+            ]]>
+          </evaluation>
+        </computed_vector>
+
+Since the output dimensions of the computed vector do not include a "k" index, this index is integrated.  The volume element for this summation is the spacing between neighbouring values of "j", and since this spacing is one, this integration is just a sum over k, as required.
+
+
+By this point, we have introduced most of the important features in XMDS2.  More details on other transform options and rarely used features can be found in the :ref:`advancedTopics` section.
+
+
diff --git a/documentation/_sources/xsil2graphics2.txt b/documentation/_sources/xsil2graphics2.txt
new file mode 100644
index 0000000..0665961
--- /dev/null
+++ b/documentation/_sources/xsil2graphics2.txt
@@ -0,0 +1,8 @@
+.. _xsil2graphics2:
+
+xsil2graphics2
+===============
+
+**xsil2graphics2** is a way of converting ".xsil" files to formats that other programs can read.  The syntax is described in the :ref:`QuickStartTutorial`, and by using the ``xsil2graphics2 --help`` option.  It currently can covert any output format for use by Mathematica.
+
+We recommend HDF5 format instead of the binary format for output and input, as many visualisation tools can already read/write to this format directly.
\ No newline at end of file
diff --git a/documentation/_static/ajax-loader.gif b/documentation/_static/ajax-loader.gif
new file mode 100644
index 0000000..61faf8c
Binary files /dev/null and b/documentation/_static/ajax-loader.gif differ
diff --git a/documentation/_static/basic.css b/documentation/_static/basic.css
new file mode 100644
index 0000000..a04c8e1
--- /dev/null
+++ b/documentation/_static/basic.css
@@ -0,0 +1,540 @@
+/*
+ * basic.css
+ * ~~~~~~~~~
+ *
+ * Sphinx stylesheet -- basic theme.
+ *
+ * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+/* -- main layout ----------------------------------------------------------- */
+
+div.clearer {
+    clear: both;
+}
+
+/* -- relbar ---------------------------------------------------------------- */
+
+div.related {
+    width: 100%;
+    font-size: 90%;
+}
+
+div.related h3 {
+    display: none;
+}
+
+div.related ul {
+    margin: 0;
+    padding: 0 0 0 10px;
+    list-style: none;
+}
+
+div.related li {
+    display: inline;
+}
+
+div.related li.right {
+    float: right;
+    margin-right: 5px;
+}
+
+/* -- sidebar --------------------------------------------------------------- */
+
+div.sphinxsidebarwrapper {
+    padding: 10px 5px 0 10px;
+}
+
+div.sphinxsidebar {
+    float: left;
+    width: 230px;
+    margin-left: -100%;
+    font-size: 90%;
+}
+
+div.sphinxsidebar ul {
+    list-style: none;
+}
+
+div.sphinxsidebar ul ul,
+div.sphinxsidebar ul.want-points {
+    margin-left: 20px;
+    list-style: square;
+}
+
+div.sphinxsidebar ul ul {
+    margin-top: 0;
+    margin-bottom: 0;
+}
+
+div.sphinxsidebar form {
+    margin-top: 10px;
+}
+
+div.sphinxsidebar input {
+    border: 1px solid #98dbcc;
+    font-family: sans-serif;
+    font-size: 1em;
+}
+
+div.sphinxsidebar #searchbox input[type="text"] {
+    width: 170px;
+}
+
+div.sphinxsidebar #searchbox input[type="submit"] {
+    width: 30px;
+}
+
+img {
+    border: 0;
+}
+
+/* -- search page ----------------------------------------------------------- */
+
+ul.search {
+    margin: 10px 0 0 20px;
+    padding: 0;
+}
+
+ul.search li {
+    padding: 5px 0 5px 20px;
+    background-image: url(file.png);
+    background-repeat: no-repeat;
+    background-position: 0 7px;
+}
+
+ul.search li a {
+    font-weight: bold;
+}
+
+ul.search li div.context {
+    color: #888;
+    margin: 2px 0 0 30px;
+    text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+    font-weight: bold;
+}
+
+/* -- index page ------------------------------------------------------------ */
+
+table.contentstable {
+    width: 90%;
+}
+
+table.contentstable p.biglink {
+    line-height: 150%;
+}
+
+a.biglink {
+    font-size: 1.3em;
+}
+
+span.linkdescr {
+    font-style: italic;
+    padding-top: 5px;
+    font-size: 90%;
+}
+
+/* -- general index --------------------------------------------------------- */
+
+table.indextable {
+    width: 100%;
+}
+
+table.indextable td {
+    text-align: left;
+    vertical-align: top;
+}
+
+table.indextable dl, table.indextable dd {
+    margin-top: 0;
+    margin-bottom: 0;
+}
+
+table.indextable tr.pcap {
+    height: 10px;
+}
+
+table.indextable tr.cap {
+    margin-top: 10px;
+    background-color: #f2f2f2;
+}
+
+img.toggler {
+    margin-right: 3px;
+    margin-top: 3px;
+    cursor: pointer;
+}
+
+div.modindex-jumpbox {
+    border-top: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
+    margin: 1em 0 1em 0;
+    padding: 0.4em;
+}
+
+div.genindex-jumpbox {
+    border-top: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
+    margin: 1em 0 1em 0;
+    padding: 0.4em;
+}
+
+/* -- general body styles --------------------------------------------------- */
+
+a.headerlink {
+    visibility: hidden;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink {
+    visibility: visible;
+}
+
+div.body p.caption {
+    text-align: inherit;
+}
+
+div.body td {
+    text-align: left;
+}
+
+.field-list ul {
+    padding-left: 1em;
+}
+
+.first {
+    margin-top: 0 !important;
+}
+
+p.rubric {
+    margin-top: 30px;
+    font-weight: bold;
+}
+
+img.align-left, .figure.align-left, object.align-left {
+    clear: left;
+    float: left;
+    margin-right: 1em;
+}
+
+img.align-right, .figure.align-right, object.align-right {
+    clear: right;
+    float: right;
+    margin-left: 1em;
+}
+
+img.align-center, .figure.align-center, object.align-center {
+  display: block;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+.align-left {
+    text-align: left;
+}
+
+.align-center {
+    text-align: center;
+}
+
+.align-right {
+    text-align: right;
+}
+
+/* -- sidebars -------------------------------------------------------------- */
+
+div.sidebar {
+    margin: 0 0 0.5em 1em;
+    border: 1px solid #ddb;
+    padding: 7px 7px 0 7px;
+    background-color: #ffe;
+    width: 40%;
+    float: right;
+}
+
+p.sidebar-title {
+    font-weight: bold;
+}
+
+/* -- topics ---------------------------------------------------------------- */
+
+div.topic {
+    border: 1px solid #ccc;
+    padding: 7px 7px 0 7px;
+    margin: 10px 0 10px 0;
+}
+
+p.topic-title {
+    font-size: 1.1em;
+    font-weight: bold;
+    margin-top: 10px;
+}
+
+/* -- admonitions ----------------------------------------------------------- */
+
+div.admonition {
+    margin-top: 10px;
+    margin-bottom: 10px;
+    padding: 7px;
+}
+
+div.admonition dt {
+    font-weight: bold;
+}
+
+div.admonition dl {
+    margin-bottom: 0;
+}
+
+p.admonition-title {
+    margin: 0px 10px 5px 0px;
+    font-weight: bold;
+}
+
+div.body p.centered {
+    text-align: center;
+    margin-top: 25px;
+}
+
+/* -- tables ---------------------------------------------------------------- */
+
+table.docutils {
+    border: 0;
+    border-collapse: collapse;
+}
+
+table.docutils td, table.docutils th {
+    padding: 1px 8px 1px 5px;
+    border-top: 0;
+    border-left: 0;
+    border-right: 0;
+    border-bottom: 1px solid #aaa;
+}
+
+table.field-list td, table.field-list th {
+    border: 0 !important;
+}
+
+table.footnote td, table.footnote th {
+    border: 0 !important;
+}
+
+th {
+    text-align: left;
+    padding-right: 5px;
+}
+
+table.citation {
+    border-left: solid 1px gray;
+    margin-left: 1px;
+}
+
+table.citation td {
+    border-bottom: none;
+}
+
+/* -- other body styles ----------------------------------------------------- */
+
+ol.arabic {
+    list-style: decimal;
+}
+
+ol.loweralpha {
+    list-style: lower-alpha;
+}
+
+ol.upperalpha {
+    list-style: upper-alpha;
+}
+
+ol.lowerroman {
+    list-style: lower-roman;
+}
+
+ol.upperroman {
+    list-style: upper-roman;
+}
+
+dl {
+    margin-bottom: 15px;
+}
+
+dd p {
+    margin-top: 0px;
+}
+
+dd ul, dd table {
+    margin-bottom: 10px;
+}
+
+dd {
+    margin-top: 3px;
+    margin-bottom: 10px;
+    margin-left: 30px;
+}
+
+dt:target, .highlighted {
+    background-color: #fbe54e;
+}
+
+dl.glossary dt {
+    font-weight: bold;
+    font-size: 1.1em;
+}
+
+.field-list ul {
+    margin: 0;
+    padding-left: 1em;
+}
+
+.field-list p {
+    margin: 0;
+}
+
+.refcount {
+    color: #060;
+}
+
+.optional {
+    font-size: 1.3em;
+}
+
+.versionmodified {
+    font-style: italic;
+}
+
+.system-message {
+    background-color: #fda;
+    padding: 5px;
+    border: 3px solid red;
+}
+
+.footnote:target  {
+    background-color: #ffa;
+}
+
+.line-block {
+    display: block;
+    margin-top: 1em;
+    margin-bottom: 1em;
+}
+
+.line-block .line-block {
+    margin-top: 0;
+    margin-bottom: 0;
+    margin-left: 1.5em;
+}
+
+.guilabel, .menuselection {
+    font-family: sans-serif;
+}
+
+.accelerator {
+    text-decoration: underline;
+}
+
+.classifier {
+    font-style: oblique;
+}
+
+abbr, acronym {
+    border-bottom: dotted 1px;
+    cursor: help;
+}
+
+/* -- code displays --------------------------------------------------------- */
+
+pre {
+    overflow: auto;
+    overflow-y: hidden;  /* fixes display issues on Chrome browsers */
+}
+
+td.linenos pre {
+    padding: 5px 0px;
+    border: 0;
+    background-color: transparent;
+    color: #aaa;
+}
+
+table.highlighttable {
+    margin-left: 0.5em;
+}
+
+table.highlighttable td {
+    padding: 0 0.5em 0 0.5em;
+}
+
+tt.descname {
+    background-color: transparent;
+    font-weight: bold;
+    font-size: 1.2em;
+}
+
+tt.descclassname {
+    background-color: transparent;
+}
+
+tt.xref, a tt {
+    background-color: transparent;
+    font-weight: bold;
+}
+
+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
+    background-color: transparent;
+}
+
+.viewcode-link {
+    float: right;
+}
+
+.viewcode-back {
+    float: right;
+    font-family: sans-serif;
+}
+
+div.viewcode-block:target {
+    margin: -1px -10px;
+    padding: 0 10px;
+}
+
+/* -- math display ---------------------------------------------------------- */
+
+img.math {
+    vertical-align: middle;
+}
+
+div.body div.math p {
+    text-align: center;
+}
+
+span.eqno {
+    float: right;
+}
+
+/* -- printout stylesheet --------------------------------------------------- */
+
+ at media print {
+    div.document,
+    div.documentwrapper,
+    div.bodywrapper {
+        margin: 0 !important;
+        width: 100%;
+    }
+
+    div.sphinxsidebar,
+    div.related,
+    div.footer,
+    #top-link {
+        display: none;
+    }
+}
\ No newline at end of file
diff --git a/documentation/_static/comment-bright.png b/documentation/_static/comment-bright.png
new file mode 100644
index 0000000..551517b
Binary files /dev/null and b/documentation/_static/comment-bright.png differ
diff --git a/documentation/_static/comment-close.png b/documentation/_static/comment-close.png
new file mode 100644
index 0000000..09b54be
Binary files /dev/null and b/documentation/_static/comment-close.png differ
diff --git a/documentation/_static/comment.png b/documentation/_static/comment.png
new file mode 100644
index 0000000..92feb52
Binary files /dev/null and b/documentation/_static/comment.png differ
diff --git a/documentation/_static/default.css b/documentation/_static/default.css
new file mode 100644
index 0000000..e534a07
--- /dev/null
+++ b/documentation/_static/default.css
@@ -0,0 +1,256 @@
+/*
+ * default.css_t
+ * ~~~~~~~~~~~~~
+ *
+ * Sphinx stylesheet -- default theme.
+ *
+ * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+ at import url("basic.css");
+
+/* -- page layout ----------------------------------------------------------- */
+
+body {
+    font-family: sans-serif;
+    font-size: 100%;
+    background-color: #11303d;
+    color: #000;
+    margin: 0;
+    padding: 0;
+}
+
+div.document {
+    background-color: #1c4e63;
+}
+
+div.documentwrapper {
+    float: left;
+    width: 100%;
+}
+
+div.bodywrapper {
+    margin: 0 0 0 230px;
+}
+
+div.body {
+    background-color: #ffffff;
+    color: #000000;
+    padding: 0 20px 30px 20px;
+}
+
+div.footer {
+    color: #ffffff;
+    width: 100%;
+    padding: 9px 0 9px 0;
+    text-align: center;
+    font-size: 75%;
+}
+
+div.footer a {
+    color: #ffffff;
+    text-decoration: underline;
+}
+
+div.related {
+    background-color: #133f52;
+    line-height: 30px;
+    color: #ffffff;
+}
+
+div.related a {
+    color: #ffffff;
+}
+
+div.sphinxsidebar {
+}
+
+div.sphinxsidebar h3 {
+    font-family: 'Trebuchet MS', sans-serif;
+    color: #ffffff;
+    font-size: 1.4em;
+    font-weight: normal;
+    margin: 0;
+    padding: 0;
+}
+
+div.sphinxsidebar h3 a {
+    color: #ffffff;
+}
+
+div.sphinxsidebar h4 {
+    font-family: 'Trebuchet MS', sans-serif;
+    color: #ffffff;
+    font-size: 1.3em;
+    font-weight: normal;
+    margin: 5px 0 0 0;
+    padding: 0;
+}
+
+div.sphinxsidebar p {
+    color: #ffffff;
+}
+
+div.sphinxsidebar p.topless {
+    margin: 5px 10px 10px 10px;
+}
+
+div.sphinxsidebar ul {
+    margin: 10px;
+    padding: 0;
+    color: #ffffff;
+}
+
+div.sphinxsidebar a {
+    color: #98dbcc;
+}
+
+div.sphinxsidebar input {
+    border: 1px solid #98dbcc;
+    font-family: sans-serif;
+    font-size: 1em;
+}
+
+
+
+/* -- hyperlink styles ------------------------------------------------------ */
+
+a {
+    color: #355f7c;
+    text-decoration: none;
+}
+
+a:visited {
+    color: #355f7c;
+    text-decoration: none;
+}
+
+a:hover {
+    text-decoration: underline;
+}
+
+
+
+/* -- body styles ----------------------------------------------------------- */
+
+div.body h1,
+div.body h2,
+div.body h3,
+div.body h4,
+div.body h5,
+div.body h6 {
+    font-family: 'Trebuchet MS', sans-serif;
+    background-color: #f2f2f2;
+    font-weight: normal;
+    color: #20435c;
+    border-bottom: 1px solid #ccc;
+    margin: 20px -20px 10px -20px;
+    padding: 3px 0 3px 10px;
+}
+
+div.body h1 { margin-top: 0; font-size: 200%; }
+div.body h2 { font-size: 160%; }
+div.body h3 { font-size: 140%; }
+div.body h4 { font-size: 120%; }
+div.body h5 { font-size: 110%; }
+div.body h6 { font-size: 100%; }
+
+a.headerlink {
+    color: #c60f0f;
+    font-size: 0.8em;
+    padding: 0 4px 0 4px;
+    text-decoration: none;
+}
+
+a.headerlink:hover {
+    background-color: #c60f0f;
+    color: white;
+}
+
+div.body p, div.body dd, div.body li {
+    text-align: justify;
+    line-height: 130%;
+}
+
+div.admonition p.admonition-title + p {
+    display: inline;
+}
+
+div.admonition p {
+    margin-bottom: 5px;
+}
+
+div.admonition pre {
+    margin-bottom: 5px;
+}
+
+div.admonition ul, div.admonition ol {
+    margin-bottom: 5px;
+}
+
+div.note {
+    background-color: #eee;
+    border: 1px solid #ccc;
+}
+
+div.seealso {
+    background-color: #ffc;
+    border: 1px solid #ff6;
+}
+
+div.topic {
+    background-color: #eee;
+}
+
+div.warning {
+    background-color: #ffe4e4;
+    border: 1px solid #f66;
+}
+
+p.admonition-title {
+    display: inline;
+}
+
+p.admonition-title:after {
+    content: ":";
+}
+
+pre {
+    padding: 5px;
+    background-color: #eeffcc;
+    color: #333333;
+    line-height: 120%;
+    border: 1px solid #ac9;
+    border-left: none;
+    border-right: none;
+}
+
+tt {
+    background-color: #ecf0f3;
+    padding: 0 1px 0 1px;
+    font-size: 0.95em;
+}
+
+th {
+    background-color: #ede;
+}
+
+.warning tt {
+    background: #efc2c2;
+}
+
+.note tt {
+    background: #d6d6d6;
+}
+
+.viewcode-back {
+    font-family: sans-serif;
+}
+
+div.viewcode-block:target {
+    background-color: #f4debf;
+    border-top: 1px solid #ac9;
+    border-bottom: 1px solid #ac9;
+}
\ No newline at end of file
diff --git a/documentation/_static/doctools.js b/documentation/_static/doctools.js
new file mode 100644
index 0000000..8614442
--- /dev/null
+++ b/documentation/_static/doctools.js
@@ -0,0 +1,235 @@
+/*
+ * doctools.js
+ * ~~~~~~~~~~~
+ *
+ * Sphinx JavaScript utilities for all documentation.
+ *
+ * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+/**
+ * select a different prefix for underscore
+ */
+$u = _.noConflict();
+
+/**
+ * make the code below compatible with browsers without
+ * an installed firebug like debugger
+if (!window.console || !console.firebug) {
+  var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
+    "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
+    "profile", "profileEnd"];
+  window.console = {};
+  for (var i = 0; i < names.length; ++i)
+    window.console[names[i]] = function() {};
+}
+ */
+
+/**
+ * small helper function to urldecode strings
+ */
+jQuery.urldecode = function(x) {
+  return decodeURIComponent(x).replace(/\+/g, ' ');
+};
+
+/**
+ * small helper function to urlencode strings
+ */
+jQuery.urlencode = encodeURIComponent;
+
+/**
+ * This function returns the parsed url parameters of the
+ * current request. Multiple values per key are supported,
+ * it will always return arrays of strings for the value parts.
+ */
+jQuery.getQueryParameters = function(s) {
+  if (typeof s == 'undefined')
+    s = document.location.search;
+  var parts = s.substr(s.indexOf('?') + 1).split('&');
+  var result = {};
+  for (var i = 0; i < parts.length; i++) {
+    var tmp = parts[i].split('=', 2);
+    var key = jQuery.urldecode(tmp[0]);
+    var value = jQuery.urldecode(tmp[1]);
+    if (key in result)
+      result[key].push(value);
+    else
+      result[key] = [value];
+  }
+  return result;
+};
+
+/**
+ * highlight a given string on a jquery object by wrapping it in
+ * span elements with the given class name.
+ */
+jQuery.fn.highlightText = function(text, className) {
+  function highlight(node) {
+    if (node.nodeType == 3) {
+      var val = node.nodeValue;
+      var pos = val.toLowerCase().indexOf(text);
+      if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) {
+        var span = document.createElement("span");
+        span.className = className;
+        span.appendChild(document.createTextNode(val.substr(pos, text.length)));
+        node.parentNode.insertBefore(span, node.parentNode.insertBefore(
+          document.createTextNode(val.substr(pos + text.length)),
+          node.nextSibling));
+        node.nodeValue = val.substr(0, pos);
+      }
+    }
+    else if (!jQuery(node).is("button, select, textarea")) {
+      jQuery.each(node.childNodes, function() {
+        highlight(this);
+      });
+    }
+  }
+  return this.each(function() {
+    highlight(this);
+  });
+};
+
+/**
+ * Small JavaScript module for the documentation.
+ */
+var Documentation = {
+
+  init : function() {
+    this.fixFirefoxAnchorBug();
+    this.highlightSearchWords();
+    this.initIndexTable();
+  },
+
+  /**
+   * i18n support
+   */
+  TRANSLATIONS : {},
+  PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
+  LOCALE : 'unknown',
+
+  // gettext and ngettext don't access this so that the functions
+  // can safely bound to a different name (_ = Documentation.gettext)
+  gettext : function(string) {
+    var translated = Documentation.TRANSLATIONS[string];
+    if (typeof translated == 'undefined')
+      return string;
+    return (typeof translated == 'string') ? translated : translated[0];
+  },
+
+  ngettext : function(singular, plural, n) {
+    var translated = Documentation.TRANSLATIONS[singular];
+    if (typeof translated == 'undefined')
+      return (n == 1) ? singular : plural;
+    return translated[Documentation.PLURALEXPR(n)];
+  },
+
+  addTranslations : function(catalog) {
+    for (var key in catalog.messages)
+      this.TRANSLATIONS[key] = catalog.messages[key];
+    this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
+    this.LOCALE = catalog.locale;
+  },
+
+  /**
+   * add context elements like header anchor links
+   */
+  addContextElements : function() {
+    $('div[id] > :header:first').each(function() {
+      $('<a class="headerlink">\u00B6</a>').
+      attr('href', '#' + this.id).
+      attr('title', _('Permalink to this headline')).
+      appendTo(this);
+    });
+    $('dt[id]').each(function() {
+      $('<a class="headerlink">\u00B6</a>').
+      attr('href', '#' + this.id).
+      attr('title', _('Permalink to this definition')).
+      appendTo(this);
+    });
+  },
+
+  /**
+   * workaround a firefox stupidity
+   */
+  fixFirefoxAnchorBug : function() {
+    if (document.location.hash && $.browser.mozilla)
+      window.setTimeout(function() {
+        document.location.href += '';
+      }, 10);
+  },
+
+  /**
+   * highlight the search words provided in the url in the text
+   */
+  highlightSearchWords : function() {
+    var params = $.getQueryParameters();
+    var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
+    if (terms.length) {
+      var body = $('div.body');
+      window.setTimeout(function() {
+        $.each(terms, function() {
+          body.highlightText(this.toLowerCase(), 'highlighted');
+        });
+      }, 10);
+      $('<p class="highlight-link"><a href="javascript:Documentation.' +
+        'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>')
+          .appendTo($('#searchbox'));
+    }
+  },
+
+  /**
+   * init the domain index toggle buttons
+   */
+  initIndexTable : function() {
+    var togglers = $('img.toggler').click(function() {
+      var src = $(this).attr('src');
+      var idnum = $(this).attr('id').substr(7);
+      $('tr.cg-' + idnum).toggle();
+      if (src.substr(-9) == 'minus.png')
+        $(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
+      else
+        $(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
+    }).css('display', '');
+    if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
+        togglers.click();
+    }
+  },
+
+  /**
+   * helper function to hide the search marks again
+   */
+  hideSearchWords : function() {
+    $('#searchbox .highlight-link').fadeOut(300);
+    $('span.highlighted').removeClass('highlighted');
+  },
+
+  /**
+   * make the url absolute
+   */
+  makeURL : function(relativeURL) {
+    return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
+  },
+
+  /**
+   * get the current relative url
+   */
+  getCurrentURL : function() {
+    var path = document.location.pathname;
+    var parts = path.split(/\//);
+    $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
+      if (this == '..')
+        parts.pop();
+    });
+    var url = parts.join('/');
+    return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
+  }
+};
+
+// quick alias for translations
+_ = Documentation.gettext;
+
+$(document).ready(function() {
+  Documentation.init();
+});
diff --git a/documentation/_static/down-pressed.png b/documentation/_static/down-pressed.png
new file mode 100644
index 0000000..6f7ad78
Binary files /dev/null and b/documentation/_static/down-pressed.png differ
diff --git a/documentation/_static/down.png b/documentation/_static/down.png
new file mode 100644
index 0000000..3003a88
Binary files /dev/null and b/documentation/_static/down.png differ
diff --git a/documentation/_static/file.png b/documentation/_static/file.png
new file mode 100644
index 0000000..d18082e
Binary files /dev/null and b/documentation/_static/file.png differ
diff --git a/documentation/_static/jquery.js b/documentation/_static/jquery.js
new file mode 100644
index 0000000..83589da
--- /dev/null
+++ b/documentation/_static/jquery.js
@@ -0,0 +1,2 @@
+/*! jQuery v1.8.3 jquery.com | jquery.org/license */
+(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){retur [...]
\ No newline at end of file
diff --git a/documentation/_static/mathjax-use-tex-fonts.js b/documentation/_static/mathjax-use-tex-fonts.js
new file mode 100644
index 0000000..ae31c3a
--- /dev/null
+++ b/documentation/_static/mathjax-use-tex-fonts.js
@@ -0,0 +1,9 @@
+MathJax.Hub.Config({
+  showProcessingMessages: false,
+  messageStyle: "none",
+  "HTML-CSS": {
+    availableFonts: ["TeX"], 
+  },
+});
+
+MathJax.Ajax.loadComplete("http://www.xmds.org/_static/mathjax-use-tex-fonts.js");
diff --git a/documentation/_static/minus.png b/documentation/_static/minus.png
new file mode 100644
index 0000000..da1c562
Binary files /dev/null and b/documentation/_static/minus.png differ
diff --git a/documentation/_static/plus.png b/documentation/_static/plus.png
new file mode 100644
index 0000000..b3cb374
Binary files /dev/null and b/documentation/_static/plus.png differ
diff --git a/documentation/_static/pygments.css b/documentation/_static/pygments.css
new file mode 100644
index 0000000..ed79e79
--- /dev/null
+++ b/documentation/_static/pygments.css
@@ -0,0 +1,62 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight  { background: #f0f0f0; }
+.highlight .c { color: #408090; font-style: italic } /* Comment */
+.highlight .err { border: 1px solid #FF0000 } /* Error */
+.highlight .k { color: #007020; font-weight: bold } /* Keyword */
+.highlight .o { color: #666666 } /* Operator */
+.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #007020 } /* Comment.Preproc */
+.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
+.highlight .gd { color: #A00000 } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #FF0000 } /* Generic.Error */
+.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #00A000 } /* Generic.Inserted */
+.highlight .go { color: #333333 } /* Generic.Output */
+.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #0044DD } /* Generic.Traceback */
+.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #007020 } /* Keyword.Pseudo */
+.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #902000 } /* Keyword.Type */
+.highlight .m { color: #208050 } /* Literal.Number */
+.highlight .s { color: #517918; font-style: italic } /* Literal.String */
+.highlight .na { color: #4070a0 } /* Name.Attribute */
+.highlight .nb { color: #007020 } /* Name.Builtin */
+.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
+.highlight .no { color: #60add5 } /* Name.Constant */
+.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
+.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
+.highlight .ne { color: #007020 } /* Name.Exception */
+.highlight .nf { color: #06287e } /* Name.Function */
+.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
+.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
+.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #bb60d5 } /* Name.Variable */
+.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #208050 } /* Literal.Number.Float */
+.highlight .mh { color: #208050 } /* Literal.Number.Hex */
+.highlight .mi { color: #208050 } /* Literal.Number.Integer */
+.highlight .mo { color: #208050 } /* Literal.Number.Oct */
+.highlight .sb { color: #517918; font-style: italic } /* Literal.String.Backtick */
+.highlight .sc { color: #517918; font-style: italic } /* Literal.String.Char */
+.highlight .sd { color: #517918; font-style: italic } /* Literal.String.Doc */
+.highlight .s2 { color: #517918; font-style: italic } /* Literal.String.Double */
+.highlight .se { color: #4070a0; font-weight: bold; font-style: italic } /* Literal.String.Escape */
+.highlight .sh { color: #517918; font-style: italic } /* Literal.String.Heredoc */
+.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
+.highlight .sx { color: #c65d09; font-style: italic } /* Literal.String.Other */
+.highlight .sr { color: #235388; font-style: italic } /* Literal.String.Regex */
+.highlight .s1 { color: #517918; font-style: italic } /* Literal.String.Single */
+.highlight .ss { color: #517918; font-style: italic } /* Literal.String.Symbol */
+.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
+.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
+.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
+.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */
\ No newline at end of file
diff --git a/documentation/_static/searchtools.js b/documentation/_static/searchtools.js
new file mode 100644
index 0000000..56676b2
--- /dev/null
+++ b/documentation/_static/searchtools.js
@@ -0,0 +1,622 @@
+/*
+ * searchtools.js_t
+ * ~~~~~~~~~~~~~~~~
+ *
+ * Sphinx JavaScript utilties for the full-text search.
+ *
+ * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+
+/**
+ * Porter Stemmer
+ */
+var Stemmer = function() {
+
+  var step2list = {
+    ational: 'ate',
+    tional: 'tion',
+    enci: 'ence',
+    anci: 'ance',
+    izer: 'ize',
+    bli: 'ble',
+    alli: 'al',
+    entli: 'ent',
+    eli: 'e',
+    ousli: 'ous',
+    ization: 'ize',
+    ation: 'ate',
+    ator: 'ate',
+    alism: 'al',
+    iveness: 'ive',
+    fulness: 'ful',
+    ousness: 'ous',
+    aliti: 'al',
+    iviti: 'ive',
+    biliti: 'ble',
+    logi: 'log'
+  };
+
+  var step3list = {
+    icate: 'ic',
+    ative: '',
+    alize: 'al',
+    iciti: 'ic',
+    ical: 'ic',
+    ful: '',
+    ness: ''
+  };
+
+  var c = "[^aeiou]";          // consonant
+  var v = "[aeiouy]";          // vowel
+  var C = c + "[^aeiouy]*";    // consonant sequence
+  var V = v + "[aeiou]*";      // vowel sequence
+
+  var mgr0 = "^(" + C + ")?" + V + C;                      // [C]VC... is m>0
+  var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$";    // [C]VC[V] is m=1
+  var mgr1 = "^(" + C + ")?" + V + C + V + C;              // [C]VCVC... is m>1
+  var s_v   = "^(" + C + ")?" + v;                         // vowel in stem
+
+  this.stemWord = function (w) {
+    var stem;
+    var suffix;
+    var firstch;
+    var origword = w;
+
+    if (w.length < 3)
+      return w;
+
+    var re;
+    var re2;
+    var re3;
+    var re4;
+
+    firstch = w.substr(0,1);
+    if (firstch == "y")
+      w = firstch.toUpperCase() + w.substr(1);
+
+    // Step 1a
+    re = /^(.+?)(ss|i)es$/;
+    re2 = /^(.+?)([^s])s$/;
+
+    if (re.test(w))
+      w = w.replace(re,"$1$2");
+    else if (re2.test(w))
+      w = w.replace(re2,"$1$2");
+
+    // Step 1b
+    re = /^(.+?)eed$/;
+    re2 = /^(.+?)(ed|ing)$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      re = new RegExp(mgr0);
+      if (re.test(fp[1])) {
+        re = /.$/;
+        w = w.replace(re,"");
+      }
+    }
+    else if (re2.test(w)) {
+      var fp = re2.exec(w);
+      stem = fp[1];
+      re2 = new RegExp(s_v);
+      if (re2.test(stem)) {
+        w = stem;
+        re2 = /(at|bl|iz)$/;
+        re3 = new RegExp("([^aeiouylsz])\\1$");
+        re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
+        if (re2.test(w))
+          w = w + "e";
+        else if (re3.test(w)) {
+          re = /.$/;
+          w = w.replace(re,"");
+        }
+        else if (re4.test(w))
+          w = w + "e";
+      }
+    }
+
+    // Step 1c
+    re = /^(.+?)y$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      stem = fp[1];
+      re = new RegExp(s_v);
+      if (re.test(stem))
+        w = stem + "i";
+    }
+
+    // Step 2
+    re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      stem = fp[1];
+      suffix = fp[2];
+      re = new RegExp(mgr0);
+      if (re.test(stem))
+        w = stem + step2list[suffix];
+    }
+
+    // Step 3
+    re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      stem = fp[1];
+      suffix = fp[2];
+      re = new RegExp(mgr0);
+      if (re.test(stem))
+        w = stem + step3list[suffix];
+    }
+
+    // Step 4
+    re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
+    re2 = /^(.+?)(s|t)(ion)$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      stem = fp[1];
+      re = new RegExp(mgr1);
+      if (re.test(stem))
+        w = stem;
+    }
+    else if (re2.test(w)) {
+      var fp = re2.exec(w);
+      stem = fp[1] + fp[2];
+      re2 = new RegExp(mgr1);
+      if (re2.test(stem))
+        w = stem;
+    }
+
+    // Step 5
+    re = /^(.+?)e$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      stem = fp[1];
+      re = new RegExp(mgr1);
+      re2 = new RegExp(meq1);
+      re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
+      if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
+        w = stem;
+    }
+    re = /ll$/;
+    re2 = new RegExp(mgr1);
+    if (re.test(w) && re2.test(w)) {
+      re = /.$/;
+      w = w.replace(re,"");
+    }
+
+    // and turn initial Y back to y
+    if (firstch == "y")
+      w = firstch.toLowerCase() + w.substr(1);
+    return w;
+  }
+}
+
+
+
+/**
+ * Simple result scoring code.
+ */
+var Scorer = {
+  // Implement the following function to further tweak the score for each result
+  // The function takes a result array [filename, title, anchor, descr, score]
+  // and returns the new score.
+  /*
+  score: function(result) {
+    return result[4];
+  },
+  */
+
+  // query matches the full name of an object
+  objNameMatch: 11,
+  // or matches in the last dotted part of the object name
+  objPartialMatch: 6,
+  // Additive scores depending on the priority of the object
+  objPrio: {0:  15,   // used to be importantResults
+            1:  5,   // used to be objectResults
+            2: -5},  // used to be unimportantResults
+  //  Used when the priority is not in the mapping.
+  objPrioDefault: 0,
+
+  // query found in title
+  title: 15,
+  // query found in terms
+  term: 5
+};
+
+
+/**
+ * Search Module
+ */
+var Search = {
+
+  _index : null,
+  _queued_query : null,
+  _pulse_status : -1,
+
+  init : function() {
+      var params = $.getQueryParameters();
+      if (params.q) {
+          var query = params.q[0];
+          $('input[name="q"]')[0].value = query;
+          this.performSearch(query);
+      }
+  },
+
+  loadIndex : function(url) {
+    $.ajax({type: "GET", url: url, data: null,
+            dataType: "script", cache: true,
+            complete: function(jqxhr, textstatus) {
+              if (textstatus != "success") {
+                document.getElementById("searchindexloader").src = url;
+              }
+            }});
+  },
+
+  setIndex : function(index) {
+    var q;
+    this._index = index;
+    if ((q = this._queued_query) !== null) {
+      this._queued_query = null;
+      Search.query(q);
+    }
+  },
+
+  hasIndex : function() {
+      return this._index !== null;
+  },
+
+  deferQuery : function(query) {
+      this._queued_query = query;
+  },
+
+  stopPulse : function() {
+      this._pulse_status = 0;
+  },
+
+  startPulse : function() {
+    if (this._pulse_status >= 0)
+        return;
+    function pulse() {
+      var i;
+      Search._pulse_status = (Search._pulse_status + 1) % 4;
+      var dotString = '';
+      for (i = 0; i < Search._pulse_status; i++)
+        dotString += '.';
+      Search.dots.text(dotString);
+      if (Search._pulse_status > -1)
+        window.setTimeout(pulse, 500);
+    }
+    pulse();
+  },
+
+  /**
+   * perform a search for something (or wait until index is loaded)
+   */
+  performSearch : function(query) {
+    // create the required interface elements
+    this.out = $('#search-results');
+    this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out);
+    this.dots = $('<span></span>').appendTo(this.title);
+    this.status = $('<p style="display: none"></p>').appendTo(this.out);
+    this.output = $('<ul class="search"/>').appendTo(this.out);
+
+    $('#search-progress').text(_('Preparing search...'));
+    this.startPulse();
+
+    // index already loaded, the browser was quick!
+    if (this.hasIndex())
+      this.query(query);
+    else
+      this.deferQuery(query);
+  },
+
+  /**
+   * execute search (requires search index to be loaded)
+   */
+  query : function(query) {
+    var i;
+    var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"];
+
+    // stem the searchterms and add them to the correct list
+    var stemmer = new Stemmer();
+    var searchterms = [];
+    var excluded = [];
+    var hlterms = [];
+    var tmp = query.split(/\s+/);
+    var objectterms = [];
+    for (i = 0; i < tmp.length; i++) {
+      if (tmp[i] !== "") {
+          objectterms.push(tmp[i].toLowerCase());
+      }
+
+      if ($u.indexOf(stopwords, tmp[i]) != -1 || tmp[i].match(/^\d+$/) ||
+          tmp[i] === "") {
+        // skip this "word"
+        continue;
+      }
+      // stem the word
+      var word = stemmer.stemWord(tmp[i]).toLowerCase();
+      var toAppend;
+      // select the correct list
+      if (word[0] == '-') {
+        toAppend = excluded;
+        word = word.substr(1);
+      }
+      else {
+        toAppend = searchterms;
+        hlterms.push(tmp[i].toLowerCase());
+      }
+      // only add if not already in the list
+      if (!$u.contains(toAppend, word))
+        toAppend.push(word);
+    }
+    var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
+
+    // console.debug('SEARCH: searching for:');
+    // console.info('required: ', searchterms);
+    // console.info('excluded: ', excluded);
+
+    // prepare search
+    var terms = this._index.terms;
+    var titleterms = this._index.titleterms;
+
+    // array of [filename, title, anchor, descr, score]
+    var results = [];
+    $('#search-progress').empty();
+
+    // lookup as object
+    for (i = 0; i < objectterms.length; i++) {
+      var others = [].concat(objectterms.slice(0, i),
+                             objectterms.slice(i+1, objectterms.length));
+      results = results.concat(this.performObjectSearch(objectterms[i], others));
+    }
+
+    // lookup as search terms in fulltext
+    results = results.concat(this.performTermsSearch(searchterms, excluded, terms, Scorer.term))
+                     .concat(this.performTermsSearch(searchterms, excluded, titleterms, Scorer.title));
+
+    // let the scorer override scores with a custom scoring function
+    if (Scorer.score) {
+      for (i = 0; i < results.length; i++)
+        results[i][4] = Scorer.score(results[i]);
+    }
+
+    // now sort the results by score (in opposite order of appearance, since the
+    // display function below uses pop() to retrieve items) and then
+    // alphabetically
+    results.sort(function(a, b) {
+      var left = a[4];
+      var right = b[4];
+      if (left > right) {
+        return 1;
+      } else if (left < right) {
+        return -1;
+      } else {
+        // same score: sort alphabetically
+        left = a[1].toLowerCase();
+        right = b[1].toLowerCase();
+        return (left > right) ? -1 : ((left < right) ? 1 : 0);
+      }
+    });
+
+    // for debugging
+    //Search.lastresults = results.slice();  // a copy
+    //console.info('search results:', Search.lastresults);
+
+    // print the results
+    var resultCount = results.length;
+    function displayNextItem() {
+      // results left, load the summary and display it
+      if (results.length) {
+        var item = results.pop();
+        var listItem = $('<li style="display:none"></li>');
+        if (DOCUMENTATION_OPTIONS.FILE_SUFFIX === '') {
+          // dirhtml builder
+          var dirname = item[0] + '/';
+          if (dirname.match(/\/index\/$/)) {
+            dirname = dirname.substring(0, dirname.length-6);
+          } else if (dirname == 'index/') {
+            dirname = '';
+          }
+          listItem.append($('<a/>').attr('href',
+            DOCUMENTATION_OPTIONS.URL_ROOT + dirname +
+            highlightstring + item[2]).html(item[1]));
+        } else {
+          // normal html builders
+          listItem.append($('<a/>').attr('href',
+            item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
+            highlightstring + item[2]).html(item[1]));
+        }
+        if (item[3]) {
+          listItem.append($('<span> (' + item[3] + ')</span>'));
+          Search.output.append(listItem);
+          listItem.slideDown(5, function() {
+            displayNextItem();
+          });
+        } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
+          $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[0] + '.txt',
+                  dataType: "text",
+                  complete: function(jqxhr, textstatus) {
+                    var data = jqxhr.responseText;
+                    if (data !== '') {
+                      listItem.append(Search.makeSearchSummary(data, searchterms, hlterms));
+                    }
+                    Search.output.append(listItem);
+                    listItem.slideDown(5, function() {
+                      displayNextItem();
+                    });
+                  }});
+        } else {
+          // no source available, just display title
+          Search.output.append(listItem);
+          listItem.slideDown(5, function() {
+            displayNextItem();
+          });
+        }
+      }
+      // search finished, update title and status message
+      else {
+        Search.stopPulse();
+        Search.title.text(_('Search Results'));
+        if (!resultCount)
+          Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
+        else
+            Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
+        Search.status.fadeIn(500);
+      }
+    }
+    displayNextItem();
+  },
+
+  /**
+   * search for object names
+   */
+  performObjectSearch : function(object, otherterms) {
+    var filenames = this._index.filenames;
+    var objects = this._index.objects;
+    var objnames = this._index.objnames;
+    var titles = this._index.titles;
+
+    var i;
+    var results = [];
+
+    for (var prefix in objects) {
+      for (var name in objects[prefix]) {
+        var fullname = (prefix ? prefix + '.' : '') + name;
+        if (fullname.toLowerCase().indexOf(object) > -1) {
+          var score = 0;
+          var parts = fullname.split('.');
+          // check for different match types: exact matches of full name or
+          // "last name" (i.e. last dotted part)
+          if (fullname == object || parts[parts.length - 1] == object) {
+            score += Scorer.objNameMatch;
+          // matches in last name
+          } else if (parts[parts.length - 1].indexOf(object) > -1) {
+            score += Scorer.objPartialMatch;
+          }
+          var match = objects[prefix][name];
+          var objname = objnames[match[1]][2];
+          var title = titles[match[0]];
+          // If more than one term searched for, we require other words to be
+          // found in the name/title/description
+          if (otherterms.length > 0) {
+            var haystack = (prefix + ' ' + name + ' ' +
+                            objname + ' ' + title).toLowerCase();
+            var allfound = true;
+            for (i = 0; i < otherterms.length; i++) {
+              if (haystack.indexOf(otherterms[i]) == -1) {
+                allfound = false;
+                break;
+              }
+            }
+            if (!allfound) {
+              continue;
+            }
+          }
+          var descr = objname + _(', in ') + title;
+
+          var anchor = match[3];
+          if (anchor === '')
+            anchor = fullname;
+          else if (anchor == '-')
+            anchor = objnames[match[1]][1] + '-' + fullname;
+          // add custom score for some objects according to scorer
+          if (Scorer.objPrio.hasOwnProperty(match[2])) {
+            score += Scorer.objPrio[match[2]];
+          } else {
+            score += Scorer.objPrioDefault;
+          }
+          results.push([filenames[match[0]], fullname, '#'+anchor, descr, score]);
+        }
+      }
+    }
+
+    return results;
+  },
+
+  /**
+   * search for full-text terms in the index
+   */
+  performTermsSearch : function(searchterms, excluded, terms, score) {
+    var filenames = this._index.filenames;
+    var titles = this._index.titles;
+
+    var i, j, file, files;
+    var fileMap = {};
+    var results = [];
+
+    // perform the search on the required terms
+    for (i = 0; i < searchterms.length; i++) {
+      var word = searchterms[i];
+      // no match but word was a required one
+      if (!(files = terms[word]))
+        break;
+      if (files.length === undefined) {
+        files = [files];
+      }
+      // create the mapping
+      for (j = 0; j < files.length; j++) {
+        file = files[j];
+        if (file in fileMap)
+          fileMap[file].push(word);
+        else
+          fileMap[file] = [word];
+      }
+    }
+
+    // now check if the files don't contain excluded terms
+    for (file in fileMap) {
+      var valid = true;
+
+      // check if all requirements are matched
+      if (fileMap[file].length != searchterms.length)
+          continue;
+
+      // ensure that none of the excluded terms is in the search result
+      for (i = 0; i < excluded.length; i++) {
+        if (terms[excluded[i]] == file ||
+          $u.contains(terms[excluded[i]] || [], file)) {
+          valid = false;
+          break;
+        }
+      }
+
+      // if we have still a valid result we can add it to the result list
+      if (valid) {
+        results.push([filenames[file], titles[file], '', null, score]);
+      }
+    }
+    return results;
+  },
+
+  /**
+   * helper function to return a node containing the
+   * search summary for a given text. keywords is a list
+   * of stemmed words, hlwords is the list of normal, unstemmed
+   * words. the first one is used to find the occurance, the
+   * latter for highlighting it.
+   */
+  makeSearchSummary : function(text, keywords, hlwords) {
+    var textLower = text.toLowerCase();
+    var start = 0;
+    $.each(keywords, function() {
+      var i = textLower.indexOf(this.toLowerCase());
+      if (i > -1)
+        start = i;
+    });
+    start = Math.max(start - 120, 0);
+    var excerpt = ((start > 0) ? '...' : '') +
+      $.trim(text.substr(start, 240)) +
+      ((start + 240 - text.length) ? '...' : '');
+    var rv = $('<div class="context"></div>').text(excerpt);
+    $.each(hlwords, function() {
+      rv = rv.highlightText(this, 'highlighted');
+    });
+    return rv;
+  }
+};
+
+$(document).ready(function() {
+  Search.init();
+});
\ No newline at end of file
diff --git a/documentation/_static/sidebar.js b/documentation/_static/sidebar.js
new file mode 100644
index 0000000..874a890
--- /dev/null
+++ b/documentation/_static/sidebar.js
@@ -0,0 +1,159 @@
+/*
+ * sidebar.js
+ * ~~~~~~~~~~
+ *
+ * This script makes the Sphinx sidebar collapsible.
+ *
+ * .sphinxsidebar contains .sphinxsidebarwrapper.  This script adds
+ * in .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton
+ * used to collapse and expand the sidebar.
+ *
+ * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden
+ * and the width of the sidebar and the margin-left of the document
+ * are decreased. When the sidebar is expanded the opposite happens.
+ * This script saves a per-browser/per-session cookie used to
+ * remember the position of the sidebar among the pages.
+ * Once the browser is closed the cookie is deleted and the position
+ * reset to the default (expanded).
+ *
+ * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+$(function() {
+  
+  
+  
+  
+  
+  
+  
+
+  // global elements used by the functions.
+  // the 'sidebarbutton' element is defined as global after its
+  // creation, in the add_sidebar_button function
+  var bodywrapper = $('.bodywrapper');
+  var sidebar = $('.sphinxsidebar');
+  var sidebarwrapper = $('.sphinxsidebarwrapper');
+
+  // for some reason, the document has no sidebar; do not run into errors
+  if (!sidebar.length) return;
+
+  // original margin-left of the bodywrapper and width of the sidebar
+  // with the sidebar expanded
+  var bw_margin_expanded = bodywrapper.css('margin-left');
+  var ssb_width_expanded = sidebar.width();
+
+  // margin-left of the bodywrapper and width of the sidebar
+  // with the sidebar collapsed
+  var bw_margin_collapsed = '.8em';
+  var ssb_width_collapsed = '.8em';
+
+  // colors used by the current theme
+  var dark_color = $('.related').css('background-color');
+  var light_color = $('.document').css('background-color');
+
+  function sidebar_is_collapsed() {
+    return sidebarwrapper.is(':not(:visible)');
+  }
+
+  function toggle_sidebar() {
+    if (sidebar_is_collapsed())
+      expand_sidebar();
+    else
+      collapse_sidebar();
+  }
+
+  function collapse_sidebar() {
+    sidebarwrapper.hide();
+    sidebar.css('width', ssb_width_collapsed);
+    bodywrapper.css('margin-left', bw_margin_collapsed);
+    sidebarbutton.css({
+        'margin-left': '0',
+        'height': bodywrapper.height()
+    });
+    sidebarbutton.find('span').text('»');
+    sidebarbutton.attr('title', _('Expand sidebar'));
+    document.cookie = 'sidebar=collapsed';
+  }
+
+  function expand_sidebar() {
+    bodywrapper.css('margin-left', bw_margin_expanded);
+    sidebar.css('width', ssb_width_expanded);
+    sidebarwrapper.show();
+    sidebarbutton.css({
+        'margin-left': ssb_width_expanded-12,
+        'height': bodywrapper.height()
+    });
+    sidebarbutton.find('span').text('«');
+    sidebarbutton.attr('title', _('Collapse sidebar'));
+    document.cookie = 'sidebar=expanded';
+  }
+
+  function add_sidebar_button() {
+    sidebarwrapper.css({
+        'float': 'left',
+        'margin-right': '0',
+        'width': ssb_width_expanded - 28
+    });
+    // create the button
+    sidebar.append(
+        '<div id="sidebarbutton"><span>«</span></div>'
+    );
+    var sidebarbutton = $('#sidebarbutton');
+    light_color = sidebarbutton.css('background-color');
+    // find the height of the viewport to center the '<<' in the page
+    var viewport_height;
+    if (window.innerHeight)
+ 	  viewport_height = window.innerHeight;
+    else
+	  viewport_height = $(window).height();
+    sidebarbutton.find('span').css({
+        'display': 'block',
+        'margin-top': (viewport_height - sidebar.position().top - 20) / 2
+    });
+
+    sidebarbutton.click(toggle_sidebar);
+    sidebarbutton.attr('title', _('Collapse sidebar'));
+    sidebarbutton.css({
+        'color': '#FFFFFF',
+        'border-left': '1px solid ' + dark_color,
+        'font-size': '1.2em',
+        'cursor': 'pointer',
+        'height': bodywrapper.height(),
+        'padding-top': '1px',
+        'margin-left': ssb_width_expanded - 12
+    });
+
+    sidebarbutton.hover(
+      function () {
+          $(this).css('background-color', dark_color);
+      },
+      function () {
+          $(this).css('background-color', light_color);
+      }
+    );
+  }
+
+  function set_position_from_cookie() {
+    if (!document.cookie)
+      return;
+    var items = document.cookie.split(';');
+    for(var k=0; k<items.length; k++) {
+      var key_val = items[k].split('=');
+      var key = key_val[0].replace(/ /, "");  // strip leading spaces
+      if (key == 'sidebar') {
+        var value = key_val[1];
+        if ((value == 'collapsed') && (!sidebar_is_collapsed()))
+          collapse_sidebar();
+        else if ((value == 'expanded') && (sidebar_is_collapsed()))
+          expand_sidebar();
+      }
+    }
+  }
+
+  add_sidebar_button();
+  var sidebarbutton = $('#sidebarbutton');
+  set_position_from_cookie();
+});
\ No newline at end of file
diff --git a/documentation/_static/underscore.js b/documentation/_static/underscore.js
new file mode 100644
index 0000000..5b55f32
--- /dev/null
+++ b/documentation/_static/underscore.js
@@ -0,0 +1,31 @@
+// Underscore.js 1.3.1
+// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
+// Underscore is freely distributable under the MIT license.
+// Portions of Underscore are inspired or borrowed from Prototype,
+// Oliver Steele's Functional, and John Resig's Micro-Templating.
+// For all details and documentation:
+// http://documentcloud.github.com/underscore
+(function(){function q(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object [...]
+c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&q(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&q(a[h],c[h],d))))break;if(g){for(h i [...]
+h)&&!f--)break;g=!f}}d.pop();return g}var r=this,G=r._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,H=k.unshift,l=o.toString,I=o.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,p=k.indexOf,D=k.lastIndexOf,o=Array.isArray,J=Object.keys,s=Function.prototype.bind,b=function(a){return new m(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else r._=b;b.VERSION="1.3.1";var [...]
+b.forEach=function(a,c,d){if(a!=null)if(w&&a.forEach===w)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(d,a[e],e,a)===n)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===n)break};b.map=b.collect=function(a,c,b){var e=[];if(a==null)return e;if(x&&a.map===x)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});if(a.length===+a.length)e.length=a.length;return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=arguments.l [...]
+null&&(a=[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.f [...]
+function(a,c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g, [...]
+e&&c.call(b,a,g,h)))return n});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return n});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return p&&a.indexOf===p?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d) [...]
+function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&(e={value:a [...]
+return e.value};b.shuffle=function(a){var b=[],d;j(a,function(a,f){f==0?b[0]=a:(d=Math.floor(Math.random()*(f+1)),b[f]=b[d],b[d]=a)});return b};b.sortBy=function(a,c,d){return b.pluck(b.map(a,function(a,b,g){return{value:a,criteria:c.call(d,a,b,g)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c<d?-1:c>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedInd [...]
+c,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:a.toArray?a.toArray():b.isArray(a)?i.call(a):b.isArguments(a)?i.call(a):b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=b.head=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length- [...]
+b.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,e=[];b.reduce(d,function(d,g,h){if(0==h||(c===true?b.last(d)!=g:!b.include(d,g)))d[d.length]=g,e[e.length]=a[h];retur [...]
+return e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=func [...]
+d){if(a==null)return-1;var e;if(d)return d=b.sortedIndex(a,c),a[d]===c?d:-1;if(p&&a.indexOf===p)return a.indexOf(c);for(d=0,e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(D&&a.lastIndexOf===D)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){arguments.length<=1&&(b=a||0,a=0);for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;)g[f++]=a,a+=d; [...]
+var F=function(){};b.bind=function(a,c){var d,e;if(a.bind===s&&s)return s.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));F.prototype=a.prototype;var b=new F,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.mem [...]
+c){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i=b.debounce(function(){h=g=false},c);return function(){d=this;e=arguments;var b;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);i()},c)) [...]
+a.apply(d,e);i();g=true}};b.debounce=function(a,b){var d;return function(){var e=this,f=arguments;clearTimeout(d);d=setTimeout(function(){d=null;a.apply(e,f)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments,0));return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)] [...]
+b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=J||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.defaults=function( [...]
+1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return q(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=o||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){ret [...]
+b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!b.has(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a) [...]
+b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return I.call(a,b)};b.noConflict=function(){r._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;")};b.mixin [...]
+function(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\/g,"\\").replace(/\\'/g,"'")};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||t,function(a,b){return [...]
+u(b)+"),'"}).replace(d.interpolate||t,function(a,b){return"',"+u(b)+",'"}).replace(d.evaluate||t,function(a,b){return"');"+u(b).replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=func [...]
+function(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.ch [...]
+true;return this};m.prototype.value=function(){return this._wrapped}}).call(this);
diff --git a/documentation/_static/up-pressed.png b/documentation/_static/up-pressed.png
new file mode 100644
index 0000000..8bd587a
Binary files /dev/null and b/documentation/_static/up-pressed.png differ
diff --git a/documentation/_static/up.png b/documentation/_static/up.png
new file mode 100644
index 0000000..b946256
Binary files /dev/null and b/documentation/_static/up.png differ
diff --git a/documentation/_static/websupport.js b/documentation/_static/websupport.js
new file mode 100644
index 0000000..19fcda5
--- /dev/null
+++ b/documentation/_static/websupport.js
@@ -0,0 +1,808 @@
+/*
+ * websupport.js
+ * ~~~~~~~~~~~~~
+ *
+ * sphinx.websupport utilties for all documentation.
+ *
+ * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+(function($) {
+  $.fn.autogrow = function() {
+    return this.each(function() {
+    var textarea = this;
+
+    $.fn.autogrow.resize(textarea);
+
+    $(textarea)
+      .focus(function() {
+        textarea.interval = setInterval(function() {
+          $.fn.autogrow.resize(textarea);
+        }, 500);
+      })
+      .blur(function() {
+        clearInterval(textarea.interval);
+      });
+    });
+  };
+
+  $.fn.autogrow.resize = function(textarea) {
+    var lineHeight = parseInt($(textarea).css('line-height'), 10);
+    var lines = textarea.value.split('\n');
+    var columns = textarea.cols;
+    var lineCount = 0;
+    $.each(lines, function() {
+      lineCount += Math.ceil(this.length / columns) || 1;
+    });
+    var height = lineHeight * (lineCount + 1);
+    $(textarea).css('height', height);
+  };
+})(jQuery);
+
+(function($) {
+  var comp, by;
+
+  function init() {
+    initEvents();
+    initComparator();
+  }
+
+  function initEvents() {
+    $('a.comment-close').live("click", function(event) {
+      event.preventDefault();
+      hide($(this).attr('id').substring(2));
+    });
+    $('a.vote').live("click", function(event) {
+      event.preventDefault();
+      handleVote($(this));
+    });
+    $('a.reply').live("click", function(event) {
+      event.preventDefault();
+      openReply($(this).attr('id').substring(2));
+    });
+    $('a.close-reply').live("click", function(event) {
+      event.preventDefault();
+      closeReply($(this).attr('id').substring(2));
+    });
+    $('a.sort-option').live("click", function(event) {
+      event.preventDefault();
+      handleReSort($(this));
+    });
+    $('a.show-proposal').live("click", function(event) {
+      event.preventDefault();
+      showProposal($(this).attr('id').substring(2));
+    });
+    $('a.hide-proposal').live("click", function(event) {
+      event.preventDefault();
+      hideProposal($(this).attr('id').substring(2));
+    });
+    $('a.show-propose-change').live("click", function(event) {
+      event.preventDefault();
+      showProposeChange($(this).attr('id').substring(2));
+    });
+    $('a.hide-propose-change').live("click", function(event) {
+      event.preventDefault();
+      hideProposeChange($(this).attr('id').substring(2));
+    });
+    $('a.accept-comment').live("click", function(event) {
+      event.preventDefault();
+      acceptComment($(this).attr('id').substring(2));
+    });
+    $('a.delete-comment').live("click", function(event) {
+      event.preventDefault();
+      deleteComment($(this).attr('id').substring(2));
+    });
+    $('a.comment-markup').live("click", function(event) {
+      event.preventDefault();
+      toggleCommentMarkupBox($(this).attr('id').substring(2));
+    });
+  }
+
+  /**
+   * Set comp, which is a comparator function used for sorting and
+   * inserting comments into the list.
+   */
+  function setComparator() {
+    // If the first three letters are "asc", sort in ascending order
+    // and remove the prefix.
+    if (by.substring(0,3) == 'asc') {
+      var i = by.substring(3);
+      comp = function(a, b) { return a[i] - b[i]; };
+    } else {
+      // Otherwise sort in descending order.
+      comp = function(a, b) { return b[by] - a[by]; };
+    }
+
+    // Reset link styles and format the selected sort option.
+    $('a.sel').attr('href', '#').removeClass('sel');
+    $('a.by' + by).removeAttr('href').addClass('sel');
+  }
+
+  /**
+   * Create a comp function. If the user has preferences stored in
+   * the sortBy cookie, use those, otherwise use the default.
+   */
+  function initComparator() {
+    by = 'rating'; // Default to sort by rating.
+    // If the sortBy cookie is set, use that instead.
+    if (document.cookie.length > 0) {
+      var start = document.cookie.indexOf('sortBy=');
+      if (start != -1) {
+        start = start + 7;
+        var end = document.cookie.indexOf(";", start);
+        if (end == -1) {
+          end = document.cookie.length;
+          by = unescape(document.cookie.substring(start, end));
+        }
+      }
+    }
+    setComparator();
+  }
+
+  /**
+   * Show a comment div.
+   */
+  function show(id) {
+    $('#ao' + id).hide();
+    $('#ah' + id).show();
+    var context = $.extend({id: id}, opts);
+    var popup = $(renderTemplate(popupTemplate, context)).hide();
+    popup.find('textarea[name="proposal"]').hide();
+    popup.find('a.by' + by).addClass('sel');
+    var form = popup.find('#cf' + id);
+    form.submit(function(event) {
+      event.preventDefault();
+      addComment(form);
+    });
+    $('#s' + id).after(popup);
+    popup.slideDown('fast', function() {
+      getComments(id);
+    });
+  }
+
+  /**
+   * Hide a comment div.
+   */
+  function hide(id) {
+    $('#ah' + id).hide();
+    $('#ao' + id).show();
+    var div = $('#sc' + id);
+    div.slideUp('fast', function() {
+      div.remove();
+    });
+  }
+
+  /**
+   * Perform an ajax request to get comments for a node
+   * and insert the comments into the comments tree.
+   */
+  function getComments(id) {
+    $.ajax({
+     type: 'GET',
+     url: opts.getCommentsURL,
+     data: {node: id},
+     success: function(data, textStatus, request) {
+       var ul = $('#cl' + id);
+       var speed = 100;
+       $('#cf' + id)
+         .find('textarea[name="proposal"]')
+         .data('source', data.source);
+
+       if (data.comments.length === 0) {
+         ul.html('<li>No comments yet.</li>');
+         ul.data('empty', true);
+       } else {
+         // If there are comments, sort them and put them in the list.
+         var comments = sortComments(data.comments);
+         speed = data.comments.length * 100;
+         appendComments(comments, ul);
+         ul.data('empty', false);
+       }
+       $('#cn' + id).slideUp(speed + 200);
+       ul.slideDown(speed);
+     },
+     error: function(request, textStatus, error) {
+       showError('Oops, there was a problem retrieving the comments.');
+     },
+     dataType: 'json'
+    });
+  }
+
+  /**
+   * Add a comment via ajax and insert the comment into the comment tree.
+   */
+  function addComment(form) {
+    var node_id = form.find('input[name="node"]').val();
+    var parent_id = form.find('input[name="parent"]').val();
+    var text = form.find('textarea[name="comment"]').val();
+    var proposal = form.find('textarea[name="proposal"]').val();
+
+    if (text == '') {
+      showError('Please enter a comment.');
+      return;
+    }
+
+    // Disable the form that is being submitted.
+    form.find('textarea,input').attr('disabled', 'disabled');
+
+    // Send the comment to the server.
+    $.ajax({
+      type: "POST",
+      url: opts.addCommentURL,
+      dataType: 'json',
+      data: {
+        node: node_id,
+        parent: parent_id,
+        text: text,
+        proposal: proposal
+      },
+      success: function(data, textStatus, error) {
+        // Reset the form.
+        if (node_id) {
+          hideProposeChange(node_id);
+        }
+        form.find('textarea')
+          .val('')
+          .add(form.find('input'))
+          .removeAttr('disabled');
+	var ul = $('#cl' + (node_id || parent_id));
+        if (ul.data('empty')) {
+          $(ul).empty();
+          ul.data('empty', false);
+        }
+        insertComment(data.comment);
+        var ao = $('#ao' + node_id);
+        ao.find('img').attr({'src': opts.commentBrightImage});
+        if (node_id) {
+          // if this was a "root" comment, remove the commenting box
+          // (the user can get it back by reopening the comment popup)
+          $('#ca' + node_id).slideUp();
+        }
+      },
+      error: function(request, textStatus, error) {
+        form.find('textarea,input').removeAttr('disabled');
+        showError('Oops, there was a problem adding the comment.');
+      }
+    });
+  }
+
+  /**
+   * Recursively append comments to the main comment list and children
+   * lists, creating the comment tree.
+   */
+  function appendComments(comments, ul) {
+    $.each(comments, function() {
+      var div = createCommentDiv(this);
+      ul.append($(document.createElement('li')).html(div));
+      appendComments(this.children, div.find('ul.comment-children'));
+      // To avoid stagnating data, don't store the comments children in data.
+      this.children = null;
+      div.data('comment', this);
+    });
+  }
+
+  /**
+   * After adding a new comment, it must be inserted in the correct
+   * location in the comment tree.
+   */
+  function insertComment(comment) {
+    var div = createCommentDiv(comment);
+
+    // To avoid stagnating data, don't store the comments children in data.
+    comment.children = null;
+    div.data('comment', comment);
+
+    var ul = $('#cl' + (comment.node || comment.parent));
+    var siblings = getChildren(ul);
+
+    var li = $(document.createElement('li'));
+    li.hide();
+
+    // Determine where in the parents children list to insert this comment.
+    for(i=0; i < siblings.length; i++) {
+      if (comp(comment, siblings[i]) <= 0) {
+        $('#cd' + siblings[i].id)
+          .parent()
+          .before(li.html(div));
+        li.slideDown('fast');
+        return;
+      }
+    }
+
+    // If we get here, this comment rates lower than all the others,
+    // or it is the only comment in the list.
+    ul.append(li.html(div));
+    li.slideDown('fast');
+  }
+
+  function acceptComment(id) {
+    $.ajax({
+      type: 'POST',
+      url: opts.acceptCommentURL,
+      data: {id: id},
+      success: function(data, textStatus, request) {
+        $('#cm' + id).fadeOut('fast');
+        $('#cd' + id).removeClass('moderate');
+      },
+      error: function(request, textStatus, error) {
+        showError('Oops, there was a problem accepting the comment.');
+      }
+    });
+  }
+
+  function deleteComment(id) {
+    $.ajax({
+      type: 'POST',
+      url: opts.deleteCommentURL,
+      data: {id: id},
+      success: function(data, textStatus, request) {
+        var div = $('#cd' + id);
+        if (data == 'delete') {
+          // Moderator mode: remove the comment and all children immediately
+          div.slideUp('fast', function() {
+            div.remove();
+          });
+          return;
+        }
+        // User mode: only mark the comment as deleted
+        div
+          .find('span.user-id:first')
+          .text('[deleted]').end()
+          .find('div.comment-text:first')
+          .text('[deleted]').end()
+          .find('#cm' + id + ', #dc' + id + ', #ac' + id + ', #rc' + id +
+                ', #sp' + id + ', #hp' + id + ', #cr' + id + ', #rl' + id)
+          .remove();
+        var comment = div.data('comment');
+        comment.username = '[deleted]';
+        comment.text = '[deleted]';
+        div.data('comment', comment);
+      },
+      error: function(request, textStatus, error) {
+        showError('Oops, there was a problem deleting the comment.');
+      }
+    });
+  }
+
+  function showProposal(id) {
+    $('#sp' + id).hide();
+    $('#hp' + id).show();
+    $('#pr' + id).slideDown('fast');
+  }
+
+  function hideProposal(id) {
+    $('#hp' + id).hide();
+    $('#sp' + id).show();
+    $('#pr' + id).slideUp('fast');
+  }
+
+  function showProposeChange(id) {
+    $('#pc' + id).hide();
+    $('#hc' + id).show();
+    var textarea = $('#pt' + id);
+    textarea.val(textarea.data('source'));
+    $.fn.autogrow.resize(textarea[0]);
+    textarea.slideDown('fast');
+  }
+
+  function hideProposeChange(id) {
+    $('#hc' + id).hide();
+    $('#pc' + id).show();
+    var textarea = $('#pt' + id);
+    textarea.val('').removeAttr('disabled');
+    textarea.slideUp('fast');
+  }
+
+  function toggleCommentMarkupBox(id) {
+    $('#mb' + id).toggle();
+  }
+
+  /** Handle when the user clicks on a sort by link. */
+  function handleReSort(link) {
+    var classes = link.attr('class').split(/\s+/);
+    for (var i=0; i<classes.length; i++) {
+      if (classes[i] != 'sort-option') {
+	by = classes[i].substring(2);
+      }
+    }
+    setComparator();
+    // Save/update the sortBy cookie.
+    var expiration = new Date();
+    expiration.setDate(expiration.getDate() + 365);
+    document.cookie= 'sortBy=' + escape(by) +
+                     ';expires=' + expiration.toUTCString();
+    $('ul.comment-ul').each(function(index, ul) {
+      var comments = getChildren($(ul), true);
+      comments = sortComments(comments);
+      appendComments(comments, $(ul).empty());
+    });
+  }
+
+  /**
+   * Function to process a vote when a user clicks an arrow.
+   */
+  function handleVote(link) {
+    if (!opts.voting) {
+      showError("You'll need to login to vote.");
+      return;
+    }
+
+    var id = link.attr('id');
+    if (!id) {
+      // Didn't click on one of the voting arrows.
+      return;
+    }
+    // If it is an unvote, the new vote value is 0,
+    // Otherwise it's 1 for an upvote, or -1 for a downvote.
+    var value = 0;
+    if (id.charAt(1) != 'u') {
+      value = id.charAt(0) == 'u' ? 1 : -1;
+    }
+    // The data to be sent to the server.
+    var d = {
+      comment_id: id.substring(2),
+      value: value
+    };
+
+    // Swap the vote and unvote links.
+    link.hide();
+    $('#' + id.charAt(0) + (id.charAt(1) == 'u' ? 'v' : 'u') + d.comment_id)
+      .show();
+
+    // The div the comment is displayed in.
+    var div = $('div#cd' + d.comment_id);
+    var data = div.data('comment');
+
+    // If this is not an unvote, and the other vote arrow has
+    // already been pressed, unpress it.
+    if ((d.value !== 0) && (data.vote === d.value * -1)) {
+      $('#' + (d.value == 1 ? 'd' : 'u') + 'u' + d.comment_id).hide();
+      $('#' + (d.value == 1 ? 'd' : 'u') + 'v' + d.comment_id).show();
+    }
+
+    // Update the comments rating in the local data.
+    data.rating += (data.vote === 0) ? d.value : (d.value - data.vote);
+    data.vote = d.value;
+    div.data('comment', data);
+
+    // Change the rating text.
+    div.find('.rating:first')
+      .text(data.rating + ' point' + (data.rating == 1 ? '' : 's'));
+
+    // Send the vote information to the server.
+    $.ajax({
+      type: "POST",
+      url: opts.processVoteURL,
+      data: d,
+      error: function(request, textStatus, error) {
+        showError('Oops, there was a problem casting that vote.');
+      }
+    });
+  }
+
+  /**
+   * Open a reply form used to reply to an existing comment.
+   */
+  function openReply(id) {
+    // Swap out the reply link for the hide link
+    $('#rl' + id).hide();
+    $('#cr' + id).show();
+
+    // Add the reply li to the children ul.
+    var div = $(renderTemplate(replyTemplate, {id: id})).hide();
+    $('#cl' + id)
+      .prepend(div)
+      // Setup the submit handler for the reply form.
+      .find('#rf' + id)
+      .submit(function(event) {
+        event.preventDefault();
+        addComment($('#rf' + id));
+        closeReply(id);
+      })
+      .find('input[type=button]')
+      .click(function() {
+        closeReply(id);
+      });
+    div.slideDown('fast', function() {
+      $('#rf' + id).find('textarea').focus();
+    });
+  }
+
+  /**
+   * Close the reply form opened with openReply.
+   */
+  function closeReply(id) {
+    // Remove the reply div from the DOM.
+    $('#rd' + id).slideUp('fast', function() {
+      $(this).remove();
+    });
+
+    // Swap out the hide link for the reply link
+    $('#cr' + id).hide();
+    $('#rl' + id).show();
+  }
+
+  /**
+   * Recursively sort a tree of comments using the comp comparator.
+   */
+  function sortComments(comments) {
+    comments.sort(comp);
+    $.each(comments, function() {
+      this.children = sortComments(this.children);
+    });
+    return comments;
+  }
+
+  /**
+   * Get the children comments from a ul. If recursive is true,
+   * recursively include childrens' children.
+   */
+  function getChildren(ul, recursive) {
+    var children = [];
+    ul.children().children("[id^='cd']")
+      .each(function() {
+        var comment = $(this).data('comment');
+        if (recursive)
+          comment.children = getChildren($(this).find('#cl' + comment.id), true);
+        children.push(comment);
+      });
+    return children;
+  }
+
+  /** Create a div to display a comment in. */
+  function createCommentDiv(comment) {
+    if (!comment.displayed && !opts.moderator) {
+      return $('<div class="moderate">Thank you!  Your comment will show up '
+               + 'once it is has been approved by a moderator.</div>');
+    }
+    // Prettify the comment rating.
+    comment.pretty_rating = comment.rating + ' point' +
+      (comment.rating == 1 ? '' : 's');
+    // Make a class (for displaying not yet moderated comments differently)
+    comment.css_class = comment.displayed ? '' : ' moderate';
+    // Create a div for this comment.
+    var context = $.extend({}, opts, comment);
+    var div = $(renderTemplate(commentTemplate, context));
+
+    // If the user has voted on this comment, highlight the correct arrow.
+    if (comment.vote) {
+      var direction = (comment.vote == 1) ? 'u' : 'd';
+      div.find('#' + direction + 'v' + comment.id).hide();
+      div.find('#' + direction + 'u' + comment.id).show();
+    }
+
+    if (opts.moderator || comment.text != '[deleted]') {
+      div.find('a.reply').show();
+      if (comment.proposal_diff)
+        div.find('#sp' + comment.id).show();
+      if (opts.moderator && !comment.displayed)
+        div.find('#cm' + comment.id).show();
+      if (opts.moderator || (opts.username == comment.username))
+        div.find('#dc' + comment.id).show();
+    }
+    return div;
+  }
+
+  /**
+   * A simple template renderer. Placeholders such as <%id%> are replaced
+   * by context['id'] with items being escaped. Placeholders such as <#id#>
+   * are not escaped.
+   */
+  function renderTemplate(template, context) {
+    var esc = $(document.createElement('div'));
+
+    function handle(ph, escape) {
+      var cur = context;
+      $.each(ph.split('.'), function() {
+        cur = cur[this];
+      });
+      return escape ? esc.text(cur || "").html() : cur;
+    }
+
+    return template.replace(/<([%#])([\w\.]*)\1>/g, function() {
+      return handle(arguments[2], arguments[1] == '%' ? true : false);
+    });
+  }
+
+  /** Flash an error message briefly. */
+  function showError(message) {
+    $(document.createElement('div')).attr({'class': 'popup-error'})
+      .append($(document.createElement('div'))
+               .attr({'class': 'error-message'}).text(message))
+      .appendTo('body')
+      .fadeIn("slow")
+      .delay(2000)
+      .fadeOut("slow");
+  }
+
+  /** Add a link the user uses to open the comments popup. */
+  $.fn.comment = function() {
+    return this.each(function() {
+      var id = $(this).attr('id').substring(1);
+      var count = COMMENT_METADATA[id];
+      var title = count + ' comment' + (count == 1 ? '' : 's');
+      var image = count > 0 ? opts.commentBrightImage : opts.commentImage;
+      var addcls = count == 0 ? ' nocomment' : '';
+      $(this)
+        .append(
+          $(document.createElement('a')).attr({
+            href: '#',
+            'class': 'sphinx-comment-open' + addcls,
+            id: 'ao' + id
+          })
+            .append($(document.createElement('img')).attr({
+              src: image,
+              alt: 'comment',
+              title: title
+            }))
+            .click(function(event) {
+              event.preventDefault();
+              show($(this).attr('id').substring(2));
+            })
+        )
+        .append(
+          $(document.createElement('a')).attr({
+            href: '#',
+            'class': 'sphinx-comment-close hidden',
+            id: 'ah' + id
+          })
+            .append($(document.createElement('img')).attr({
+              src: opts.closeCommentImage,
+              alt: 'close',
+              title: 'close'
+            }))
+            .click(function(event) {
+              event.preventDefault();
+              hide($(this).attr('id').substring(2));
+            })
+        );
+    });
+  };
+
+  var opts = {
+    processVoteURL: '/_process_vote',
+    addCommentURL: '/_add_comment',
+    getCommentsURL: '/_get_comments',
+    acceptCommentURL: '/_accept_comment',
+    deleteCommentURL: '/_delete_comment',
+    commentImage: '/static/_static/comment.png',
+    closeCommentImage: '/static/_static/comment-close.png',
+    loadingImage: '/static/_static/ajax-loader.gif',
+    commentBrightImage: '/static/_static/comment-bright.png',
+    upArrow: '/static/_static/up.png',
+    downArrow: '/static/_static/down.png',
+    upArrowPressed: '/static/_static/up-pressed.png',
+    downArrowPressed: '/static/_static/down-pressed.png',
+    voting: false,
+    moderator: false
+  };
+
+  if (typeof COMMENT_OPTIONS != "undefined") {
+    opts = jQuery.extend(opts, COMMENT_OPTIONS);
+  }
+
+  var popupTemplate = '\
+    <div class="sphinx-comments" id="sc<%id%>">\
+      <p class="sort-options">\
+        Sort by:\
+        <a href="#" class="sort-option byrating">best rated</a>\
+        <a href="#" class="sort-option byascage">newest</a>\
+        <a href="#" class="sort-option byage">oldest</a>\
+      </p>\
+      <div class="comment-header">Comments</div>\
+      <div class="comment-loading" id="cn<%id%>">\
+        loading comments... <img src="<%loadingImage%>" alt="" /></div>\
+      <ul id="cl<%id%>" class="comment-ul"></ul>\
+      <div id="ca<%id%>">\
+      <p class="add-a-comment">Add a comment\
+        (<a href="#" class="comment-markup" id="ab<%id%>">markup</a>):</p>\
+      <div class="comment-markup-box" id="mb<%id%>">\
+        reStructured text markup: <i>*emph*</i>, <b>**strong**</b>, \
+        <tt>``code``</tt>, \
+        code blocks: <tt>::</tt> and an indented block after blank line</div>\
+      <form method="post" id="cf<%id%>" class="comment-form" action="">\
+        <textarea name="comment" cols="80"></textarea>\
+        <p class="propose-button">\
+          <a href="#" id="pc<%id%>" class="show-propose-change">\
+            Propose a change ▹\
+          </a>\
+          <a href="#" id="hc<%id%>" class="hide-propose-change">\
+            Propose a change ▿\
+          </a>\
+        </p>\
+        <textarea name="proposal" id="pt<%id%>" cols="80"\
+                  spellcheck="false"></textarea>\
+        <input type="submit" value="Add comment" />\
+        <input type="hidden" name="node" value="<%id%>" />\
+        <input type="hidden" name="parent" value="" />\
+      </form>\
+      </div>\
+    </div>';
+
+  var commentTemplate = '\
+    <div id="cd<%id%>" class="sphinx-comment<%css_class%>">\
+      <div class="vote">\
+        <div class="arrow">\
+          <a href="#" id="uv<%id%>" class="vote" title="vote up">\
+            <img src="<%upArrow%>" />\
+          </a>\
+          <a href="#" id="uu<%id%>" class="un vote" title="vote up">\
+            <img src="<%upArrowPressed%>" />\
+          </a>\
+        </div>\
+        <div class="arrow">\
+          <a href="#" id="dv<%id%>" class="vote" title="vote down">\
+            <img src="<%downArrow%>" id="da<%id%>" />\
+          </a>\
+          <a href="#" id="du<%id%>" class="un vote" title="vote down">\
+            <img src="<%downArrowPressed%>" />\
+          </a>\
+        </div>\
+      </div>\
+      <div class="comment-content">\
+        <p class="tagline comment">\
+          <span class="user-id"><%username%></span>\
+          <span class="rating"><%pretty_rating%></span>\
+          <span class="delta"><%time.delta%></span>\
+        </p>\
+        <div class="comment-text comment"><#text#></div>\
+        <p class="comment-opts comment">\
+          <a href="#" class="reply hidden" id="rl<%id%>">reply ▹</a>\
+          <a href="#" class="close-reply" id="cr<%id%>">reply ▿</a>\
+          <a href="#" id="sp<%id%>" class="show-proposal">proposal ▹</a>\
+          <a href="#" id="hp<%id%>" class="hide-proposal">proposal ▿</a>\
+          <a href="#" id="dc<%id%>" class="delete-comment hidden">delete</a>\
+          <span id="cm<%id%>" class="moderation hidden">\
+            <a href="#" id="ac<%id%>" class="accept-comment">accept</a>\
+          </span>\
+        </p>\
+        <pre class="proposal" id="pr<%id%>">\
+<#proposal_diff#>\
+        </pre>\
+          <ul class="comment-children" id="cl<%id%>"></ul>\
+        </div>\
+        <div class="clearleft"></div>\
+      </div>\
+    </div>';
+
+  var replyTemplate = '\
+    <li>\
+      <div class="reply-div" id="rd<%id%>">\
+        <form id="rf<%id%>">\
+          <textarea name="comment" cols="80"></textarea>\
+          <input type="submit" value="Add reply" />\
+          <input type="button" value="Cancel" />\
+          <input type="hidden" name="parent" value="<%id%>" />\
+          <input type="hidden" name="node" value="" />\
+        </form>\
+      </div>\
+    </li>';
+
+  $(document).ready(function() {
+    init();
+  });
+})(jQuery);
+
+$(document).ready(function() {
+  // add comment anchors for all paragraphs that are commentable
+  $('.sphinx-has-comment').comment();
+
+  // highlight search words in search results
+  $("div.context").each(function() {
+    var params = $.getQueryParameters();
+    var terms = (params.q) ? params.q[0].split(/\s+/) : [];
+    var result = $(this);
+    $.each(terms, function() {
+      result.highlightText(this.toLowerCase(), 'highlighted');
+    });
+  });
+
+  // directly open comment window if requested
+  var anchor = document.location.hash;
+  if (anchor.substring(0, 9) == '#comment-') {
+    $('#ao' + anchor.substring(9)).click();
+    document.location.hash = '#s' + anchor.substring(9);
+  }
+});
diff --git a/documentation/_static/xmds_favicon.ico b/documentation/_static/xmds_favicon.ico
new file mode 100644
index 0000000..4e53c4a
Binary files /dev/null and b/documentation/_static/xmds_favicon.ico differ
diff --git a/documentation/_static/xmds_logo.png b/documentation/_static/xmds_logo.png
new file mode 100644
index 0000000..cfd7f0a
Binary files /dev/null and b/documentation/_static/xmds_logo.png differ
diff --git a/documentation/advanced_topics.html b/documentation/advanced_topics.html
new file mode 100644
index 0000000..f0969ae
--- /dev/null
+++ b/documentation/advanced_topics.html
@@ -0,0 +1,304 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>Advanced Topics — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="index.html" /> 
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+  <div class="section" id="advanced-topics">
+<span id="advancedtopics"></span><h1>Advanced Topics<a class="headerlink" href="#advanced-topics" title="Permalink to this headline">¶</a></h1>
+<p>This section has further details on some important topics.</p>
+<p><a class="reference internal" href="#importing"><em>Importing data</em></a> (importing data into XMDS2, and data formats used in the export)</p>
+<p><a class="reference internal" href="#convolutions"><em>Convolutions and Fourier transforms</em></a> (extra information on the Fourier transforms used in XMDS2, and applications to defining convolutions)</p>
+<p><a class="reference internal" href="#dimensionaliases"><em>Dimension aliases</em></a> (dimensions which are declared to be identical, useful for correlation functions)</p>
+<div class="section" id="importing-data">
+<span id="importing"></span><h2>Importing data<a class="headerlink" href="#importing-data" title="Permalink to this headline">¶</a></h2>
+<p>There are many cases where it is advantageous to import previously acquired data into XMDS2. For example, the differential equation you wish to solve may depend on a complicated functional form, which is more easily obtained via an analytical package such as Mathematica or Maple. Furthermore, importing data from another source can be quicker than needlessly performing calculations in XMDS2. In this tutorial, we shall consider an example of importing into XMDS2 a function generated in  [...]
+<p>Suppose we want to import the following function into XMDS2:</p>
+<div class="math">
+\[f(x) = x^2\]</div>
+<p>The first step is to create an hdf5 file, from XMDS2, which specifies the dimensions of the grid for the x dimension. Create and save a new XMDS2 file. For the purposes of this tutorial we shall call it “grid_specifier.xmds” with name “grid_specifier”. Within this file, enter the following “dummy” vector - which we shall call “gen_dummy” - which depends on the x dimension:</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><vector</span> <span class="na">type=</span><span class="s">"real"</span> <span class="na">name=</span><span class="s">"gen_dummy"</span> <span class="na">dimensions=</span><span class="s">"x"</span><span class="nt">></span>
+  <span class="nt"><components></span>dummy<span class="nt"></components></span>
+  <span class="nt"><initialisation></span>
+  <span class="cp"><![CDATA[</span>
+    <span class="n">dummy</span> <span class="o">=</span> <span class="n">x</span><span class="p">;</span>
+      <span class="cp">]]></span>
+  <span class="nt"></initialisation></span>
+<span class="nt"></vector></span>
+</pre></div>
+</div>
+<p>What “dummy” is is not actually important. It is only necessary that it is a function of <span class="math">\(x\)</span>. However, it is important that the domain and lattice for the <span class="math">\(x\)</span> dimension are identical to those in the XMDS2 you plan to import the function into. We output the following xsil file (in hdf5 format) by placing a breakpoint in the sequence block as follows:</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><sequence></span>
+  <span class="nt"><breakpoint</span> <span class="na">filename=</span><span class="s">"grid.xsil"</span> <span class="na">format=</span><span class="s">"hdf5"</span><span class="nt">></span>
+      <span class="nt"><dependencies></span>
+        gen_dummy
+      <span class="nt"></dependencies></span>
+  <span class="nt"></breakpoint></span>
+</pre></div>
+</div>
+<p>In terminal, compile the file “grid_specifier.xmds” in XMDS2 and run the c code as usual. This creates two files - “grid.xsil” and “grid.h5”. The file “grid.h5” contains the list of points which make up the grids for the x dimensions. This data can now be used to ensure that the function <span class="math">\(f(x)\)</span> which we will import into XMDS2 is compatible with the the specified grid in your primary XMDS2 file.</p>
+<p>In order to read the “grid.h5” data into Mathematica version 6.0, type the following command into terminal:.. code-block:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre>xsil2graphics2 -e grid.xsil
+</pre></div>
+</div>
+<p>This creates the Mathematica notebook “grid.nb”. Open this notebook in Mathematica and evaluate the first set of cells. This has loaded the grid information into Mathematica. For example, suppose you have specified that the <span class="math">\(x\)</span> dimension has a lattice of 128 points and a domain of (-32, 32). Then calling “x1” in Mathematica should return the following list:</p>
+<div class="highlight-none"><div class="highlight"><pre>{-32., -31.5, -31., -30.5, -30., -29.5, -29., -28.5, -28., -27.5,
+-27., -26.5, -26., -25.5, -25., -24.5, -24., -23.5, -23., -22.5,
+-22., -21.5, -21., -20.5, -20., -19.5, -19., -18.5, -18., -17.5,
+-17., -16.5, -16., -15.5, -15., -14.5, -14., -13.5, -13., -12.5,
+-12., -11.5, -11., -10.5, -10., -9.5, -9., -8.5, -8., -7.5, -7.,
+-6.5, -6., -5.5, -5., -4.5, -4., -3.5, -3., -2.5, -2., -1.5, -1.,
+-0.5, 0., 0.5, 1., 1.5, 2., 2.5, 3., 3.5, 4., 4.5, 5., 5.5, 6., 6.5,
+7., 7.5, 8., 8.5, 9., 9.5, 10., 10.5, 11., 11.5, 12., 12.5, 13.,
+13.5, 14., 14.5, 15., 15.5, 16., 16.5, 17., 17.5, 18., 18.5, 19.,
+19.5, 20., 20.5, 21., 21.5, 22., 22.5, 23., 23.5, 24., 24.5, 25.,
+25.5, 26., 26.5, 27., 27.5, 28., 28.5, 29., 29.5, 30., 30.5, 31.,
+31.5}
+</pre></div>
+</div>
+<p>This is, of course, the list of points which define our grid.</p>
+<p>We are now in a position to define the function <span class="math">\(f(x)\)</span> in Mathematica. Type the following command into a cell in the Mathematica notebook “grid.nb”:</p>
+<div class="highlight-none"><div class="highlight"><pre>f[x_]:= x^2
+</pre></div>
+</div>
+<p>At this stage this is an abstract mathematical function as defined in Mathematica. What we need is a list of values for <span class="math">\(f(x)\)</span> corresponding to the specified grid points. We will call this list “func”. This achieved by simply acting the function on the list of grid points “x1”:</p>
+<div class="highlight-none"><div class="highlight"><pre>func := f[x1]
+</pre></div>
+</div>
+<p>For the example grid mentioned above, calling “func” gives the following list:</p>
+<div class="highlight-none"><div class="highlight"><pre>{1024., 992.25, 961., 930.25, 900., 870.25, 841., 812.25, 784.,
+756.25, 729., 702.25, 676., 650.25, 625., 600.25, 576., 552.25, 529.,
+506.25, 484., 462.25, 441., 420.25, 400., 380.25, 361., 342.25, 324.,
+306.25, 289., 272.25, 256., 240.25, 225., 210.25, 196., 182.25, 169.,
+156.25, 144., 132.25, 121., 110.25, 100., 90.25, 81., 72.25, 64.,
+56.25, 49., 42.25, 36., 30.25, 25., 20.25, 16., 12.25, 9., 6.25, 4.,
+2.25, 1., 0.25, 0., 0.25, 1., 2.25, 4., 6.25, 9., 12.25, 16., 20.25,
+25., 30.25, 36., 42.25, 49., 56.25, 64., 72.25, 81., 90.25, 100.,
+110.25, 121., 132.25, 144., 156.25, 169., 182.25, 196., 210.25, 225.,
+240.25, 256., 272.25, 289., 306.25, 324., 342.25, 361., 380.25, 400.,
+420.25, 441., 462.25, 484., 506.25, 529., 552.25, 576., 600.25, 625.,
+650.25, 676., 702.25, 729., 756.25, 784., 812.25, 841., 870.25, 900.,
+930.25, 961., 992.25}
+</pre></div>
+</div>
+<p>The next step is to export the list “func” as an h5 file that XMDS2 can read. This is done by typing the following command into a Mathematica cell:</p>
+<div class="highlight-none"><div class="highlight"><pre>SetDirectory[NotebookDirectory[]];
+Export["func.h5", {func, x1}, {"Datasets", { "function_x", "x"}}]
+</pre></div>
+</div>
+<p>In the directory containing the notebook “grid.nb” you should now see the file “func.h5”. This file essentially contains the list <tt class="docutils literal"><span class="pre">{func,</span> <span class="pre">x1}</span></tt>. However, the hdf5 format stores func and x1 as separate entities called “Datasets”. For importation into XMDS2 it is necessary that these datasets are named. This is precisely what the segment <tt class="docutils literal"><span [...]
+<p>The final step is to import the file “func.h5” into your primary XMDS2 file. This data will be stored as a vector called “gen_function_x”, in component “function_x”.</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><vector</span> <span class="na">type=</span><span class="s">"real"</span> <span class="na">name=</span><span class="s">"gen_function_x"</span> <span class="na">dimensions=</span><span class="s">"x"</span><span class="nt">></span>
+  <span class="nt"><components></span>function_x<span class="nt"></components></span>
+  <span class="nt"><initialisation</span> <span class="na">kind=</span><span class="s">"hdf5"</span><span class="nt">></span>
+    <span class="nt"><filename></span> function_x.h5 <span class="nt"></filename></span>
+  <span class="nt"></initialisation></span>
+<span class="nt"></vector></span>
+</pre></div>
+</div>
+<p>You’re now done. Anytime you want to use <span class="math">\(f(x)\)</span> you can simply refer to “function_x” in the vector “gen_function_x”.</p>
+<p>The situation is slightly more complicated if the function you wish to import depends on more than one dimension. For example, consider</p>
+<div class="math">
+\[g(x,y) = x \sin(y)\]</div>
+<p>As for the single dimensional case, we need to export an hdf5 file from XMDS2 which specifies the dimensions of the grid. As in the one dimensional case, this is done by creating a dummy vector which depends on all the relevant dimensions:</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><vector</span> <span class="na">type=</span><span class="s">"real"</span> <span class="na">name=</span><span class="s">"gen_dummy"</span> <span class="na">dimensions=</span><span class="s">"x y"</span><span class="nt">></span>
+  <span class="nt"><components></span>dummy<span class="nt"></components></span>
+  <span class="nt"><initialisation></span>
+  <span class="cp"><![CDATA[</span>
+    <span class="n">dummy</span> <span class="o">=</span> <span class="n">x</span><span class="p">;</span>
+      <span class="cp">]]></span>
+  <span class="nt"></initialisation></span>
+<span class="nt"></vector></span>
+</pre></div>
+</div>
+<p>and exporting it as shown above.</p>
+<p>After importing the grid data into Mathematica, define the multi-dimensional function which you wish to import into XMDS2:</p>
+<div class="highlight-none"><div class="highlight"><pre>g[x_,y_]:= x*Sin[y]
+</pre></div>
+</div>
+<p>We need to create a 2x2 array of data which depends upon the imported lists x1 and y1. This can be done by using the Table function:</p>
+<div class="highlight-none"><div class="highlight"><pre>func := Table[g[x, p], {x, x1}, {p, p1}]
+</pre></div>
+</div>
+<p>This function can be exported as an h5 file,</p>
+<div class="highlight-none"><div class="highlight"><pre>SetDirectory[NotebookDirectory[]];
+Export["func.h5", {func, x1, y1}, {"Datasets", { "function_x", "x", "y"}}]
+</pre></div>
+</div>
+<p>and imported into XMDS2 as outlined above.</p>
+</div>
+<div class="section" id="convolutions-and-fourier-transforms">
+<span id="convolutions"></span><h2>Convolutions and Fourier transforms<a class="headerlink" href="#convolutions-and-fourier-transforms" title="Permalink to this headline">¶</a></h2>
+<p>When evaluating a numerical Fourier transform, XMDS2 doesn’t behave as expected. While many simulations have ranges in their spatial coordinate (here assumed to be x) that range from some negative value <span class="math">\(x_\text{min}\)</span> to some positive value <span class="math">\(x_\text{max}\)</span>, the Fourier transform used in XMDS2 treats all spatial coordinates as starting at zero. The result of this is that a phase factor of the form <span class="math">\(e^{-i x [...]
+<p>The standard Fourier transform is</p>
+<div class="math">
+\[\mathcal{F}\left[f(x)\right](k) = \frac{1}{\sqrt{2\pi}}\int_{x_\text{min}}^{x_\text{max}} f(x) e^{-i x k} dx\]</div>
+<p>The XMDS2 Fourier transform is</p>
+<div class="math">
+\[\begin{split}\tilde{\mathcal{F}}\left[f(x)\right](k) &= \frac{1}{\sqrt{2\pi}}\int_{x_\text{min}}^{x_\text{max}} f(x) e^{-i (x+ x_\text{min}) k} dx \\
+&= e^{-i x_\text{min} k} \mathcal{F}\left[f(x)\right](k)\end{split}\]</div>
+<p>When the number of forward Fourier transforms and backwards Fourier transforms are unequal a phase factor is required. Some examples of using Fourier transforms in XMDS2 are shown below.</p>
+<div class="section" id="example-1">
+<h3>Example 1<a class="headerlink" href="#example-1" title="Permalink to this headline">¶</a></h3>
+<img alt="_images/FourierTransformEx1.png" class="align-center" src="_images/FourierTransformEx1.png" />
+<p>When data is input in Fourier space and output in real space there is one backwards Fourier transform is required. Therefore the Fourier space data must be multiplied by a phase factor before the backwards Fourier transform is applied.</p>
+<div class="math">
+\[\mathcal{F}^{-1}[F(k)](x) = \tilde{\mathcal{F}}[e^{i x_\text{min} k} F(k)](x)\]</div>
+</div>
+<div class="section" id="example-2">
+<h3>Example 2<a class="headerlink" href="#example-2" title="Permalink to this headline">¶</a></h3>
+<img alt="_images/FourierTransformEx2.png" class="align-center" src="_images/FourierTransformEx2.png" />
+<p>Functions of the form <span class="math">\(h(x) = \int f(x') g(x-x') dx'\)</span> can be evaluated using the convolution theorem:</p>
+<div class="math">
+\[\mathcal{F}[h(x)](k) = \mathcal{F}[f(x)](k) \times \mathcal{F}[g(x)](k)\]</div>
+<p>This requires two forward Fourier transforms to get the two functions f and g into Fourier space, and one backwards Fourier transform to get the resulting product back into real space. Thus in Fourier space the product needs to be multiplied by a phase factor <span class="math">\(e^{-i x_\text{min} k}\)</span></p>
+</div>
+<div class="section" id="example-3">
+<h3>Example 3<a class="headerlink" href="#example-3" title="Permalink to this headline">¶</a></h3>
+<img alt="_images/FourierTransformEx3.png" class="align-center" src="_images/FourierTransformEx3.png" />
+<p>Sometimes when the convolution theorem is used one of the forward Fourier transforms is calculated analytically and input in Fourier space. In this case only one forward numerical Fourier transform and one backward numerical Fourier transform is used. The number of forward and backward transforms are equal, so no phase factor is required.</p>
+</div>
+</div>
+<div class="section" id="loose-geometry-matching-mode">
+<span id="loosegeometrymatchingmode"></span><h2>‘Loose’ <tt class="docutils literal"><span class="pre">geometry_matching_mode</span></tt><a class="headerlink" href="#loose-geometry-matching-mode" title="Permalink to this headline">¶</a></h2>
+</div>
+<div class="section" id="dimension-aliases">
+<span id="dimensionaliases"></span><h2>Dimension aliases<a class="headerlink" href="#dimension-aliases" title="Permalink to this headline">¶</a></h2>
+<p>Dimension aliases specify that two or more dimensions have exactly the same <tt class="docutils literal"><span class="pre">lattice</span></tt>, <tt class="docutils literal"><span class="pre">domain</span></tt> and <tt class="docutils literal"><span class="pre">transform</span></tt>.  This can be useful in situations where the problem enforces this, for example when computing correlation functions or representing square matrices.</p>
+<p>Dimension aliases are not just a short-hand for defining an additional dimension, they also permit dimensions to be accessed <a class="reference internal" href="reference_elements.html#referencingnonlocal"><em>non-locally</em></a>, which is essential when computing spatial correlation functions.</p>
+<p>Here is how to compute a spatial correlation function <span class="math">\(g^{(1)}(x, x') = \psi^*(x) \psi(x')\)</span> of the quantity <tt class="docutils literal"><span class="pre">psi</span></tt>:</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+
+  <span class="c"><!-- name, features block --></span>
+
+  <span class="nt"><geometry></span>
+    <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+    <span class="nt"><transverse_dimensions></span>
+      <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"x"</span> <span class="na">lattice=</span><span class="s">"1024"</span> <span class="na">domain=</span><span class="s">"(-1.0, 1.0)"</span> <span class="na">aliases=</span><span class="s">"xp"</span> <span class="nt">/></span>
+    <span class="nt"></transverse_dimensions></span>
+  <span class="nt"></geometry></span>
+
+  <span class="nt"><vector</span> <span class="na">name=</span><span class="s">"wavefunction"</span> <span class="na">type=</span><span class="s">"complex"</span> <span class="nt">></span>
+    <span class="nt"><components></span> psi <span class="nt"></components></span>
+    <span class="nt"><initialisation></span>
+      <span class="c"><!-- initialisation code --></span>
+    <span class="nt"></initialisation></span>
+  <span class="nt"></vector></span>
+
+  <span class="nt"><computed_vector</span> <span class="na">name=</span><span class="s">"correlation"</span> <span class="na">dimensions=</span><span class="s">"x xp"</span> <span class="na">type=</span><span class="s">"complex"</span> <span class="nt">></span>
+    <span class="nt"><components></span> g1 <span class="nt"></components></span>
+    <span class="nt"><evaluation></span>
+      <span class="nt"><dependencies></span> wavefunction <span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">g1</span> <span class="o">=</span> <span class="nf">conj</span><span class="p">(</span><span class="n">psi</span><span class="p">(</span><span class="n">x</span> <span class="o">=></span> <span class="n">x</span><span class="p">))</span> <span class="o">*</span> <span class="n">psi</span><span class="p">(</span><span class="n">x</span> <span class="o">=></span> <span class="n">xp</span><span class="p">);</span>
+      <span class="cp">]]></span>
+    <span class="nt"></evaluation></span>
+  <span class="nt"></computed_vector></span>
+
+  <span class="c"><!-- integration and sampling code --></span>
+
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+<p>In this simulation note that the vector <tt class="docutils literal"><span class="pre">wavefunction</span></tt> defaults to only having the dimension “x” even though “xp” is also a dimension (implicitly declared through the <tt class="docutils literal"><span class="pre">aliases</span></tt> attribute).  <tt class="docutils literal"><span class="pre">vector</span></tt>‘s without an explicit <tt class="docutils literal"><span class="pre">dimensions</span></t [...]
+<p>See the example <tt class="docutils literal"><span class="pre">groundstate_gaussian.xmds</span></tt> for a complete example.</p>
+</div>
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="index.html">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+  <h3><a href="index.html">Table Of Contents</a></h3>
+  <ul>
+<li><a class="reference internal" href="#">Advanced Topics</a><ul>
+<li><a class="reference internal" href="#importing-data">Importing data</a></li>
+<li><a class="reference internal" href="#convolutions-and-fourier-transforms">Convolutions and Fourier transforms</a><ul>
+<li><a class="reference internal" href="#example-1">Example 1</a></li>
+<li><a class="reference internal" href="#example-2">Example 2</a></li>
+<li><a class="reference internal" href="#example-3">Example 3</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#loose-geometry-matching-mode">‘Loose’ <tt class="docutils literal"><span class="pre">geometry_matching_mode</span></tt></a></li>
+<li><a class="reference internal" href="#dimension-aliases">Dimension aliases</a></li>
+</ul>
+</li>
+</ul>
+
+<div id="searchbox" style="display: none">
+  <h3>Quick search</h3>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" />
+      <input type="submit" value="Go" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    <p class="searchtip" style="font-size: 90%">
+    Enter search terms or a module, class or function name.
+    </p>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/documentation/developer.html b/documentation/developer.html
new file mode 100644
index 0000000..0a74719
--- /dev/null
+++ b/documentation/developer.html
@@ -0,0 +1,263 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>Developer Documentation — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="index.html" /> 
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+  <div class="section" id="developer-documentation">
+<h1>Developer Documentation<a class="headerlink" href="#developer-documentation" title="Permalink to this headline">¶</a></h1>
+<p>Developers need to know more than users.  For example, they need to know about the test suite, and writing test cases.  They need to know how to perform a developer installation.  They need to know how to edit and compile this documentation.  They need a step-by-step release process.</p>
+<div class="section" id="test-scripts">
+<span id="testscripts"></span><h2>Test scripts<a class="headerlink" href="#test-scripts" title="Permalink to this headline">¶</a></h2>
+<p>Every time you add a new feature and/or fix a new and exciting bug, it is a great idea to make sure that the new feature works and/or the bug stays fixed.  Fortunately, it is pleasantly easy to add a test case to the testing suite.</p>
+<ol class="arabic simple">
+<li>Write normal XMDS script that behaves as you expect.</li>
+<li>Add a <tt class="docutils literal"><span class="pre"><testing></span></tt> element to your script.  You can read the description of this element and its contents below, and have a look at other testcases for examples, but the basic structure is simple:.</li>
+</ol>
+<pre class="literal-block">
+<<a class="reference internal" href="#testingelement"><em>testing</em></a>>
+  <<a class="reference internal" href="#commandlineelement"><em>command_line</em></a>> <<a class="reference internal" href="#commandlineelement"><em>/command_line</em></a>>
+  <<a class="reference internal" href="reference_elements.html#argumentselement"><em>arguments</em></a>>
+    <<a class="reference internal" href="reference_elements.html#argumentelement"><em>argument</em></a> />
+    <<a class="reference internal" href="reference_elements.html#argumentelement"><em>argument</em></a> />
+    ...
+  <<a class="reference internal" href="reference_elements.html#argumentselement"><em>/arguments</em></a>>
+  <<a class="reference internal" href="#inputxsilfileelement"><em>input_xsil_file</em></a> />
+  <<a class="reference internal" href="#xsilfileelement"><em>xsil_file</em></a>>
+    <<a class="reference internal" href="#momentgroupelement"><em>moment_group</em></a> />
+    <<a class="reference internal" href="#momentgroupelement"><em>moment_group</em></a> />
+    ...
+  <<a class="reference internal" href="#xsilfileelement"><em>/xsil_file</em></a>>
+<<a class="reference internal" href="#testingelement"><em>/testing</em></a>>
+</pre>
+<ol class="arabic simple" start="3">
+<li>Put into the appropriate <tt class="docutils literal"><span class="pre">testsuite/</span></tt> directory.</li>
+<li>run <tt class="docutils literal"><span class="pre">./run_tests.py</span></tt> This will automatically generate your <tt class="docutils literal"><span class="pre">_expected</span></tt> files.</li>
+<li>Commit the <tt class="docutils literal"><span class="pre">.xmds</span></tt>, <tt class="docutils literal"><span class="pre">*_expected.xsil</span></tt> file and any <tt class="docutils literal"><span class="pre">*_expected*</span></tt> data files.</li>
+</ol>
+<div class="section" id="testing-element">
+<span id="testingelement"></span><h3>Testing element<a class="headerlink" href="#testing-element" title="Permalink to this headline">¶</a></h3>
+</div>
+<div class="section" id="command-line-element">
+<span id="commandlineelement"></span><h3>command_line element<a class="headerlink" href="#command-line-element" title="Permalink to this headline">¶</a></h3>
+</div>
+<div class="section" id="input-xsil-file-element">
+<span id="inputxsilfileelement"></span><h3>input_xsil_file element<a class="headerlink" href="#input-xsil-file-element" title="Permalink to this headline">¶</a></h3>
+</div>
+<div class="section" id="xsil-file-element">
+<span id="xsilfileelement"></span><h3>xsil_file element<a class="headerlink" href="#xsil-file-element" title="Permalink to this headline">¶</a></h3>
+</div>
+<div class="section" id="moment-group-element">
+<span id="momentgroupelement"></span><h3>moment_group element<a class="headerlink" href="#moment-group-element" title="Permalink to this headline">¶</a></h3>
+</div>
+</div>
+<div class="section" id="steps-to-update-xmds-script-validator-xml-schema">
+<h2>Steps to update <tt class="docutils literal"><span class="pre">XMDS</span></tt> script validator (XML schema)<a class="headerlink" href="#steps-to-update-xmds-script-validator-xml-schema" title="Permalink to this headline">¶</a></h2>
+<ol class="arabic simple">
+<li>Modify <tt class="docutils literal"><span class="pre">xpdeint/support/xpdeint.rnc</span></tt>. This is a RelaxNG compact file, which specifies the XML schema which is only used for issuing warnings to users about missing or extraneous XML tags / attributes.</li>
+<li>Run <tt class="docutils literal"><span class="pre">make</span></tt> in <tt class="docutils literal"><span class="pre">xpdeint/support/</span></tt> to update <tt class="docutils literal"><span class="pre">xpdeint/support/xpdeint.rng</span></tt>. This is the file which is actually used, which is in RelaxNG format, but RelaxNG compact is easier to read and edit.</li>
+<li>Commit both <tt class="docutils literal"><span class="pre">xpdeint/support/xpdeint.rnc</span></tt> and <tt class="docutils literal"><span class="pre">xpdeint/support/xpdeint.rng</span></tt>.</li>
+</ol>
+</div>
+<div class="section" id="directory-layout">
+<h2>Directory layout<a class="headerlink" href="#directory-layout" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="xmds2-s-code-and-templates">
+<h3>XMDS2’s code and templates<a class="headerlink" href="#xmds2-s-code-and-templates" title="Permalink to this headline">¶</a></h3>
+<p>All <tt class="docutils literal"><span class="pre">.tmpl</span></tt> files are Cheetah template files.  These are used to generate C++ code.  These templates are compiled as part of the XMDS2 build process to <tt class="docutils literal"><span class="pre">.py</span></tt> files of the same name.  Do not edit the generated <tt class="docutils literal"><span class="pre">.py</span></tt> files, always edit the <tt class="docutils literal"><span class="pre">.tmpl</span></tt> files and regen [...]
+<ul>
+<li><dl class="first docutils">
+<dt><tt class="docutils literal"><span class="pre">xpdeint/</span></tt>:</dt>
+<dd><ul class="first last">
+<li><dl class="first docutils">
+<dt><tt class="docutils literal"><span class="pre">Features/</span></tt>: Code for all <tt class="docutils literal"><span class="pre"><feature></span></tt> elements, such as <tt class="docutils literal"><span class="pre"><globals></span></tt> and <tt class="docutils literal"><span class="pre"><auto_vectorise></span></tt></dt>
+<dd><ul class="first last simple">
+<li><tt class="docutils literal"><span class="pre">Transforms/</span></tt>: Code for the Fourier and matrix-based transforms (including MPI variants).</li>
+</ul>
+</dd>
+</dl>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">Geometry/</span></tt>: Code for describing the geometry of simulation dimensions and domains.  Includes code for <tt class="docutils literal"><span class="pre">Geometry</span></tt>, <tt class="docutils literal"><span class="pre">Field</span></tt> and all <tt class="docutils literal"><span class="pre">DimensionRepresentations</span></tt>.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">Operators/</span></tt>: Code for all <tt class="docutils literal"><span class="pre"><operator></span></tt> elements, including <tt class="docutils literal"><span class="pre">IP</span></tt>, <tt class="docutils literal"><span class="pre">EX</span></tt> and the temporal derivative operator <tt class="docutils literal"><span class="pre">DeltaA</span></tt>.</p>
+</li>
+<li><dl class="first docutils">
+<dt><tt class="docutils literal"><span class="pre">Segments/</span></tt>: Code for all elements that can appear in a <tt class="docutils literal"><span class="pre"><segments></span></tt> tag.  This includes <tt class="docutils literal"><span class="pre"><integrate></span></tt>, <tt class="docutils literal"><span class="pre"><filter></span></tt>, and <tt class="docutils literal"><span class="pre"><breakpoint></span></tt>.</dt>
+<dd><ul class="first last simple">
+<li><tt class="docutils literal"><span class="pre">Integrators</span></tt>: Code for fixed and adaptive integration schemes, and all steppers (e.g. <tt class="docutils literal"><span class="pre">RK4</span></tt>, <tt class="docutils literal"><span class="pre">RK45</span></tt>, <tt class="docutils literal"><span class="pre">RK9</span></tt>, etc.)</li>
+</ul>
+</dd>
+</dl>
+</li>
+<li><dl class="first docutils">
+<dt><tt class="docutils literal"><span class="pre">Stochastic/</span></tt>: Code for all random number generators and the random variables derived from them.</dt>
+<dd><ul class="first last simple">
+<li><tt class="docutils literal"><span class="pre">Generators/</span></tt>: Code for random number generators, includes <tt class="docutils literal"><span class="pre">dSFMT</span></tt>, <tt class="docutils literal"><span class="pre">POSIX</span></tt>, <tt class="docutils literal"><span class="pre">Solirte</span></tt>.</li>
+<li><tt class="docutils literal"><span class="pre">RandomVariables/</span></tt>: Code for the random variables derived from the random number generators.  These are the gaussian, poissonian and uniform random variables.</li>
+</ul>
+</dd>
+</dl>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">SimulationDrivers/</span></tt>: Code for all <tt class="docutils literal"><span class="pre"><driver></span></tt> elements.  In particular, this is where the location of MPI and multi-path code.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">Vectors/</span></tt>: Code for all <tt class="docutils literal"><span class="pre"><vector></span></tt> elements, and their initialisation.  This includes normal <tt class="docutils literal"><span class="pre"><vector></span></tt> elements as well as <tt class="docutils literal"><span class="pre"><computed_vector></span></tt> and <tt class="docutils literal"><span class="pre"><noise_vector></span></ [...]
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">includes/</span></tt>: C++ header and sources files used by the generated simulations.</p>
+</li>
+<li><dl class="first docutils">
+<dt><tt class="docutils literal"><span class="pre">support/</span></tt>: Support files</dt>
+<dd><ul class="first last simple">
+<li><tt class="docutils literal"><span class="pre">wscript</span></tt>: <tt class="docutils literal"><span class="pre">waf</span></tt> build script for configuring and compiling generated simulations</li>
+<li><tt class="docutils literal"><span class="pre">xpdeint.rnc</span></tt>: Compact RelaxNG XML validation for XMDS scripts.  This is the source file for the XML RelaxNG file <tt class="docutils literal"><span class="pre">xpdeint.rng</span></tt></li>
+<li><tt class="docutils literal"><span class="pre">xpdeint.rng</span></tt>: RelaxNG XML validation for XMDS scripts.  To regenerate this file from <tt class="docutils literal"><span class="pre">xpdeint.rnc</span></tt>, just run <tt class="docutils literal"><span class="pre">make</span></tt> in this directory.</li>
+</ul>
+</dd>
+</dl>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">waf/</span></tt>: Our included version of the Python configuration and build tool <tt class="docutils literal"><span class="pre">waf</span></tt>.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">waf_extensions/</span></tt>: <tt class="docutils literal"><span class="pre">waf</span></tt> tool for compiling Cheetah templates.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">xsil2graphics2/</span></tt>: Templates for the output formats supported by <tt class="docutils literal"><span class="pre">xsil2graphics2</span></tt>.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">wscript</span></tt>: <tt class="docutils literal"><span class="pre">waf</span></tt> build script for XMDS2 itself.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">CodeParser.py</span></tt>: Minimally parses included C++ code for handling nonlocal dimension access, IP/EX operators and IP operator validation.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">Configuration.py</span></tt>: Manages configuration and building of generated simulations.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">FriendlyPlusStyle.py</span></tt>: Sphinx plug-in to improve formatting of XMDS scripts in user documentation.</p>
+</li>
+<li><p class="first">This directory also contains code for the input script parser, code blocks, code indentation, and the root <tt class="docutils literal"><span class="pre">_ScriptElement</span></tt> class.</p>
+</li>
+</ul>
+</dd>
+</dl>
+</li>
+</ul>
+</div>
+<div class="section" id="support-files">
+<h3>Support files<a class="headerlink" href="#support-files" title="Permalink to this headline">¶</a></h3>
+<ul>
+<li><dl class="first docutils">
+<dt><tt class="docutils literal"><span class="pre">admin/</span></tt>: Documentation source, Linux installer and release scripts.</dt>
+<dd><ul class="first last simple">
+<li><tt class="docutils literal"><span class="pre">developer-doc-source/</span></tt>: source for epydoc python class documentation (generated from python code).</li>
+<li><tt class="docutils literal"><span class="pre">userdoc-source/</span></tt>: source for the user documentation (results visible at www.xmds.org and xmds2.readthedocs.org).</li>
+<li><tt class="docutils literal"><span class="pre">xpdeint.tmbundle/</span></tt>: TextMate support bundle for Cheetah templates and XMDS scripts</li>
+</ul>
+</dd>
+</dl>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">bin/</span></tt>: Executable scripts to be installed as part of XMDS2 (includes <tt class="docutils literal"><span class="pre">xmds2</span></tt> and <tt class="docutils literal"><span class="pre">xsil2graphics2</span></tt>).</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">examples/</span></tt>: Example XMDS2 input scripts demonstrating most of XMDS2’s features.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">testsuite/</span></tt>: Testsuite of XMDS2 scripts.  Run the testsuite by executing <tt class="docutils literal"><span class="pre">./run_tests.py</span></tt></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="index.html">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+  <h3><a href="index.html">Table Of Contents</a></h3>
+  <ul>
+<li><a class="reference internal" href="#">Developer Documentation</a><ul>
+<li><a class="reference internal" href="#test-scripts">Test scripts</a><ul>
+<li><a class="reference internal" href="#testing-element">Testing element</a></li>
+<li><a class="reference internal" href="#command-line-element">command_line element</a></li>
+<li><a class="reference internal" href="#input-xsil-file-element">input_xsil_file element</a></li>
+<li><a class="reference internal" href="#xsil-file-element">xsil_file element</a></li>
+<li><a class="reference internal" href="#moment-group-element">moment_group element</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#steps-to-update-xmds-script-validator-xml-schema">Steps to update <tt class="docutils literal"><span class="pre">XMDS</span></tt> script validator (XML schema)</a></li>
+<li><a class="reference internal" href="#directory-layout">Directory layout</a><ul>
+<li><a class="reference internal" href="#xmds2-s-code-and-templates">XMDS2’s code and templates</a></li>
+<li><a class="reference internal" href="#support-files">Support files</a></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+
+<div id="searchbox" style="display: none">
+  <h3>Quick search</h3>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" />
+      <input type="submit" value="Go" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    <p class="searchtip" style="font-size: 90%">
+    Enter search terms or a module, class or function name.
+    </p>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/documentation/doctrees/advanced_topics.doctree b/documentation/doctrees/advanced_topics.doctree
new file mode 100644
index 0000000..b74da9d
Binary files /dev/null and b/documentation/doctrees/advanced_topics.doctree differ
diff --git a/documentation/doctrees/developer.doctree b/documentation/doctrees/developer.doctree
new file mode 100644
index 0000000..d35b5b9
Binary files /dev/null and b/documentation/doctrees/developer.doctree differ
diff --git a/documentation/doctrees/documentation_toc.doctree b/documentation/doctrees/documentation_toc.doctree
new file mode 100644
index 0000000..484ebb2
Binary files /dev/null and b/documentation/doctrees/documentation_toc.doctree differ
diff --git a/documentation/doctrees/environment.pickle b/documentation/doctrees/environment.pickle
new file mode 100644
index 0000000..59b0ff3
Binary files /dev/null and b/documentation/doctrees/environment.pickle differ
diff --git a/documentation/doctrees/faq.doctree b/documentation/doctrees/faq.doctree
new file mode 100644
index 0000000..c6a8747
Binary files /dev/null and b/documentation/doctrees/faq.doctree differ
diff --git a/documentation/doctrees/index.doctree b/documentation/doctrees/index.doctree
new file mode 100644
index 0000000..b9b3762
Binary files /dev/null and b/documentation/doctrees/index.doctree differ
diff --git a/documentation/doctrees/installation.doctree b/documentation/doctrees/installation.doctree
new file mode 100644
index 0000000..2d58a38
Binary files /dev/null and b/documentation/doctrees/installation.doctree differ
diff --git a/documentation/doctrees/introduction.doctree b/documentation/doctrees/introduction.doctree
new file mode 100644
index 0000000..f8da832
Binary files /dev/null and b/documentation/doctrees/introduction.doctree differ
diff --git a/documentation/doctrees/licensing.doctree b/documentation/doctrees/licensing.doctree
new file mode 100644
index 0000000..0b59a30
Binary files /dev/null and b/documentation/doctrees/licensing.doctree differ
diff --git a/documentation/doctrees/news.doctree b/documentation/doctrees/news.doctree
new file mode 100644
index 0000000..ffddd34
Binary files /dev/null and b/documentation/doctrees/news.doctree differ
diff --git a/documentation/doctrees/optimisation_hints.doctree b/documentation/doctrees/optimisation_hints.doctree
new file mode 100644
index 0000000..b4a699f
Binary files /dev/null and b/documentation/doctrees/optimisation_hints.doctree differ
diff --git a/documentation/doctrees/reference_elements.doctree b/documentation/doctrees/reference_elements.doctree
new file mode 100644
index 0000000..98230a5
Binary files /dev/null and b/documentation/doctrees/reference_elements.doctree differ
diff --git a/documentation/doctrees/reference_index.doctree b/documentation/doctrees/reference_index.doctree
new file mode 100644
index 0000000..70e2246
Binary files /dev/null and b/documentation/doctrees/reference_index.doctree differ
diff --git a/documentation/doctrees/reference_installation_and_configuration.doctree b/documentation/doctrees/reference_installation_and_configuration.doctree
new file mode 100644
index 0000000..d900121
Binary files /dev/null and b/documentation/doctrees/reference_installation_and_configuration.doctree differ
diff --git a/documentation/doctrees/reference_schema.doctree b/documentation/doctrees/reference_schema.doctree
new file mode 100644
index 0000000..cef0a70
Binary files /dev/null and b/documentation/doctrees/reference_schema.doctree differ
diff --git a/documentation/doctrees/reference_usefulXMLSyntax.doctree b/documentation/doctrees/reference_usefulXMLSyntax.doctree
new file mode 100644
index 0000000..666efb8
Binary files /dev/null and b/documentation/doctrees/reference_usefulXMLSyntax.doctree differ
diff --git a/documentation/doctrees/tutorial.doctree b/documentation/doctrees/tutorial.doctree
new file mode 100644
index 0000000..4113525
Binary files /dev/null and b/documentation/doctrees/tutorial.doctree differ
diff --git a/documentation/doctrees/upgrade.doctree b/documentation/doctrees/upgrade.doctree
new file mode 100644
index 0000000..4884623
Binary files /dev/null and b/documentation/doctrees/upgrade.doctree differ
diff --git a/documentation/doctrees/worked_examples.doctree b/documentation/doctrees/worked_examples.doctree
new file mode 100644
index 0000000..b308922
Binary files /dev/null and b/documentation/doctrees/worked_examples.doctree differ
diff --git a/documentation/doctrees/xsil2graphics2.doctree b/documentation/doctrees/xsil2graphics2.doctree
new file mode 100644
index 0000000..832a899
Binary files /dev/null and b/documentation/doctrees/xsil2graphics2.doctree differ
diff --git a/documentation/documentation_toc.html b/documentation/documentation_toc.html
new file mode 100644
index 0000000..8afb8b5
--- /dev/null
+++ b/documentation/documentation_toc.html
@@ -0,0 +1,164 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>Welcome to the documentation for XMDS2! — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="index.html" /> 
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+  <div class="section" id="welcome-to-the-documentation-for-xmds2">
+<span id="documentation"></span><h1>Welcome to the documentation for XMDS2!<a class="headerlink" href="#welcome-to-the-documentation-for-xmds2" title="Permalink to this headline">¶</a></h1>
+<div class="toctree-wrapper compound">
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a></li>
+<li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="installation.html#installers">Installers</a></li>
+<li class="toctree-l2"><a class="reference internal" href="installation.html#linux-installer-instructions">Linux installer instructions</a></li>
+<li class="toctree-l2"><a class="reference internal" href="installation.html#mac-os-x-installation">Mac OS X Installation</a></li>
+<li class="toctree-l2"><a class="reference internal" href="installation.html#manual-installation-from-source">Manual installation from source</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="tutorial.html">Quickstart Tutorial</a></li>
+<li class="toctree-l1"><a class="reference internal" href="worked_examples.html">Worked Examples</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="worked_examples.html#the-nonlinear-schrodinger-equation">The nonlinear Schrödinger equation</a></li>
+<li class="toctree-l2"><a class="reference internal" href="worked_examples.html#kubo-oscillator">Kubo Oscillator</a></li>
+<li class="toctree-l2"><a class="reference internal" href="worked_examples.html#fibre-noise">Fibre Noise</a></li>
+<li class="toctree-l2"><a class="reference internal" href="worked_examples.html#integer-dimensions">Integer Dimensions</a></li>
+<li class="toctree-l2"><a class="reference internal" href="worked_examples.html#wigner-function">Wigner Function</a></li>
+<li class="toctree-l2"><a class="reference internal" href="worked_examples.html#finding-the-ground-state-of-a-bec-continuous-renormalisation">Finding the Ground State of a BEC (continuous renormalisation)</a></li>
+<li class="toctree-l2"><a class="reference internal" href="worked_examples.html#finding-the-ground-state-of-a-bec-again">Finding the Ground State of a BEC again</a></li>
+<li class="toctree-l2"><a class="reference internal" href="worked_examples.html#multi-component-schrodinger-equation">Multi-component Schrödinger equation</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="reference_index.html">Reference section</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="reference_installation_and_configuration.html">Configuration, installation and runtime options</a></li>
+<li class="toctree-l2"><a class="reference internal" href="reference_usefulXMLSyntax.html">Useful XML Syntax</a></li>
+<li class="toctree-l2"><a class="reference internal" href="reference_schema.html">XMDS2 XML Schema</a></li>
+<li class="toctree-l2"><a class="reference internal" href="reference_elements.html">XMDS2 script elements</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="advanced_topics.html">Advanced Topics</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="advanced_topics.html#importing-data">Importing data</a></li>
+<li class="toctree-l2"><a class="reference internal" href="advanced_topics.html#convolutions-and-fourier-transforms">Convolutions and Fourier transforms</a></li>
+<li class="toctree-l2"><a class="reference internal" href="advanced_topics.html#loose-geometry-matching-mode">‘Loose’ <tt class="docutils literal"><span class="pre">geometry_matching_mode</span></tt></a></li>
+<li class="toctree-l2"><a class="reference internal" href="advanced_topics.html#dimension-aliases">Dimension aliases</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="faq.html">Frequently Asked Questions</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="faq.html#xmds-scripts-look-complicated-how-do-i-start">XMDS scripts look complicated! How do I start?</a></li>
+<li class="toctree-l2"><a class="reference internal" href="faq.html#where-can-i-get-help">Where can I get help?</a></li>
+<li class="toctree-l2"><a class="reference internal" href="faq.html#how-should-i-cite-xmds2">How should I cite XMDS2?</a></li>
+<li class="toctree-l2"><a class="reference internal" href="faq.html#i-think-i-found-a-bug-where-should-i-report-it">I think I found a bug! Where should I report it?</a></li>
+<li class="toctree-l2"><a class="reference internal" href="faq.html#how-do-i-put-time-dependence-into-my-vectors">How do I put time dependence into my vectors?</a></li>
+<li class="toctree-l2"><a class="reference internal" href="faq.html#can-i-specify-the-range-of-my-domain-and-number-of-grid-points-at-run-time">Can I specify the range of my domain and number of grid points at run-time?</a></li>
+<li class="toctree-l2"><a class="reference internal" href="faq.html#when-can-i-use-ip-operators-and-why-should-i-and-when-must-i-use-ex-operators">When can I use IP operators (and why should I) and when must I use EX operators?</a></li>
+<li class="toctree-l2"><a class="reference internal" href="faq.html#visual-editors">Visual Editors</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="upgrade.html">Upgrading From XMDS 1.X</a></li>
+<li class="toctree-l1"><a class="reference internal" href="optimisation_hints.html">Optimisation Hints</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="optimisation_hints.html#geometry-and-transform-based-tricks">Geometry and transform-based tricks</a></li>
+<li class="toctree-l2"><a class="reference internal" href="optimisation_hints.html#reduce-code-complexity">Reduce code complexity</a></li>
+<li class="toctree-l2"><a class="reference internal" href="optimisation_hints.html#compiler-and-library-tricks">Compiler and library tricks</a></li>
+<li class="toctree-l2"><a class="reference internal" href="optimisation_hints.html#atom-optics-specific-hints">Atom-optics-specific hints</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="xsil2graphics2.html">xsil2graphics2</a></li>
+<li class="toctree-l1"><a class="reference internal" href="developer.html">Developer Documentation</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="developer.html#test-scripts">Test scripts</a></li>
+<li class="toctree-l2"><a class="reference internal" href="developer.html#steps-to-update-xmds-script-validator-xml-schema">Steps to update <tt class="docutils literal"><span class="pre">XMDS</span></tt> script validator (XML schema)</a></li>
+<li class="toctree-l2"><a class="reference internal" href="developer.html#directory-layout">Directory layout</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="licensing.html">Licensing</a></li>
+<li class="toctree-l1"><a class="reference internal" href="news.html">News</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="news.html#xmds-2-1-4-well-if-this-isn-t-nice-i-don-t-know-what-is-september-27-2013">XMDS 2.1.4 “Well if this isn’t nice, I don’t know what is” (September 27, 2013)</a></li>
+<li class="toctree-l2"><a class="reference internal" href="news.html#xmds-2-1-3-happy-mollusc-june-7-2013">XMDS 2.1.3 “Happy Mollusc” (June 7, 2013)</a></li>
+<li class="toctree-l2"><a class="reference internal" href="news.html#xmds-2-1-2-happy-mollusc-october-15-2012">XMDS 2.1.2 “Happy Mollusc” (October 15, 2012)</a></li>
+<li class="toctree-l2"><a class="reference internal" href="news.html#xmds-2-1-happy-mollusc-june-14-2012">XMDS 2.1 “Happy Mollusc” (June 14, 2012)</a></li>
+<li class="toctree-l2"><a class="reference internal" href="news.html#xmds-2-0-shiny-september-13-2010">XMDS 2.0 “Shiny!” (September 13, 2010)</a></li>
+</ul>
+</li>
+</ul>
+</div>
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="index.html">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+<div id="searchbox" style="display: none">
+  <h3>Quick search</h3>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" />
+      <input type="submit" value="Go" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    <p class="searchtip" style="font-size: 90%">
+    Enter search terms or a module, class or function name.
+    </p>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/documentation/faq.html b/documentation/faq.html
new file mode 100644
index 0000000..927c875
--- /dev/null
+++ b/documentation/faq.html
@@ -0,0 +1,145 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>Frequently Asked Questions — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="index.html" /> 
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+  <div class="section" id="frequently-asked-questions">
+<span id="faq"></span><h1>Frequently Asked Questions<a class="headerlink" href="#frequently-asked-questions" title="Permalink to this headline">¶</a></h1>
+<div class="section" id="xmds-scripts-look-complicated-how-do-i-start">
+<h2>XMDS scripts look complicated! How do I start?<a class="headerlink" href="#xmds-scripts-look-complicated-how-do-i-start" title="Permalink to this headline">¶</a></h2>
+<p>If you’re unfamiliar with XMDS2, writing a script from scratch might seem difficult. In most cases, however, the best approach is to take an existing script and modify it for your needs. At the most basic level, you can simply take a script from the /examples directory that is similar to what you want to do, change the name of the integration variable(s) and replace the line describing the differential equation to use your DE instead. That’s all you need to do, and will en [...]
+<p>You can then incrementally change things such as the number of output points, what quantities get output, number of grid points, and so on. Many XMDS2 users have never written a script from scratch, and just use their previous scripts and example scripts as a scaffold when they create a script for a new problem.</p>
+</div>
+<div class="section" id="where-can-i-get-help">
+<h2>Where can I get help?<a class="headerlink" href="#where-can-i-get-help" title="Permalink to this headline">¶</a></h2>
+<p>The documentation on this website is currently incomplete, but it still covers a fair bit and is worth reading. Similarly, the example scripts in the /examples directory cover most of the functionality of XMDS2, so it’s worth looking looking through them to see if any of them do something similar to what you’re trying to do.</p>
+<p>You should also feel free to email questions to the XMDS users’ mailing list at <a class="reference external" href="mailto:xmds-users%40lists.sourceforge.net">xmds-users<span>@</span>lists<span>.</span>sourceforge<span>.</span>net</a>, where the developers and other users can assist you. You can join the mailing list by going to <a class="reference external" href="http://sourceforge.net/projects/xmds/">http://sourceforge.net/projects/xmds/</a> and [...]
+</div>
+<div class="section" id="how-should-i-cite-xmds2">
+<h2>How should I cite XMDS2?<a class="headerlink" href="#how-should-i-cite-xmds2" title="Permalink to this headline">¶</a></h2>
+<p>If you publish work that has involved XMDS2, please cite it as: <a class="reference external" href="http://dx.doi.org/10.1016/j.cpc.2012.08.016">Comput. Phys. Commun. 184, 201-208 (2013)</a>.</p>
+</div>
+<div class="section" id="i-think-i-found-a-bug-where-should-i-report-it">
+<h2>I think I found a bug! Where should I report it?<a class="headerlink" href="#i-think-i-found-a-bug-where-should-i-report-it" title="Permalink to this headline">¶</a></h2>
+<p>Please report bugs to the developer mailing list at <a class="reference external" href="mailto:xmds-devel%40lists.sourceforge.net">xmds-devel<span>@</span>lists<span>.</span>sourceforge<span>.</span>net</a>. In your email, please include a description of the problem and attach the XMDS2 script that triggers the bug.</p>
+</div>
+<div class="section" id="how-do-i-put-time-dependence-into-my-vectors">
+<h2>How do I put time dependence into my vectors?<a class="headerlink" href="#how-do-i-put-time-dependence-into-my-vectors" title="Permalink to this headline">¶</a></h2>
+<p>Standard vectors can’t have time dependence (or, more accurately, depend on the <tt class="docutils literal"><span class="pre">propagation_dimension</span></tt> variable), but computed vectors can. So, for example, if you have set your <tt class="docutils literal"><span class="pre">propagation_dimension</span></tt> as “t”, you can simply use the variable “t” in your computed vector and it will work.</p>
+<p>Alternatively, you can explicitly use the <tt class="docutils literal"><span class="pre">propagation_dimension</span></tt> variable in your differential equation inside the <tt class="docutils literal"><span class="pre"><operators></span></tt> block.</p>
+</div>
+<div class="section" id="can-i-specify-the-range-of-my-domain-and-number-of-grid-points-at-run-time">
+<h2>Can I specify the range of my domain and number of grid points at run-time?<a class="headerlink" href="#can-i-specify-the-range-of-my-domain-and-number-of-grid-points-at-run-time" title="Permalink to this headline">¶</a></h2>
+<p>Yes, you can. In your script, specify the domain and number of grid points as arguments to be passed in at run-time, use those variables in your <tt class="docutils literal"><span class="pre"><geometry></span></tt> block rather than explicitly specifying them, and use the <tt class="docutils literal"><span class="pre"><validation</span> <span class="pre">kind="run-time"</span> <span class="pre">/></span></tt> feature. See the <a class="reference internal" href="r [...]
+<p>While the domain can always be specified in this way, specifying the lattice size at run-time is currently only allowed with the following transforms: ‘dct’, ‘dst’, ‘dft’ and ‘none’ (see <a class="reference internal" href="reference_elements.html#validation"><em>Transforms</em></a> in the Reference section).</p>
+<p>Also note that for some multi-dimensional spaces using different transforms, XMDS2 will sometimes optimise the code it generates based on the relative sizes of the dimensions. If one or more of the lattices are specified at run-time it is unable to do this and will have to make guesses. In some situations this may result in slightly slower code.</p>
+</div>
+<div class="section" id="when-can-i-use-ip-operators-and-why-should-i-and-when-must-i-use-ex-operators">
+<h2>When can I use IP operators (and why should I) and when must I use EX operators?<a class="headerlink" href="#when-can-i-use-ip-operators-and-why-should-i-and-when-must-i-use-ex-operators" title="Permalink to this headline">¶</a></h2>
+<p>An <a class="reference internal" href="reference_elements.html#operatornameselement"><em><operator></em></a> that specifies named operators to be used in integration equations can have the <tt class="docutils literal"><span class="pre">kind="IP"</span></tt> or <tt class="docutils literal"><span class="pre">kind="EX"</span></tt> attribute, standing for ‘interaction picture’ and ‘explicit’ operators respectively.  Explicit operators can  [...]
+<p>Some explanation is in order.  The IP algorithm applies the operator separately to the rest of the evolution.  The reason this can be so effective is that the separate evolution can be performed exactly.  The solution of the equation <span class="math">\(\frac{d \psi}{dt} = L \psi\)</span> is <span class="math">\(\psi(t+\Delta t) = exp(L \Delta t) \psi(t)\)</span> for arbitrarily large timestep <span class="math">\(\Delta t\)</span>.  For a diagonal linear <tt class="docutils literal" [...]
+<p>Therefore, the limitations of IP operators themselves means that they can only be applied to to named components of one of the integration vectors, and not functions of those components.  Furthermore, an IP operator acting on a component must only be used in the derivative for that particular component.  Secondly, due to the implementation of IP operators in XMDS2, it is not safe to use them in comments, or in conjunction with declared variables.  It is also not safe to multiply or di [...]
+</div>
+<div class="section" id="visual-editors">
+<h2>Visual Editors<a class="headerlink" href="#visual-editors" title="Permalink to this headline">¶</a></h2>
+<p>In this section goes stuff about how to set up TextMate (or other editors to highlight xpdeint scripts).</p>
+</div>
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="index.html">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+  <h3><a href="index.html">Table Of Contents</a></h3>
+  <ul>
+<li><a class="reference internal" href="#">Frequently Asked Questions</a><ul>
+<li><a class="reference internal" href="#xmds-scripts-look-complicated-how-do-i-start">XMDS scripts look complicated! How do I start?</a></li>
+<li><a class="reference internal" href="#where-can-i-get-help">Where can I get help?</a></li>
+<li><a class="reference internal" href="#how-should-i-cite-xmds2">How should I cite XMDS2?</a></li>
+<li><a class="reference internal" href="#i-think-i-found-a-bug-where-should-i-report-it">I think I found a bug! Where should I report it?</a></li>
+<li><a class="reference internal" href="#how-do-i-put-time-dependence-into-my-vectors">How do I put time dependence into my vectors?</a></li>
+<li><a class="reference internal" href="#can-i-specify-the-range-of-my-domain-and-number-of-grid-points-at-run-time">Can I specify the range of my domain and number of grid points at run-time?</a></li>
+<li><a class="reference internal" href="#when-can-i-use-ip-operators-and-why-should-i-and-when-must-i-use-ex-operators">When can I use IP operators (and why should I) and when must I use EX operators?</a></li>
+<li><a class="reference internal" href="#visual-editors">Visual Editors</a></li>
+</ul>
+</li>
+</ul>
+
+<div id="searchbox" style="display: none">
+  <h3>Quick search</h3>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" />
+      <input type="submit" value="Go" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    <p class="searchtip" style="font-size: 90%">
+    Enter search terms or a module, class or function name.
+    </p>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/documentation/genindex.html b/documentation/genindex.html
new file mode 100644
index 0000000..d4bb2e7
--- /dev/null
+++ b/documentation/genindex.html
@@ -0,0 +1,95 @@
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>Index — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="index.html" /> 
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="#" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+
+<h1 id="index">Index</h1>
+
+<div class="genindex-jumpbox">
+ 
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="index.html">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+<div id="searchbox" style="display: none">
+  <h3>Quick search</h3>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" />
+      <input type="submit" value="Go" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    <p class="searchtip" style="font-size: 90%">
+    Enter search terms or a module, class or function name.
+    </p>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="#" title="General Index"
+             >index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/documentation/index.html b/documentation/index.html
new file mode 100644
index 0000000..afe0423
--- /dev/null
+++ b/documentation/index.html
@@ -0,0 +1,206 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>Welcome to XMDS2! — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="#" /> 
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="#">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+  <div class="section" id="welcome-to-xmds2">
+<h1>Welcome to XMDS2!<a class="headerlink" href="#welcome-to-xmds2" title="Permalink to this headline">¶</a></h1>
+<p>This website provides the documentation for XMDS2 (an all-new version of <a class="reference internal" href="introduction.html#xmdshistory"><em>XMDS</em></a>), a software package that allows the fast and easy solution of sets of ordinary, partial and stochastic differential equations, using a variety of efficient numerical algorithms.</p>
+<p>If you publish work that has involved XMDS2, please cite it as <a class="reference external" href="http://dx.doi.org/10.1016/j.cpc.2012.08.016">Comput. Phys. Commun. 184, 201-208 (2013)</a>.</p>
+<div class="section" id="getting-started">
+<h2>Getting Started<a class="headerlink" href="#getting-started" title="Permalink to this headline">¶</a></h2>
+<p>To get a flavour of what XMDS2 can do, take a look at our <a class="reference internal" href="tutorial.html#quickstarttutorial"><em>Quickstart Tutorial</em></a>, then take a look at our comprehensive  <a class="reference internal" href="documentation_toc.html#documentation"><em>documentation</em></a>.  Automated installers are available for Linux and Mac OS X, refer to our <a class="reference internal" href="installation.html#installation"><em>installation instructions</em></a> for de [...]
+</div>
+<div class="section" id="news">
+<span id="id1"></span><h2>News<a class="headerlink" href="#news" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="xmds-2-1-4-well-if-this-isn-t-nice-i-don-t-know-what-is-september-27-2013">
+<h3>XMDS 2.1.4 “Well if this isn’t nice, I don’t know what is” (September 27, 2013)<a class="headerlink" href="#xmds-2-1-4-well-if-this-isn-t-nice-i-don-t-know-what-is-september-27-2013" title="Permalink to this headline">¶</a></h3>
+<p>The XMDS 2.1.4 update contains many new improvements and bugfixes:</p>
+<ul class="simple">
+<li><em>xsil2graphics2</em> now supports all output formats for MATLAB, Octave and Python.  The scripts generated for MATLAB/Octave are compatible with both.</li>
+<li>Fix a bug when <a class="reference internal" href="reference_elements.html#referencingnonlocal"><em>nonlocally</em></a> referencing a <a class="reference internal" href="advanced_topics.html#dimensionaliases"><em>dimension alias</em></a> with subsampling in <em>sampling_group</em> blocks or in some situations when MPI is used.  This bug caused incorrect elements of the vector to be accessed.</li>
+<li>Correct the Fourier basis for dimensions using Hermite-Gauss transforms.  Previously ‘kx’ was effectively behaving as ‘-kx’.</li>
+<li>Improve the performance of ‘nx’ <–> ‘kx’ Hermite-Gauss transforms.</li>
+<li>Stochastic error checking with runtime noise generation now works correctly.  Previously different random numbers were generated for the full-step paths and the half-step paths.</li>
+<li>Documentation updates.</li>
+</ul>
+</div>
+<div class="section" id="xmds-2-1-3-happy-mollusc-june-7-2013">
+<h3>XMDS 2.1.3 “Happy Mollusc” (June 7, 2013)<a class="headerlink" href="#xmds-2-1-3-happy-mollusc-june-7-2013" title="Permalink to this headline">¶</a></h3>
+<p>The XMDS 2.1.3 update is a bugfix release that includes the following improvements:</p>
+<ul class="simple">
+<li>XMDS will work when MPI isn’t installed (but only for single-process simulations).</li>
+<li>Support for GCC 4.8</li>
+<li>The number of paths used by the multi-path driver can now be specified at run-time (using <em><validation kind=”run-time”></em>)</li>
+<li>Other bug fixes</li>
+</ul>
+</div>
+<div class="section" id="xmds-2-1-2-happy-mollusc-october-15-2012">
+<h3>XMDS 2.1.2 “Happy Mollusc” (October 15, 2012)<a class="headerlink" href="#xmds-2-1-2-happy-mollusc-october-15-2012" title="Permalink to this headline">¶</a></h3>
+<p>The XMDS 2.1.2 update has many improvements:</p>
+<ul class="simple">
+<li>Named filters.  You can now specify a name for a filter block and call it like a function if you need to execute it conditionally.  See the documentation for the <em><filter></em> block for more information.</li>
+<li>New <em>chunked_output</em> feature.  XMDS can now output simulation results as it goes, reducing the memory requirement for simulations that generate significant amounts of output.  See the documentation for more details.</li>
+<li>Improved OpenMP support</li>
+<li>The EX operator is now faster in the common case (but you should still prefer IP when possible)</li>
+<li>If seeds are not provided for a <em>noise_vector</em>, they are now generated at simulation run-time, so different executions will give different results.  The generated noises can still be found in the output .xsil files enabling results to be reproduced if desired.</li>
+<li>Advanced feature: Dimensions can be accessed non-locally with the index of the lattice point.  This removes the need in hacks to manually access XMDS’s underlying C arrays.  This is an advanced feature and requires a little knowledge of XMDS’s internal grid representation.  See the advanced topics documentation for further details.</li>
+<li>Fixed adaptive integrator order when noises were used in vector initialisation</li>
+<li>Fix the Spherical Bessel basis.  There were errors in the definition of this basis which made it previously unreliable.</li>
+<li>Other bug fixes</li>
+</ul>
+</div>
+<div class="section" id="xmds-2-1-happy-mollusc-june-14-2012">
+<h3>XMDS 2.1 “Happy Mollusc” (June 14, 2012)<a class="headerlink" href="#xmds-2-1-happy-mollusc-june-14-2012" title="Permalink to this headline">¶</a></h3>
+<p>XMDS 2.1 is a significant upgrade with many improvements and bug fixes since 2.0. We also now have installers for Linux and Mac OS X, so you no longer have to build XMDS from source! See <a class="reference internal" href="installation.html#installation"><em>here</em></a> for details about the installers.</p>
+<p>Existing users should note that this release introduces a more concise syntax for moment groups.  You can now use:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><sampling_group</span> <span class="na">initial_sample=</span><span class="s">"yes"</span> <span class="na">basis=</span><span class="s">"x y z"</span><span class="nt">></span>
+    ...
+<span class="nt"></sampling_group></span>
+</pre></div>
+</div>
+<p>Instead of:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><group></span>
+    <span class="nt"><sampling</span> <span class="na">initial_sample=</span><span class="s">"yes"</span> <span class="na">basis=</span><span class="s">"x y z"</span><span class="nt">></span>
+        ...
+    <span class="nt"></sampling></span>
+<span class="nt"></group></span>
+</pre></div>
+</div>
+<p>Another syntax change is that the initial basis of a vector should be specified with <em>initial_basis</em> instead of <em>initial_space</em>.</p>
+<p>In both cases, although the old syntax is not described in the documentation, it is still supported, so existing scripts will work without any changes.</p>
+<p>Other changes in XMDS 2.1 include:</p>
+<ul class="simple">
+<li>The <em>lattice</em> attribute for dimensions can now be specified at run-time.  Previously only the minimum and maximum values of the domain could be specified at run-time.  See <a class="reference internal" href="reference_elements.html#validation"><em>here</em></a> for details.</li>
+<li><em>noise_vectors</em> can now be used in non-uniform dimensions (e.g. dimensions using the Bessel transform for cylindrical symmetry).</li>
+<li>“loose” <em>geometry_matching_mode</em> for HDF5 vector initialisation.  This enables extending the simulation grid from one simulation to the next, or coarsening or refining a grid when importing.</li>
+<li><em>vectors</em> can now be initialised by integrating over dimensions of other vectors.  <em>computed_vectors</em> always supported this, now <em>vectors</em> do too.</li>
+<li>Update to latest version of waf, which is used for compiling simulations and detecting FFTW, HDF5, etc. This should lead to fewer waf-related problems.</li>
+<li>Bug fixes.</li>
+</ul>
+</div>
+<div class="section" id="xmds-2-0-shiny-september-13-2010">
+<h3>XMDS 2.0 “Shiny!” (September 13, 2010)<a class="headerlink" href="#xmds-2-0-shiny-september-13-2010" title="Permalink to this headline">¶</a></h3>
+<p>XMDS 2.0 is a major upgrade which has been rewritten from the ground up to make it easier for us to apply new features. And there are many. XMDS 2.0 is faster and far more versatile than previous versions, allowing the efficient integration of almost any initial value problem on regular domains.</p>
+<p>The feature list includes:</p>
+<ul class="simple">
+<li>Quantities of different dimensionalities. So you can have a 1D potential and a 3D wavefunction.</li>
+<li>Integrate more than one vector (in more than one geometry), so you can now simultaneously integrate a PDE and a coupled ODE (or coupled PDEs of different dimensions).</li>
+<li>Non-Fourier transformations including the Bessel basis, Spherical Bessel basis and the Hermite-Gauss (harmonic oscillator) basis.</li>
+<li>The ability to have more than one kind of noise (gaussian, poissonian, etc) in a simulation.</li>
+<li>Integer-valued dimensions with non-local access. You can have an array of variables and access different elements of that array.</li>
+<li>Significantly better error reporting. When errors are found when compiling the script they will almost always be reported with the corresponding line of your script, instead of the generated source.</li>
+<li><em>IP</em>/<em>EX</em> operators are separate from the integration algorithm, so you can have both <em>IP</em> and <em>EX</em> operators in a single integrate block. Also, <em>EX</em> operators can act on arbitrary code, not just vector components. (e.g. <em>L[phi*phi]</em>).</li>
+<li>Cross propagation in the increasing direction of a given dimension or in the decreasing dimension. And you can have more than one cross-propagator in a given integrator (going in different directions or dimensions).</li>
+<li>Faster Gaussian noises.</li>
+<li>The ability to calculate spatial correlation functions.</li>
+<li>OpenMP support.</li>
+<li>MPI support.</li>
+<li>Output moment groups use less memory when there isn’t a <em>post_processing</em> element.</li>
+<li>Generated source is indented correctly.</li>
+<li>An <em>xmds1</em>-like script file format.</li>
+<li><em>xmds1</em>-like generated source.</li>
+<li>All of the integrators from <em>xmds1</em> (<em>SI</em>, <em>RK4</em>, <em>ARK45</em>, <em>RK9</em>, <em>ARK89</em>).</li>
+</ul>
+</div>
+</div>
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="#">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+  <h3><a href="#">Table Of Contents</a></h3>
+  <ul>
+<li><a class="reference internal" href="#">Welcome to XMDS2!</a><ul>
+<li><a class="reference internal" href="#getting-started">Getting Started</a></li>
+<li><a class="reference internal" href="#news">News</a><ul>
+<li><a class="reference internal" href="#xmds-2-1-4-well-if-this-isn-t-nice-i-don-t-know-what-is-september-27-2013">XMDS 2.1.4 “Well if this isn’t nice, I don’t know what is” (September 27, 2013)</a></li>
+<li><a class="reference internal" href="#xmds-2-1-3-happy-mollusc-june-7-2013">XMDS 2.1.3 “Happy Mollusc” (June 7, 2013)</a></li>
+<li><a class="reference internal" href="#xmds-2-1-2-happy-mollusc-october-15-2012">XMDS 2.1.2 “Happy Mollusc” (October 15, 2012)</a></li>
+<li><a class="reference internal" href="#xmds-2-1-happy-mollusc-june-14-2012">XMDS 2.1 “Happy Mollusc” (June 14, 2012)</a></li>
+<li><a class="reference internal" href="#xmds-2-0-shiny-september-13-2010">XMDS 2.0 “Shiny!” (September 13, 2010)</a></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+
+<div id="searchbox" style="display: none">
+  <h3>Quick search</h3>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" />
+      <input type="submit" value="Go" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    <p class="searchtip" style="font-size: 90%">
+    Enter search terms or a module, class or function name.
+    </p>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li><a href="#">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/documentation/installation.html b/documentation/installation.html
new file mode 100644
index 0000000..041b744
--- /dev/null
+++ b/documentation/installation.html
@@ -0,0 +1,370 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>Installation — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="index.html" /> 
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+  <div class="section" id="installation">
+<span id="id1"></span><h1>Installation<a class="headerlink" href="#installation" title="Permalink to this headline">¶</a></h1>
+<p><strong>XMDS2</strong> can be installed on any unix-like system including Linux, Tru64, and Mac OS X.  It requires a C++ compiler, python, and several installed packages.  Many of these packages are optional, but a good idea to obtain full functionality.</p>
+<div class="section" id="installers">
+<h2>Installers<a class="headerlink" href="#installers" title="Permalink to this headline">¶</a></h2>
+<p>The easiest way to get started is with an installer.  If we don’t have an installer for your system, follow the <a class="reference internal" href="#manualinstallation"><em>manual installation</em></a> instructions.</p>
+<table border="1" class="docutils">
+<colgroup>
+<col width="60%" />
+<col width="20%" />
+<col width="20%" />
+</colgroup>
+<tbody valign="top">
+<tr class="row-odd"><td>Linux (Ubuntu/Debian/Fedora/RedHat)</td>
+<td><a class="reference external" href="http://svn.code.sf.net/p/xmds/code/trunk/xpdeint/admin/linux_installer.sh">Download Linux Installer</a></td>
+<td><a class="reference internal" href="#linux-installation"><em>Learn more</em></a></td>
+</tr>
+<tr class="row-even"><td>OS X 10.6/10.7</td>
+<td><a class="reference external" href="http://sourceforge.net/projects/xmds/files">Download OS X Installer</a></td>
+<td><a class="reference internal" href="#mac-installation"><em>Learn more</em></a></td>
+</tr>
+<tr class="row-odd"><td>Other systems</td>
+<td><a class="reference internal" href="#manualinstallation"><em>Install from source</em></a></td>
+<td> </td>
+</tr>
+</tbody>
+</table>
+<p>If you have one of the supported operating systems listed above, but you find the installer doesn’t work for you, please let us know by emailing xmds-devel <at> lists.sourceforge.net. If you’d like to tweak the linux installer to work on a distribution we haven’t tested, we’d love you to do that and let us know!</p>
+</div>
+<div class="section" id="linux-installer-instructions">
+<span id="linux-installation"></span><h2>Linux installer instructions<a class="headerlink" href="#linux-installer-instructions" title="Permalink to this headline">¶</a></h2>
+<p>The linux installer has currently only been tested with Ubuntu, Debian, Fedora, and Red Hat. Download the installer here: <a class="reference external" href="http://svn.code.sf.net/p/xmds/code/trunk/xpdeint/admin/linux_installer.sh">http://svn.code.sf.net/p/xmds/code/trunk/xpdeint/admin/linux_installer.sh</a></p>
+<p>Once you have downloaded it, make the installer executable and run it by typing the following into a terminal:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre>chmod u+x linux_installer.sh
+./linux_installer.sh
+</pre></div>
+</div>
+<p>Alternatively, if you wish to download and run the installer in a single step, you can use the following command:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre>/bin/bash -c "$(wget -qO - http://svn.code.sf.net/p/xmds/code/trunk/xpdeint/admin/linux_installer.sh)"
+</pre></div>
+</div>
+<p>The linux installer installs all XMDS2 dependencies from your native package manager where possible (<tt class="docutils literal"><span class="pre">apt-get</span></tt> for Ubuntu/Debian, <tt class="docutils literal"><span class="pre">yum</span></tt> for Fedora/Red Hat) but will download and compile the source code for libraries not available through the package manager. This means you’ll need to be connected to the internet when running the installer. The installer should not be [...]
+<p>For instructions on how to install XMDS2 on systems where you lack administrative rights, see <a class="reference internal" href="#manualinstallation"><em>Manual installation from source</em></a>.</p>
+<p>By default, this installer will install a known stable version of XMDS, which can be updated at any time by navigating to the XMDS directory and typing ‘make update’. To install the latest developer version at the beginning, simply run the installer with the <tt class="docutils literal"><span class="pre">--develop</span></tt> option.</p>
+<p>Once XMDS2 has been installed, you can run it from the terminal by typing <tt class="docutils literal"><span class="pre">xmds2</span></tt>. See the <a class="reference internal" href="tutorial.html#quickstarttutorial"><em>Quickstart Tutorial</em></a> for next steps.</p>
+</div>
+<div class="section" id="mac-os-x-installation">
+<span id="mac-installation"></span><h2>Mac OS X Installation<a class="headerlink" href="#mac-os-x-installation" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="download">
+<h3>Download<a class="headerlink" href="#download" title="Permalink to this headline">¶</a></h3>
+<p>Mac OS X 10.6 (Snow Leopard) or later XMDS 2 installer: <a class="reference external" href="http://sourceforge.net/projects/xmds/files/">http://sourceforge.net/projects/xmds/files/</a></p>
+</div>
+<div class="section" id="using-the-mac-os-x-installer">
+<h3>Using the Mac OS X Installer<a class="headerlink" href="#using-the-mac-os-x-installer" title="Permalink to this headline">¶</a></h3>
+<p>A self-contained installer for Mac OS X 10.6 (Snow Leopard) and later is available from the link above. This installer is only compatible with Intel Macs.  This means that the older PowerPC architecture is <em>not supported</em>.  Xcode (Apple’s developer tools) is required to use this installer. Xcode is available for free from the Mac App Store for 10.7 or later, and is available on the install disk of earlier Macs as an optional install.  For users of earlier operating system [...]
+<p>Once you have downloaded the XMDS installer, installation is as simple as dragging it to your Applications folder or any other location.  Click the XMDS application to launch it, and press the “Launch XMDS Terminal” button to open a Terminal window customised to work with XMDS.  The first time you do this, the application will complete the installation process.  This process can take a few minutes, but is only performed once.</p>
+<p>The terminal window launched by the XMDS application has environment variables set for using this installation of XMDS.  You can run XMDS in this terminal by typing <tt class="docutils literal"><span class="pre">xmds2</span></tt>.  See the <a class="reference internal" href="tutorial.html#quickstarttutorial"><em>Quickstart Tutorial</em></a> for next steps.</p>
+<p>To uninstall XMDS, drag the XMDS application to the trash. XMDS places some files in the directory <tt class="docutils literal"><span class="pre">~/Library/XMDS</span></tt>. Remove this directory to completely remove XMDS from your system.</p>
+<p>This package includes binaries for <a class="reference external" href="http://www.open-mpi.org">OpenMPI</a>, <a class="reference external" href="http://www.fftw.org">FFTW</a>, <a class="reference external" href="http://www.hdfgroup.org/HDF5">HDF5</a> and <a class="reference external" href="http://www.gnu.org/software/gsl">GSL</a>. These binaries are self-contained and do not overwrite any existing installations.</p>
+</div>
+</div>
+<div class="section" id="manual-installation-from-source">
+<span id="manualinstallation"></span><h2>Manual installation from source<a class="headerlink" href="#manual-installation-from-source" title="Permalink to this headline">¶</a></h2>
+<p>This installation guide will take you through a typical full install step by step. A large part of this procedure is obtaining and installing other libraries that XMDS2 requires, before installing XMDS2 itself.</p>
+<p>While the instructions below detail these packages individually, if you have administrative privileges (or can request packages from your administrator) and if you are using an Ubuntu, Debian, Fedora or Red Hat linux distribution, you can install all required and optional dependencies (but not XMDS2 itself) via</p>
+<p>Ubuntu / Debian:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre>sudo apt-get install build-essential subversion libopenmpi-dev openmpi-bin python-dev python-setuptools python-cheetah python-numpy python-pyparsing python-lxml python-mpmath libhdf5-serial-dev libgsl0-dev python-sphinx python-h5py libatlas-base-dev
+</pre></div>
+</div>
+<p>Fedora / Red Hat:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre>sudo yum install gcc gcc-c++ make automake subversion openmpi-devel python-devel python-setuptools python-cheetah numpy gsl-devel python-sphinx libxml2-devel libxslt-devel atlas-devel hdf5-devel pyparsing pyparsing python-lxml python-mpmath h5py
+</pre></div>
+</div>
+<p>You will still have to download and build FFTW 3.3 from source (see below) since prebuilt packages with MPI and AVX support are not currently available in the repositories.</p>
+<p>Also note that this guide adds extra notes for users wishing to install XMDS2 using the SVN repository.  This requires a few extra steps, but allows you to edit your copy, and/or update your copy very efficiently (with all the usual advantages and disadvantages of using unreleased material).</p>
+<ol class="arabic" start="0">
+<li><dl class="first docutils">
+<dt>You will need a copy of XMDS2.</dt>
+<dd><p class="first">The current release can be found at <a class="reference external" href="http://sourceforge.net/projects/xmds/">Sourceforge</a>, and downloaded as a single file.
+Download this file, and expand it in a directory where you want to keep the program files.</p>
+<ul class="last">
+<li><p class="first">Developer-only instructions: You can instead check out a working copy of the source using SVN.
+In a directory where you want to check out the repository, run:
+<tt class="docutils literal"><span class="pre">svn</span> <span class="pre">checkout</span> <span class="pre">https://svn.code.sf.net/p/xmds/code/trunk/xpdeint</span> <span class="pre">.</span></tt></p>
+<p>(Only do this once.  To update your copy, type <tt class="docutils literal"><span class="pre">svn</span> <span class="pre">up</span></tt> or <tt class="docutils literal"><span class="pre">make</span> <span class="pre">update</span></tt> in the same directory, and then repeat any developer-only instructions below).</p>
+</li>
+</ul>
+</dd>
+</dl>
+</li>
+<li><dl class="first docutils">
+<dt>You will need a working C++ compiler.</dt>
+<dd><p class="first last">For Mac OS X, this means that the developer tools (XCode) should be installed.
+One common free compiler is <a class="reference external" href="http://gcc.gnu.org/">gcc</a>.  It can be downloaded using your favourite package manager.
+XMDS2 can also use Intel’s C++ compiler if you have it.
+Intel’s compiler typically generates faster code than gcc, but it isn’t free.</p>
+</dd>
+</dl>
+</li>
+<li><p class="first">You will need a <a class="reference external" href="http://www.python.org/">python distribution</a>.</p>
+<ul class="simple">
+<li>Mac OS X: It is pre-installed on Mac OS X 10.5 or later.</li>
+<li>Linux: It should be pre-installed. If not, install using your favourite package manager.</li>
+</ul>
+<blockquote>
+<div><p>We require python 2.4 or greater. XMDS2 does not support Python 3.</p>
+</div></blockquote>
+</li>
+<li><dl class="first docutils">
+<dt>Install setuptools.</dt>
+<dd><p class="first">If you have root (sudo) access, the easy way to install this is by executing
+ez_setup.py from the repository. Simply type <tt class="docutils literal"><span class="pre">sudo</span> <span class="pre">python</span> <span class="pre">ez_setup.py</span></tt></p>
+<blockquote>
+<div><p>If you want to install into your home directory without root access, this is more complex:</p>
+<ol class="loweralpha simple">
+<li>First create the path ~/lib/python2.5/site-packages (assuming you installed python version 2.5) and ~/bin
+Add “export PYTHONPATH=~/lib/python2.5/site-packages:$PYTHONPATH” and “export PATH=~/bin:$PATH” (if necessary)
+to your .bashrc file (and run ”. ~/.bashrc”)</li>
+<li>If necessary install setuptools, by executing ez_setup.py from the repository.
+<tt class="docutils literal"><span class="pre">python</span> <span class="pre">ez_setup.py</span> <span class="pre">--prefix=~</span></tt></li>
+</ol>
+</div></blockquote>
+<p class="last">If you use Mac OS X 10.5 or later, or installed the Enthought Python Distribution on Windows, then setuptools is already installed.
+Though if the next step fails, you may need to upgrade setuptools.  To do that, type <tt class="docutils literal"><span class="pre">sudo</span> <span class="pre">easy_install</span> <span class="pre">-U</span> <span class="pre">setuptools</span></tt></p>
+</dd>
+</dl>
+</li>
+<li><dl class="first docutils">
+<dt>Install HDF5 and FFTW3 (and optionally MPI).</dt>
+<dd><ol class="first last arabic" id="hdf5-installation">
+<li><dl class="first docutils">
+<dt><strong>HDF5</strong> is a library for reading and writing the <a class="reference external" href="http://www.hdfgroup.org/HDF5/">Hierarchical Data Format</a>.</dt>
+<dd><p class="first">This is a standardised data format which it is suggested that people use in preference to the older ‘binary’ output (which is
+compatible with xmds-1). The advantage of HDF5 is that this data format is understood by a variety of other tools. xsil2graphics2
+provides support for loading data created in this format into Mathematica and Matlab.</p>
+<p>XMDS2 only requires the single process version of HDF5, so there is no need to install the MPI version.</p>
+<p>* Sidebar: Installing HDF5 from source follows a common pattern, which you may find yourself repeating later:</p>
+<blockquote class="last">
+<div><ol class="arabic">
+<li><p class="first">After extracting the source directory, type <tt class="docutils literal"><span class="pre">configure</span></tt> and then add possible options.</p>
+<blockquote>
+<div><p>(For HDF5, install with the <tt class="docutils literal"><span class="pre">--prefix=/usr/local/</span></tt> option if you want XMDS2 to find the library automatically.  This is rarely needed for other packages.)</p>
+</div></blockquote>
+</li>
+<li><p class="first">Once that is finished, type <tt class="docutils literal"><span class="pre">make</span></tt>.  Then wait for that to finish, which will often be longer than you think.</p>
+</li>
+<li><p class="first">Finally, type <tt class="docutils literal"><span class="pre">sudo</span> <span class="pre">make</span> <span class="pre">install</span></tt> to install it into the appropriate directory.</p>
+</li>
+</ol>
+</div></blockquote>
+</dd>
+</dl>
+</li>
+<li><dl class="first docutils">
+<dt><strong>FFTW</strong> is the library XMDS2 uses for Fourier transforms.</dt>
+<dd><p class="first">This is the transform most people will use in their simulations. If you need
+support for MPI distributed simulations, you must configure FFTW to use MPI.</p>
+<p class="last">FFTW is available for free at the <a class="reference external" href="http://www.fftw.org/">FFTW website</a>.
+To configure and compile it, follow the steps described in the HDF5 sidebar above.
+You may wish to add the <tt class="docutils literal"><span class="pre">--enable-mpi</span> <span class="pre">--disable-fortran</span></tt> options to the <tt class="docutils literal"><span class="pre">configure</span></tt> command.</p>
+</dd>
+</dl>
+</li>
+<li><dl class="first docutils">
+<dt><strong>MPI</strong> is an API for doing parallel processing.</dt>
+<dd><p class="first">XMDS2 can use MPI to parallelise simulations on multi-processor/multi-core computers, or clusters of computers.
+Many supercomputing systems come with MPI libraries pre-installed.
+The <a class="reference external" href="http://www.open-mpi.org/">Open MPI</a> project has free distributions of this library available.</p>
+<p class="last">If you intend to take advantage of XMDS2’s multi-processing features, you must install MPI, and configure FFTW3 to use it.</p>
+</dd>
+</dl>
+</li>
+</ol>
+</dd>
+</dl>
+</li>
+<li><p class="first">There are a range of optional installs.  We recommend that you install them all if possible:</p>
+<blockquote>
+<div><ol class="arabic">
+<li><dl class="first docutils">
+<dt>A Matrix library like <a class="reference external" href="http://math-atlas.sourceforge.net/">ATLAS</a>, Intel’s <a class="reference external" href="http://software.intel.com/en-us/intel-mkl/">MKL</a> or the <a class="reference external" href="http://www.gnu.org/software/gsl/">GNU Scientific library (GSL)</a></dt>
+<dd><p class="first last">These libraries allow efficient implementation of transform spaces other than Fourier space.
+Mac OS X comes with its own (fast) matrix library.</p>
+</dd>
+</dl>
+</li>
+<li><dl class="first docutils">
+<dt><strong>numpy</strong> is a tool that XMDS2 uses for automated testing.</dt>
+<dd><p class="first">It can be installed with <tt class="docutils literal"><span class="pre">sudo</span> <span class="pre">easy_install</span> <span class="pre">numpy</span></tt>.</p>
+<p class="last">Mac OS X 10.5 and later come with numpy.</p>
+</dd>
+</dl>
+</li>
+<li><dl class="first docutils">
+<dt><strong>lxml</strong> is used to validate the syntax of scripts passed to XMDS2.</dt>
+<dd><p class="first">If you have root access, this can be installed with the command <tt class="docutils literal"><span class="pre">sudo</span> <span class="pre">easy_install</span> <span class="pre">lxml</span></tt></p>
+<p>You will need to have ‘libxml2’ and ‘libxslt’ installed (via your choice of package manager) to install lxml.
+Sufficient versions are preinstalled on Mac OS X 10.6.</p>
+<dl class="last docutils">
+<dt>If you don’t have root access or want to install into your home directory, use:</dt>
+<dd><p class="first last"><tt class="docutils literal"><span class="pre">easy_install</span> <span class="pre">--prefix=~</span> <span class="pre">lxml</span></tt></p>
+</dd>
+</dl>
+</dd>
+</dl>
+</li>
+<li><dl class="first docutils">
+<dt><strong>h5py</strong> is needed for checking the results of XMDS2 tests that generate HDF5 output.</dt>
+<dd><p class="first">h5py requires numpy version 1.0.3 or later.</p>
+<p class="last">Upgrading <a class="reference external" href="http://h5py.alfven.org/">h5py</a> on Mac OS X is best done with the source of the package, as the easy_install option can get confused with multiple numpy versions.
+(Mac OS X Snow Leopard comes with version 1.2.1).
+After downloading the source, execute <tt class="docutils literal"><span class="pre">python</span> <span class="pre">./setup.py</span> <span class="pre">build</span></tt> in the source directory, and then <tt class="docutils literal"><span class="pre">python</span> <span class="pre">./setup.py</span> <span class="pre">install</span></tt> to install it.</p>
+</dd>
+</dl>
+</li>
+</ol>
+</div></blockquote>
+</li>
+<li><dl class="first docutils">
+<dt>Install XMDS2 into your python path by running (in the xmds-2.1.4/ directory):</dt>
+<dd><p class="first"><tt class="docutils literal"><span class="pre">sudo</span> <span class="pre">./setup.py</span> <span class="pre">develop</span></tt></p>
+<p>If you want to install it into your home directory, type <tt class="docutils literal"><span class="pre">./setup.py</span> <span class="pre">develop</span> <span class="pre">--prefix=~</span></tt></p>
+<p>This step requires access to the net, as it downloads any dependent packages.  If you are behind a firewall, you may need to set your HTTP_PROXY environment variable in order to do this.</p>
+<ul class="last">
+<li><dl class="first docutils">
+<dt>Developer only instructions:</dt>
+<dd><p class="first last">The Cheetah templates (*.tmpl) must be compiled into python.
+To do this, run <tt class="docutils literal"><span class="pre">make</span></tt> in the xmds-2.1.4/ directory.</p>
+</dd>
+</dl>
+</li>
+<li><dl class="first docutils">
+<dt>Developer-only instructions:</dt>
+<dd><p class="first last">If you have ‘numpy’ installed, test XMDS2 by typing <tt class="docutils literal"><span class="pre">./run_tests.py</span></tt> in the xmds-2.1.4/ directory.
+The package ‘numpy’ is one of the optional packages, with installation instructions below.</p>
+</dd>
+</dl>
+</li>
+<li><dl class="first docutils">
+<dt>Developer-only instructions:</dt>
+<dd><p class="first">To build the user documentation, you first need to install sphinx, either via your package manager or:
+<tt class="docutils literal"><span class="pre">sudo</span> <span class="pre">easy_install</span> <span class="pre">Sphinx</span></tt></p>
+<p>Then, to build the documentation, in the xmds-2.1.4/admin/userdoc-source/ directory run: <tt class="docutils literal"><span class="pre">make</span> <span class="pre">html</span></tt></p>
+<p>If this results in an error, you may need to run <tt class="docutils literal"><span class="pre">sudo</span> <span class="pre">./setup.py</span> <span class="pre">develop</span></tt></p>
+<p class="last">The generated html documentation will then be found at xmds-2.1.4/documentation/index.html</p>
+</dd>
+</dl>
+</li>
+</ul>
+</dd>
+</dl>
+</li>
+<li><p class="first">Configure XMDS2 by typing <tt class="docutils literal"><span class="pre">xmds2</span> <span class="pre">--reconfigure</span></tt>.  If XMDS2 is unable to find a library, you can tell XMDS2 where these libraries are located by adding <tt class="docutils literal"><span class="pre">include</span></tt> and <tt class="docutils literal"><span class="pre">lib</span></tt> search paths using the <tt class="docutils literal"><span class="pre">--include-path</span></tt> and <tt [...]
+<blockquote>
+<div><ul class="simple">
+<li><tt class="docutils literal"><span class="pre">xmds2</span> <span class="pre">--reconfigure</span> <span class="pre">--include-path</span> <span class="pre">/apps/fftw3/include</span> <span class="pre">--lib-path</span> <span class="pre">/apps/fftw3/lib</span></tt>.</li>
+</ul>
+<p>If you need to use additional compiler or link flags for XMDS2 to use certain libraries, set the <tt class="docutils literal"><span class="pre">CXXFLAGS</span></tt> or <tt class="docutils literal"><span class="pre">LINKFLAGS</span></tt> environment variables before calling <tt class="docutils literal"><span class="pre">xmds2</span> <span class="pre">--reconfigure</span></tt>.  For example, to pass the compiler flag <tt class="docutils literal"><span class="pre">-pedantic</span></tt> a [...]
+<ul class="simple">
+<li><tt class="docutils literal"><span class="pre">CXXFLAGS="-pedantic"</span> <span class="pre">LINKFLAGS="-lm"</span> <span class="pre">xmds2</span> <span class="pre">--reconfigure</span></tt>.</li>
+</ul>
+</div></blockquote>
+</li>
+</ol>
+<p><strong>Congratulations!</strong> You should now have a fully operational copy of xmds2 and xsil2graphics2.  You can test your copy using examples from the “xmds-2.1.4/examples” directory, and follow the worked examples in the <a class="reference internal" href="tutorial.html#quickstarttutorial"><em>Quickstart Tutorial</em></a> and <a class="reference internal" href="worked_examples.html#workedexamples"><em>Worked Examples</em></a>.</p>
+</div>
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="index.html">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+  <h3><a href="index.html">Table Of Contents</a></h3>
+  <ul>
+<li><a class="reference internal" href="#">Installation</a><ul>
+<li><a class="reference internal" href="#installers">Installers</a></li>
+<li><a class="reference internal" href="#linux-installer-instructions">Linux installer instructions</a></li>
+<li><a class="reference internal" href="#mac-os-x-installation">Mac OS X Installation</a><ul>
+<li><a class="reference internal" href="#download">Download</a></li>
+<li><a class="reference internal" href="#using-the-mac-os-x-installer">Using the Mac OS X Installer</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#manual-installation-from-source">Manual installation from source</a></li>
+</ul>
+</li>
+</ul>
+
+<div id="searchbox" style="display: none">
+  <h3>Quick search</h3>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" />
+      <input type="submit" value="Go" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    <p class="searchtip" style="font-size: 90%">
+    Enter search terms or a module, class or function name.
+    </p>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/documentation/introduction.html b/documentation/introduction.html
new file mode 100644
index 0000000..0f602ee
--- /dev/null
+++ b/documentation/introduction.html
@@ -0,0 +1,114 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>Introduction — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="index.html" /> 
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+  <div class="section" id="introduction">
+<h1>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline">¶</a></h1>
+<p>Welcome to <strong>XMDS2</strong> (codenamed <cite>xpdeint</cite>), which is an all-new version of <a class="reference internal" href="#xmdshistory"><em>XMDS</em></a>.  Prepare for fast, easily-extended simulations with minimal code error.</p>
+<p><strong>Description:</strong>   The purpose of XMDS2 is to simplify the process of creating simulations that solve systems of initial-value first-order partial and ordinary differential equations. Instead of going through the error-prone process of writing by hand thousands of lines of code, XMDS2 enables many problems to be described in a simple XML format. From this XML description XMDS2 writes a C++ simulation that solves the problem using fast algorithms. Anecdotally, the code gen [...]
+<p>XMDS2 can be used to simulate almost any set of (coupled) (partial) (stochastic) differential equations in any number of dimensions.  It can input and output data in a range of data formats, produce programs that can take command-line arguments, and produce parallelised code suitable for either modern computer architectures or distributed clusters.</p>
+<p>If this is your first time with XMDS, then an ideal place to start is the <a class="reference internal" href="tutorial.html#quickstarttutorial"><em>Quickstart Tutorial</em></a>, where we will show you how to write a basic simulation.  <a class="reference internal" href="installation.html#installation"><em>Installation</em></a> instructions should get you up and running and able to start playing with the large library of examples provided. The impatient will probably have good luck bro [...]
+<p>If you are upgrading from <strong>XMDS version 1.x</strong>, then after following the installation instructions (<a class="reference internal" href="installation.html#installation"><em>Installation</em></a>), you might want to have a quick read of the note for upgraders (<a class="reference internal" href="upgrade.html#upgradefromxmds1"><em>Upgrading From XMDS 1.X</em></a>).  The syntax of the XML scripts has changed, but hopefully you will find the new scripts very intuitive.</p>
+<p>Detailed advice on input/output issues, and ways to code more complicated simulations can be found in <a class="reference internal" href="advanced_topics.html#advancedtopics"><em>Advanced Topics</em></a>.</p>
+<p>XMDS2 should be cited as <a class="reference external" href="http://dx.doi.org/10.1016/j.cpc.2012.08.016">Comput. Phys. Commun. 184, 201-208 (2013)</a>.</p>
+<p id="xmdshistory"><strong>History:</strong>   <strong>XMDS</strong> was created in 1997 by Peter Drummond and Greg Collecutt, who conceived of the idea of using an XML-based code generator to simplify the process of integrating systems of equations with arbitrary dimension <a class="footnote-reference" href="#f1" id="id1">[1]</a>.  The first version was written in C, and featured a very flexible, strongly convergent stochastic algorithm: the <a class="reference internal" href="referenc [...]
+<p>In 2003, the increased scope of the package prompted a complete rewrite by Greg Collecutt (using C++), which lead to <strong>XMDS 1.0</strong>.  It was placed on sourceforge, and over a dozen developers contributed from 2003-2007 to help XMDS address a wider range of problems with a range of modern algorithms and support for parallel supercomputing.  The documentation and installation method was improved enabling the software to be used in a wider context, and XMDS gained many users f [...]
+<p>In 2008 a second complete rewrite was undertaken, largely by Graham Dennis (using Cheetah templates in python), leading to the current version <strong>XMDS2</strong>.  This restructuring of the internal treatment of XML elements and the generated code allowed a new range of extensions to be explored.  These included possibilities such as integrating multiple fields with different dimensionality, a more general set of differential equations that can be solved efficiently, and multiple  [...]
+<p class="rubric">Footnotes</p>
+<table class="docutils footnote" frame="void" id="f1" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id1">[1]</a></td><td>G.R.Collecutt and P.D.Drummond, <cite>Xmds: eXtensible multi-dimensional simulator</cite>, Comput. Phys. Commun. <strong>142</strong>, 219 (2001).</td></tr>
+</tbody>
+</table>
+<table class="docutils footnote" frame="void" id="f2" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id2">[2]</a></td><td>M.J.Werner and P.D.Drummond, <cite>Robust algorithms for solving stochastic partial differential equations</cite>, J. Comput. Phys. <strong>132</strong>, 312 (1997).</td></tr>
+</tbody>
+</table>
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="index.html">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+<div id="searchbox" style="display: none">
+  <h3>Quick search</h3>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" />
+      <input type="submit" value="Go" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    <p class="searchtip" style="font-size: 90%">
+    Enter search terms or a module, class or function name.
+    </p>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/documentation/latex/FourierTransformEx1.pdf b/documentation/latex/FourierTransformEx1.pdf
new file mode 100644
index 0000000..840f843
Binary files /dev/null and b/documentation/latex/FourierTransformEx1.pdf differ
diff --git a/documentation/latex/FourierTransformEx2.pdf b/documentation/latex/FourierTransformEx2.pdf
new file mode 100644
index 0000000..1c31b06
Binary files /dev/null and b/documentation/latex/FourierTransformEx2.pdf differ
diff --git a/documentation/latex/FourierTransformEx3.pdf b/documentation/latex/FourierTransformEx3.pdf
new file mode 100644
index 0000000..b9b49c8
Binary files /dev/null and b/documentation/latex/FourierTransformEx3.pdf differ
diff --git a/documentation/latex/Makefile b/documentation/latex/Makefile
new file mode 100644
index 0000000..6b87ad8
--- /dev/null
+++ b/documentation/latex/Makefile
@@ -0,0 +1,66 @@
+# Makefile for Sphinx LaTeX output
+
+ALLDOCS = $(basename $(wildcard *.tex))
+ALLPDF = $(addsuffix .pdf,$(ALLDOCS))
+ALLDVI = $(addsuffix .dvi,$(ALLDOCS))
+
+# Prefix for archive names
+ARCHIVEPRREFIX =
+# Additional LaTeX options
+LATEXOPTS =
+
+all: $(ALLPDF)
+all-pdf: $(ALLPDF)
+all-dvi: $(ALLDVI)
+all-ps: all-dvi
+	for f in *.dvi; do dvips $$f; done
+
+all-pdf-ja:
+	for f in *.pdf *.png *.gif *.jpg *.jpeg; do extractbb $$f; done
+	for f in *.tex; do platex -kanji=utf8 $(LATEXOPTS) $$f; done
+	for f in *.tex; do platex -kanji=utf8 $(LATEXOPTS) $$f; done
+	for f in *.tex; do platex -kanji=utf8 $(LATEXOPTS) $$f; done
+	-for f in *.idx; do mendex -U -f -d "`basename $$f .idx`.dic" -s python.ist $$f; done
+	for f in *.tex; do platex -kanji=utf8 $(LATEXOPTS) $$f; done
+	for f in *.tex; do platex -kanji=utf8 $(LATEXOPTS) $$f; done
+	for f in *.dvi; do dvipdfmx $$f; done
+
+zip: all-$(FMT)
+	mkdir $(ARCHIVEPREFIX)docs-$(FMT)
+	cp $(ALLPDF) $(ARCHIVEPREFIX)docs-$(FMT)
+	zip -q -r -9 $(ARCHIVEPREFIX)docs-$(FMT).zip $(ARCHIVEPREFIX)docs-$(FMT)
+	rm -r $(ARCHIVEPREFIX)docs-$(FMT)
+
+tar: all-$(FMT)
+	mkdir $(ARCHIVEPREFIX)docs-$(FMT)
+	cp $(ALLPDF) $(ARCHIVEPREFIX)docs-$(FMT)
+	tar cf $(ARCHIVEPREFIX)docs-$(FMT).tar $(ARCHIVEPREFIX)docs-$(FMT)
+	rm -r $(ARCHIVEPREFIX)docs-$(FMT)
+
+bz2: tar
+	bzip2 -9 -k $(ARCHIVEPREFIX)docs-$(FMT).tar
+
+# The number of LaTeX runs is quite conservative, but I don't expect it
+# to get run often, so the little extra time won't hurt.
+%.dvi: %.tex
+	latex $(LATEXOPTS) '$<'
+	latex $(LATEXOPTS) '$<'
+	latex $(LATEXOPTS) '$<'
+	-makeindex -s python.ist '$(basename $<).idx'
+	latex $(LATEXOPTS) '$<'
+	latex $(LATEXOPTS) '$<'
+
+%.pdf: %.tex
+	pdflatex $(LATEXOPTS) '$<'
+	pdflatex $(LATEXOPTS) '$<'
+	pdflatex $(LATEXOPTS) '$<'
+	-makeindex -s python.ist '$(basename $<).idx'
+	pdflatex $(LATEXOPTS) '$<'
+	pdflatex $(LATEXOPTS) '$<'
+
+clean:
+	rm -f *.dvi *.log *.ind *.aux *.toc *.syn *.idx *.out *.ilg *.pla
+
+.PHONY: all all-pdf all-dvi all-ps clean
+.PHONY: all-pdf-ja
+
diff --git a/documentation/latex/fibre1024.pdf b/documentation/latex/fibre1024.pdf
new file mode 100644
index 0000000..c17abb1
Binary files /dev/null and b/documentation/latex/fibre1024.pdf differ
diff --git a/documentation/latex/fibreSingle.pdf b/documentation/latex/fibreSingle.pdf
new file mode 100644
index 0000000..e0e689c
Binary files /dev/null and b/documentation/latex/fibreSingle.pdf differ
diff --git a/documentation/latex/fncychap.sty b/documentation/latex/fncychap.sty
new file mode 100644
index 0000000..9a56c04
--- /dev/null
+++ b/documentation/latex/fncychap.sty
@@ -0,0 +1,683 @@
+%%% Copyright   Ulf A. Lindgren
+%%%
+%%% Note        Premission is granted to modify this file under
+%%%             the condition that it is saved using another
+%%%             file and package name.
+%%%
+%%% Revision    1.1 (1997)
+%%%
+%%%             Jan. 8th Modified package name base date option
+%%%             Jan. 22th Modified FmN and FmTi for error in book.cls
+%%%                  \MakeUppercase{#}->{\MakeUppercase#}
+%%%             Apr. 6th Modified Lenny option to prevent undesired 
+%%%                  skip of line.
+%%%             Nov. 8th Fixed \@chapapp for AMS
+%%%
+%%% Revision    1.2 (1998)
+%%%
+%%%             Feb. 11th Fixed appendix problem related to Bjarne
+%%%             Aug. 11th Fixed problem related to 11pt and 12pt 
+%%%                  suggested by Tomas Lundberg. THANKS!
+%%%
+%%% Revision    1.3 (2004)
+%%%             Sep. 20th problem with frontmatter, mainmatter and
+%%%                  backmatter, pointed out by Lapo Mori
+%%%
+%%% Revision    1.31 (2004)
+%%%             Sep. 21th problem with the Rejne definition streched text
+%%%                  caused ugly gaps in the vrule aligned with the title
+%%%                  text. Kindly pointed out to me by Hendri Adriaens
+%%%
+%%% Revision    1.32 (2005)
+%%%             Jun. 23th compatibility problem with the KOMA class 'scrbook.cls'
+%%%                  a remedy is a redefinition of '\@schapter' in
+%%%                  line with that used in KOMA. The problem was pointed
+%%%                  out to me by Mikkel Holm Olsen
+%%%
+%%% Revision    1.33 (2005)
+%%%             Aug. 9th misspelled ``TWELV'' corrected, the error was pointed
+%%%                  out to me by George Pearson
+%%%
+%%% Revision    1.34 (2007)
+%%%             Added an alternative to Lenny provided by Peter
+%%%             Osborne (2005-11-28)
+%%%             Corrected front, main and back matter, based on input
+%%%             from Bas van Gils (2006-04-24)
+%%%             Jul. 30th Added Bjornstrup option provided by Jean-Marc
+%%%             Francois (2007-01-05).
+%%%             Reverted to \MakeUppercase{#} see rev 1.1, solved
+%%%             problem with MakeUppercase and MakeLowercase pointed
+%%%             out by Marco Feuerstein  (2007-06-06) 
+
+
+%%% Last modified   Jul. 2007
+
+\NeedsTeXFormat{LaTeX2e}[1995/12/01]
+\ProvidesPackage{fncychap}
+             [2007/07/30 v1.34
+                 LaTeX package (Revised chapters)]
+
+%%%% For conditional inclusion of color
+\newif\ifusecolor
+\usecolorfalse
+
+
+
+%%%% DEFINITION OF Chapapp variables
+\newcommand{\CNV}{\huge\bfseries}
+\newcommand{\ChNameVar}[1]{\renewcommand{\CNV}{#1}}
+
+
+%%%% DEFINITION OF TheChapter variables
+\newcommand{\CNoV}{\huge\bfseries}
+\newcommand{\ChNumVar}[1]{\renewcommand{\CNoV}{#1}}
+
+\newif\ifUCN
+\UCNfalse
+\newif\ifLCN
+\LCNfalse
+\def\ChNameLowerCase{\LCNtrue\UCNfalse}
+\def\ChNameUpperCase{\UCNtrue\LCNfalse}
+\def\ChNameAsIs{\UCNfalse\LCNfalse}
+
+%%%%% Fix for AMSBook 971008
+
+\@ifundefined{@chapapp}{\let\@chapapp\chaptername}{}
+
+
+%%%%% Fix for Bjarne and appendix 980211
+
+\newif\ifinapp
+\inappfalse
+\renewcommand\appendix{\par
+  \setcounter{chapter}{0}%
+  \setcounter{section}{0}%
+  \inapptrue%
+  \renewcommand\@chapapp{\appendixname}%
+  \renewcommand\thechapter{\@Alph\c at chapter}}
+
+%%%%% Fix for frontmatter, mainmatter, and backmatter 040920
+
+\@ifundefined{@mainmatter}{\newif\if at mainmatter \@mainmattertrue}{}
+
+%%%%%
+
+
+
+\newcommand{\FmN}[1]{%
+\ifUCN
+   {\MakeUppercase{#1}}\LCNfalse
+\else
+   \ifLCN
+      {\MakeLowercase{#1}}\UCNfalse
+   \else #1
+   \fi
+\fi}
+
+
+%%%% DEFINITION OF Title variables
+\newcommand{\CTV}{\Huge\bfseries}
+\newcommand{\ChTitleVar}[1]{\renewcommand{\CTV}{#1}}
+
+%%%% DEFINITION OF the basic rule width
+\newlength{\RW}
+\setlength{\RW}{1pt}
+\newcommand{\ChRuleWidth}[1]{\setlength{\RW}{#1}}
+
+\newif\ifUCT
+\UCTfalse
+\newif\ifLCT
+\LCTfalse
+\def\ChTitleLowerCase{\LCTtrue\UCTfalse}
+\def\ChTitleUpperCase{\UCTtrue\LCTfalse}
+\def\ChTitleAsIs{\UCTfalse\LCTfalse}
+\newcommand{\FmTi}[1]{%
+\ifUCT
+   {\MakeUppercase{#1}}\LCTfalse
+\else
+   \ifLCT
+      {\MakeLowercase{#1}}\UCTfalse
+   \else {#1}
+   \fi
+\fi}
+
+
+
+\newlength{\mylen}
+\newlength{\myhi}
+\newlength{\px}
+\newlength{\py}
+\newlength{\pyy}
+\newlength{\pxx}
+
+
+\def\mghrulefill#1{\leavevmode\leaders\hrule\@height #1\hfill\kern\z@}
+
+\newcommand{\DOCH}{%
+  \CNV\FmN{\@chapapp}\space \CNoV\thechapter
+  \par\nobreak
+  \vskip 20\p@
+  }
+\newcommand{\DOTI}[1]{%
+    \CTV\FmTi{#1}\par\nobreak
+    \vskip 40\p@
+    }
+\newcommand{\DOTIS}[1]{%
+    \CTV\FmTi{#1}\par\nobreak
+    \vskip 40\p@
+    }
+
+%%%%%% SONNY DEF
+
+\DeclareOption{Sonny}{%
+  \ChNameVar{\Large\sf}
+  \ChNumVar{\Huge}
+  \ChTitleVar{\Large\sf}
+  \ChRuleWidth{0.5pt}
+  \ChNameUpperCase
+  \renewcommand{\DOCH}{%
+    \raggedleft
+    \CNV\FmN{\@chapapp}\space \CNoV\thechapter
+    \par\nobreak
+    \vskip 40\p@}
+  \renewcommand{\DOTI}[1]{%
+    \CTV\raggedleft\mghrulefill{\RW}\par\nobreak
+    \vskip 5\p@
+    \CTV\FmTi{#1}\par\nobreak
+    \mghrulefill{\RW}\par\nobreak
+    \vskip 40\p@}
+  \renewcommand{\DOTIS}[1]{%
+    \CTV\raggedleft\mghrulefill{\RW}\par\nobreak
+    \vskip 5\p@
+    \CTV\FmTi{#1}\par\nobreak
+    \mghrulefill{\RW}\par\nobreak
+    \vskip 40\p@}
+}
+
+%%%%%% LENNY DEF
+
+\DeclareOption{Lenny}{%
+
+  \ChNameVar{\fontsize{14}{16}\usefont{OT1}{phv}{m}{n}\selectfont}
+  \ChNumVar{\fontsize{60}{62}\usefont{OT1}{ptm}{m}{n}\selectfont}
+  \ChTitleVar{\Huge\bfseries\rm}
+  \ChRuleWidth{1pt}
+  \renewcommand{\DOCH}{%
+    \settowidth{\px}{\CNV\FmN{\@chapapp}}
+    \addtolength{\px}{2pt}
+    \settoheight{\py}{\CNV\FmN{\@chapapp}}
+    \addtolength{\py}{1pt}
+
+    \settowidth{\mylen}{\CNV\FmN{\@chapapp}\space\CNoV\thechapter}
+    \addtolength{\mylen}{1pt}
+    \settowidth{\pxx}{\CNoV\thechapter}
+    \addtolength{\pxx}{-1pt}
+
+    \settoheight{\pyy}{\CNoV\thechapter}
+    \addtolength{\pyy}{-2pt}
+    \setlength{\myhi}{\pyy}
+    \addtolength{\myhi}{-1\py}
+    \par
+    \parbox[b]{\textwidth}{%
+    \rule[\py]{\RW}{\myhi}%
+    \hskip -\RW%
+    \rule[\pyy]{\px}{\RW}%
+    \hskip -\px%
+    \raggedright%
+    \CNV\FmN{\@chapapp}\space\CNoV\thechapter%
+    \hskip1pt%
+    \mghrulefill{\RW}%
+    \rule{\RW}{\pyy}\par\nobreak%
+    \vskip -\baselineskip%
+    \vskip -\pyy%
+    \hskip \mylen%
+    \mghrulefill{\RW}\par\nobreak%
+    \vskip \pyy}%
+    \vskip 20\p@}
+ 
+
+  \renewcommand{\DOTI}[1]{%
+    \raggedright
+    \CTV\FmTi{#1}\par\nobreak
+    \vskip 40\p@}
+
+  \renewcommand{\DOTIS}[1]{%
+    \raggedright
+    \CTV\FmTi{#1}\par\nobreak
+    \vskip 40\p@}
+ }
+
+%%%%%% Peter Osbornes' version of LENNY DEF
+
+\DeclareOption{PetersLenny}{%
+
+% five new lengths 
+\newlength{\bl}                           %  bottom left   : orig \space
+\setlength{\bl}{6pt}
+\newcommand{\BL}[1]{\setlength{\bl}{#1}}
+\newlength{\br}                           %  bottom right  : orig 1pt
+\setlength{\br}{1pt}
+\newcommand{\BR}[1]{\setlength{\br}{#1}}
+\newlength{\tl}                           %  top left      : orig 2pt
+\setlength{\tl}{2pt}
+\newcommand{\TL}[1]{\setlength{\tl}{#1}}
+\newlength{\trr}                           %  top right      :orig 1pt 
+\setlength{\trr}{1pt}
+\newcommand{\TR}[1]{\setlength{\trr}{#1}}
+\newlength{\blrule}                           %  top right      :orig 1pt 
+\setlength{\trr}{0pt}
+\newcommand{\BLrule}[1]{\setlength{\blrule}{#1}}
+
+
+  \ChNameVar{\fontsize{14}{16}\usefont{OT1}{phv}{m}{n}\selectfont}
+  \ChNumVar{\fontsize{60}{62}\usefont{OT1}{ptm}{m}{n}\selectfont}
+  \ChTitleVar{\Huge\bfseries\rm}
+  \ChRuleWidth{1pt}
+\renewcommand{\DOCH}{%
+
+
+%%%%%%%                                   tweaks for 1--9 and A--Z
+\ifcase\c at chapter\relax%
+\or\BL{-3pt}\TL{-4pt}\BR{0pt}\TR{-6pt}%1
+\or\BL{0pt}\TL{-4pt}\BR{2pt}\TR{-4pt}%2
+\or\BL{0pt}\TL{-4pt}\BR{2pt}\TR{-4pt}%3
+\or\BL{0pt}\TL{5pt}\BR{2pt}\TR{-4pt}%4
+\or\BL{0pt}\TL{3pt}\BR{2pt}\TR{-4pt}%5
+\or\BL{-1pt}\TL{0pt}\BR{2pt}\TR{-2pt}%6
+\or\BL{0pt}\TL{-3pt}\BR{2pt}\TR{-2pt}%7
+\or\BL{0pt}\TL{-3pt}\BR{2pt}\TR{-2pt}%8
+\or\BL{0pt}\TL{-3pt}\BR{-4pt}\TR{-2pt}%9
+\or\BL{-3pt}\TL{-3pt}\BR{2pt}\TR{-7pt}%10
+\or\BL{-6pt}\TL{-6pt}\BR{0pt}\TR{-9pt}%11
+\or\BL{-6pt}\TL{-6pt}\BR{2pt}\TR{-7pt}%12
+\or\BL{-5pt}\TL{-5pt}\BR{0pt}\TR{-9pt}%13
+\or\BL{-6pt}\TL{-6pt}\BR{0pt}\TR{-9pt}%14
+\or\BL{-3pt}\TL{-3pt}\BR{3pt}\TR{-6pt}%15
+\or\BL{-3pt}\TL{-3pt}\BR{3pt}\TR{-6pt}%16
+\or\BL{-5pt}\TL{-3pt}\BR{-8pt}\TR{-6pt}%17
+\or\BL{-5pt}\TL{-5pt}\BR{0pt}\TR{-9pt}%18
+\or\BL{-3pt}\TL{-3pt}\BR{-6pt}\TR{-9pt}%19
+\or\BL{0pt}\TL{0pt}\BR{0pt}\TR{-5pt}%20
+\fi
+
+\ifinapp\ifcase\c at chapter\relax%
+\or\BL{0pt}\TL{14pt}\BR{5pt}\TR{-19pt}%A
+\or\BL{0pt}\TL{-5pt}\BR{-3pt}\TR{-8pt}%B
+\or\BL{-3pt}\TL{-2pt}\BR{1pt}\TR{-6pt}\BLrule{0pt}%C
+\or\BL{0pt}\TL{-5pt}\BR{-3pt}\TR{-8pt}\BLrule{0pt}%D
+\or\BL{0pt}\TL{-5pt}\BR{2pt}\TR{-3pt}%E
+\or\BL{0pt}\TL{-5pt}\BR{-10pt}\TR{-1pt}%F
+\or\BL{-3pt}\TL{0pt}\BR{0pt}\TR{-7pt}%G
+\or\BL{0pt}\TL{-5pt}\BR{3pt}\TR{-1pt}%H
+\or\BL{0pt}\TL{-5pt}\BR{3pt}\TR{-1pt}%I
+\or\BL{2pt}\TL{0pt}\BR{-3pt}\TR{1pt}%J
+\or\BL{0pt}\TL{-5pt}\BR{3pt}\TR{-1pt}%K
+\or\BL{0pt}\TL{-5pt}\BR{2pt}\TR{-19pt}%L
+\or\BL{0pt}\TL{-5pt}\BR{3pt}\TR{-1pt}%M
+\or\BL{0pt}\TL{-5pt}\BR{-2pt}\TR{-1pt}%N
+\or\BL{-3pt}\TL{-2pt}\BR{-3pt}\TR{-11pt}%O
+\or\BL{0pt}\TL{-5pt}\BR{-9pt}\TR{-3pt}%P
+\or\BL{-3pt}\TL{-2pt}\BR{-3pt}\TR{-11pt}%Q
+\or\BL{0pt}\TL{-5pt}\BR{4pt}\TR{-8pt}%R
+\or\BL{-2pt}\TL{-2pt}\BR{-2pt}\TR{-7pt}%S
+\or\BL{-3pt}\TL{0pt}\BR{-5pt}\TR{4pt}\BLrule{8pt}%T
+\or\BL{-7pt}\TL{-11pt}\BR{-5pt}\TR{-7pt}\BLrule{0pt}%U
+\or\BL{-14pt}\TL{-5pt}\BR{-14pt}\TR{-1pt}\BLrule{14pt}%V
+\or\BL{-10pt}\TL{-9pt}\BR{-13pt}\TR{-3pt}\BLrule{7pt}%W
+\or\BL{0pt}\TL{-5pt}\BR{3pt}\TR{-1pt}\BLrule{0pt}%X
+\or\BL{-6pt}\TL{-4pt}\BR{-7pt}\TR{1pt}\BLrule{7pt}%Y
+\or\BL{0pt}\TL{-5pt}\BR{3pt}\TR{-1pt}\BLrule{0pt}%Z
+\fi\fi
+%%%%%%%
+    \settowidth{\px}{\CNV\FmN{\@chapapp}}
+    \addtolength{\px}{\tl}        %MOD change 2pt to \tl
+    \settoheight{\py}{\CNV\FmN{\@chapapp}}
+    \addtolength{\py}{1pt}
+
+    \settowidth{\mylen}{\CNV\FmN{\@chapapp}\space\CNoV\thechapter}
+    \addtolength{\mylen}{\trr}% MOD change 1pt to \tr
+    \settowidth{\pxx}{\CNoV\thechapter}
+    \addtolength{\pxx}{-1pt}
+
+    \settoheight{\pyy}{\CNoV\thechapter}
+    \addtolength{\pyy}{-2pt}
+    \setlength{\myhi}{\pyy}
+    \addtolength{\myhi}{-1\py}
+    \par
+    \parbox[b]{\textwidth}{%
+    \rule[\py]{\RW}{\myhi}%
+    \hskip -\RW%
+    \rule[\pyy]{\px}{\RW}% 
+    \hskip -\px%
+    \raggedright%
+    \CNV\FmN{\@chapapp}\rule{\blrule}{\RW}\hskip\bl\CNoV\thechapter%MOD 
+%    \CNV\FmN{\@chapapp}\space\CNoV\thechapter                     %ORIGINAL
+    \hskip\br%                           %MOD 1pt to \br
+    \mghrulefill{\RW}% 
+    \rule{\RW}{\pyy}\par\nobreak% 
+    \vskip -\baselineskip%
+    \vskip -\pyy%
+    \hskip \mylen%
+    \mghrulefill{\RW}\par\nobreak%
+    \vskip \pyy}%
+    \vskip 20\p@}
+ 
+
+  \renewcommand{\DOTI}[1]{%
+    \raggedright
+    \CTV\FmTi{#1}\par\nobreak
+    \vskip 40\p@}
+
+  \renewcommand{\DOTIS}[1]{%
+    \raggedright
+    \CTV\FmTi{#1}\par\nobreak
+    \vskip 40\p@}
+ }
+
+
+%
+
+
+%%%%%% BJORNSTRUP DEF
+
+\DeclareOption{Bjornstrup}{%
+  \usecolortrue
+  % pzc (Zapf Chancelery) is nice.  ppl (Palatino) is cool too.
+  \ChNumVar{\fontsize{76}{80}\usefont{OT1}{pzc}{m}{n}\selectfont}
+  \ChTitleVar{\raggedleft\Large\sffamily\bfseries}
+
+  \setlength{\myhi}{10pt}         % Space between grey box border and text
+  \setlength{\mylen}{\textwidth}
+  \addtolength{\mylen}{-2\myhi}
+  \renewcommand{\DOCH}{%
+    \settowidth{\py}{\CNoV\thechapter}
+    \addtolength{\py}{-10pt}      % Amount of space by which the
+%                                  % number is shifted right
+    \fboxsep=0pt%
+    \colorbox[gray]{.85}{\rule{0pt}{40pt}\parbox[b]{\textwidth}{\hfill}}%
+    \kern-\py\raise20pt%
+    \hbox{\color[gray]{.5}\CNoV\thechapter}\\%
+  }
+  
+  \renewcommand{\DOTI}[1]{%
+    \nointerlineskip\raggedright%
+    \fboxsep=\myhi%
+    \vskip-1ex%
+    \colorbox[gray]{.85}{\parbox[t]{\mylen}{\CTV\FmTi{#1}}}\par\nobreak%
+    \vskip 40\p@%
+  }
+
+  \renewcommand{\DOTIS}[1]{%
+    \fboxsep=0pt
+    \colorbox[gray]{.85}{\rule{0pt}{40pt}\parbox[b]{\textwidth}{\hfill}}\\%
+    \nointerlineskip\raggedright%
+    \fboxsep=\myhi%
+    \colorbox[gray]{.85}{\parbox[t]{\mylen}{\CTV\FmTi{#1}}}\par\nobreak%
+    \vskip 40\p@%
+  }
+}
+
+
+%%%%%%% GLENN DEF
+
+
+\DeclareOption{Glenn}{%
+  \ChNameVar{\bfseries\Large\sf}
+  \ChNumVar{\Huge}
+  \ChTitleVar{\bfseries\Large\rm}
+  \ChRuleWidth{1pt}
+  \ChNameUpperCase
+  \ChTitleUpperCase
+  \renewcommand{\DOCH}{%
+    \settoheight{\myhi}{\CTV\FmTi{Test}}
+    \setlength{\py}{\baselineskip}
+    \addtolength{\py}{\RW}
+    \addtolength{\py}{\myhi}
+    \setlength{\pyy}{\py}
+    \addtolength{\pyy}{-1\RW}
+     
+    \raggedright
+    \CNV\FmN{\@chapapp}\space\CNoV\thechapter
+    \hskip 3pt\mghrulefill{\RW}\rule[-1\pyy]{2\RW}{\py}\par\nobreak}
+
+  \renewcommand{\DOTI}[1]{%
+    \addtolength{\pyy}{-4pt}
+    \settoheight{\myhi}{\CTV\FmTi{#1}}
+    \addtolength{\myhi}{\py}
+    \addtolength{\myhi}{-1\RW}
+    \vskip -1\pyy
+    \rule{2\RW}{\myhi}\mghrulefill{\RW}\hskip 2pt
+    \raggedleft\CTV\FmTi{#1}\par\nobreak
+    \vskip 80\p@}
+
+\newlength{\backskip}
+  \renewcommand{\DOTIS}[1]{%
+%    \setlength{\py}{10pt}
+%    \setlength{\pyy}{\py}
+%    \addtolength{\pyy}{\RW}
+%    \setlength{\myhi}{\baselineskip}
+%    \addtolength{\myhi}{\pyy}
+%    \mghrulefill{\RW}\rule[-1\py]{2\RW}{\pyy}\par\nobreak
+%    \addtolength{}{}
+%\vskip -1\baselineskip
+%    \rule{2\RW}{\myhi}\mghrulefill{\RW}\hskip 2pt
+%    \raggedleft\CTV\FmTi{#1}\par\nobreak
+%    \vskip 60\p@}
+%% Fix suggested by Tomas Lundberg
+    \setlength{\py}{25pt}  % eller vad man vill
+    \setlength{\pyy}{\py}
+    \setlength{\backskip}{\py}
+    \addtolength{\backskip}{2pt}
+    \addtolength{\pyy}{\RW}
+    \setlength{\myhi}{\baselineskip}
+    \addtolength{\myhi}{\pyy}
+    \mghrulefill{\RW}\rule[-1\py]{2\RW}{\pyy}\par\nobreak
+    \vskip -1\backskip
+    \rule{2\RW}{\myhi}\mghrulefill{\RW}\hskip 3pt %
+    \raggedleft\CTV\FmTi{#1}\par\nobreak
+    \vskip 40\p@}
+ }
+
+%%%%%%% CONNY DEF
+
+\DeclareOption{Conny}{%
+  \ChNameUpperCase
+  \ChTitleUpperCase  
+  \ChNameVar{\centering\Huge\rm\bfseries}
+  \ChNumVar{\Huge}
+  \ChTitleVar{\centering\Huge\rm}
+  \ChRuleWidth{2pt}
+
+  \renewcommand{\DOCH}{%
+    \mghrulefill{3\RW}\par\nobreak
+    \vskip -0.5\baselineskip
+    \mghrulefill{\RW}\par\nobreak
+    \CNV\FmN{\@chapapp}\space \CNoV\thechapter
+    \par\nobreak
+    \vskip -0.5\baselineskip
+   }
+  \renewcommand{\DOTI}[1]{%
+    \mghrulefill{\RW}\par\nobreak
+    \CTV\FmTi{#1}\par\nobreak
+    \vskip 60\p@
+    }
+  \renewcommand{\DOTIS}[1]{%
+    \mghrulefill{\RW}\par\nobreak
+    \CTV\FmTi{#1}\par\nobreak
+    \vskip 60\p@
+    }
+  }
+
+%%%%%%% REJNE DEF
+
+\DeclareOption{Rejne}{%
+
+  \ChNameUpperCase
+  \ChTitleUpperCase  
+  \ChNameVar{\centering\Large\rm}
+  \ChNumVar{\Huge}
+  \ChTitleVar{\centering\Huge\rm}
+  \ChRuleWidth{1pt}
+  \renewcommand{\DOCH}{%
+    \settoheight{\py}{\CNoV\thechapter}
+    \parskip=0pt plus 1pt % Set parskip to default, just in case v1.31
+    \addtolength{\py}{-1pt}
+    \CNV\FmN{\@chapapp}\par\nobreak
+    \vskip 20\p@
+    \setlength{\myhi}{2\baselineskip}
+    \setlength{\px}{\myhi}
+    \addtolength{\px}{-1\RW}
+    \rule[-1\px]{\RW}{\myhi}\mghrulefill{\RW}\hskip
+    10pt\raisebox{-0.5\py}{\CNoV\thechapter}\hskip 10pt\mghrulefill{\RW}\rule[-1\px]{\RW}{\myhi}\par\nobreak
+     \vskip -3\p@% Added -2pt vskip to correct for streched text v1.31
+    }
+  \renewcommand{\DOTI}[1]{%
+    \setlength{\mylen}{\textwidth}
+    \parskip=0pt plus 1pt % Set parskip to default, just in case v1.31
+    \addtolength{\mylen}{-2\RW}
+    {\vrule width\RW}\parbox{\mylen}{\CTV\FmTi{#1}}{\vrule width\RW}\par\nobreak%
+    \vskip -3pt\rule{\RW}{2\baselineskip}\mghrulefill{\RW}\rule{\RW}{2\baselineskip}%
+    \vskip 60\p@% Added -2pt in vskip to correct for streched text v1.31
+    }
+  \renewcommand{\DOTIS}[1]{%
+    \setlength{\py}{\fboxrule}
+    \setlength{\fboxrule}{\RW}
+    \setlength{\mylen}{\textwidth}
+    \addtolength{\mylen}{-2\RW}
+    \fbox{\parbox{\mylen}{\vskip 2\baselineskip\CTV\FmTi{#1}\par\nobreak\vskip \baselineskip}} 
+    \setlength{\fboxrule}{\py}
+    \vskip 60\p@
+    }
+  }
+
+
+%%%%%%% BJARNE DEF
+
+\DeclareOption{Bjarne}{%
+  \ChNameUpperCase
+  \ChTitleUpperCase  
+  \ChNameVar{\raggedleft\normalsize\rm}
+  \ChNumVar{\raggedleft \bfseries\Large}
+  \ChTitleVar{\raggedleft \Large\rm}
+  \ChRuleWidth{1pt}
+
+
+%% Note thechapter -> c at chapter fix appendix bug
+%% Fixed misspelled 12
+
+  \newcounter{AlphaCnt}
+  \newcounter{AlphaDecCnt}
+  \newcommand{\AlphaNo}{%
+    \ifcase\number\theAlphaCnt
+      \ifnum\c at chapter=0
+        ZERO\else{}\fi
+    \or ONE\or TWO\or THREE\or FOUR\or FIVE
+    \or SIX\or SEVEN\or EIGHT\or NINE\or TEN
+    \or ELEVEN\or TWELVE\or THIRTEEN\or FOURTEEN\or FIFTEEN
+    \or SIXTEEN\or SEVENTEEN\or EIGHTEEN\or NINETEEN\fi
+}
+
+  \newcommand{\AlphaDecNo}{%
+    \setcounter{AlphaDecCnt}{0}
+    \@whilenum\number\theAlphaCnt>0\do
+      {\addtocounter{AlphaCnt}{-10}
+       \addtocounter{AlphaDecCnt}{1}}
+     \ifnum\number\theAlphaCnt=0
+     \else
+       \addtocounter{AlphaDecCnt}{-1}
+       \addtocounter{AlphaCnt}{10}
+     \fi
+     
+     
+    \ifcase\number\theAlphaDecCnt\or TEN\or TWENTY\or THIRTY\or
+    FORTY\or FIFTY\or SIXTY\or SEVENTY\or EIGHTY\or NINETY\fi
+    }
+  \newcommand{\TheAlphaChapter}{%
+    
+    \ifinapp 
+      \thechapter
+    \else
+      \setcounter{AlphaCnt}{\c at chapter}
+      \ifnum\c at chapter<20
+        \AlphaNo
+      \else
+        \AlphaDecNo\AlphaNo
+      \fi
+    \fi
+    }  
+  \renewcommand{\DOCH}{%
+    \mghrulefill{\RW}\par\nobreak
+    \CNV\FmN{\@chapapp}\par\nobreak 
+    \CNoV\TheAlphaChapter\par\nobreak
+    \vskip -1\baselineskip\vskip 5pt\mghrulefill{\RW}\par\nobreak
+    \vskip 20\p@
+    }
+  \renewcommand{\DOTI}[1]{%
+    \CTV\FmTi{#1}\par\nobreak
+    \vskip 40\p@
+    }
+  \renewcommand{\DOTIS}[1]{%
+    \CTV\FmTi{#1}\par\nobreak
+    \vskip 40\p@
+    }
+}
+
+\DeclareOption*{%
+  \PackageWarning{fancychapter}{unknown style option}
+  }
+
+\ProcessOptions* \relax
+
+\ifusecolor
+  \RequirePackage{color} 
+\fi
+\def\@makechapterhead#1{%
+  \vspace*{50\p@}%
+  {\parindent \z@ \raggedright \normalfont
+    \ifnum \c at secnumdepth >\m at ne
+      \if at mainmatter%%%%% Fix for frontmatter, mainmatter, and backmatter 040920
+        \DOCH
+      \fi
+    \fi
+    \interlinepenalty\@M
+    \if at mainmatter%%%%% Fix for frontmatter, mainmatter, and backmatter 060424
+      \DOTI{#1}%
+    \else%
+      \DOTIS{#1}%
+    \fi
+  }}
+
+
+%%% Begin: To avoid problem with scrbook.cls (fncychap version 1.32)
+
+%%OUT:
+%\def\@schapter#1{\if at twocolumn
+%                   \@topnewpage[\@makeschapterhead{#1}]%
+%                 \else
+%                   \@makeschapterhead{#1}%
+%                   \@afterheading
+%                 \fi}
+
+%%IN:
+\def\@schapter#1{%
+\if at twocolumn%
+  \@makeschapterhead{#1}%
+\else%
+  \@makeschapterhead{#1}%
+  \@afterheading%
+\fi}
+
+%%% End: To avoid problem with scrbook.cls (fncychap version 1.32)
+
+\def\@makeschapterhead#1{%
+  \vspace*{50\p@}%
+  {\parindent \z@ \raggedright
+    \normalfont
+    \interlinepenalty\@M
+    \DOTIS{#1}
+    \vskip 40\p@
+  }}
+
+\endinput
+
+
diff --git a/documentation/latex/groundstateU2.pdf b/documentation/latex/groundstateU2.pdf
new file mode 100644
index 0000000..bb4a54c
Binary files /dev/null and b/documentation/latex/groundstateU2.pdf differ
diff --git a/documentation/latex/groundstateU20.pdf b/documentation/latex/groundstateU20.pdf
new file mode 100644
index 0000000..c322493
Binary files /dev/null and b/documentation/latex/groundstateU20.pdf differ
diff --git a/documentation/latex/kubo10000.pdf b/documentation/latex/kubo10000.pdf
new file mode 100644
index 0000000..6ccd468
Binary files /dev/null and b/documentation/latex/kubo10000.pdf differ
diff --git a/documentation/latex/kuboSingle.pdf b/documentation/latex/kuboSingle.pdf
new file mode 100644
index 0000000..2193e21
Binary files /dev/null and b/documentation/latex/kuboSingle.pdf differ
diff --git a/documentation/latex/lorenz.pdf b/documentation/latex/lorenz.pdf
new file mode 100644
index 0000000..aa528d1
Binary files /dev/null and b/documentation/latex/lorenz.pdf differ
diff --git a/documentation/latex/python.ist b/documentation/latex/python.ist
new file mode 100644
index 0000000..9ffa0f9
--- /dev/null
+++ b/documentation/latex/python.ist
@@ -0,0 +1,11 @@
+line_max 100
+headings_flag 1
+heading_prefix "  \\bigletter "
+
+preamble "\\begin{theindex}
+\\def\\bigletter#1{{\\Large\\sffamily#1}\\nopagebreak\\vspace{1mm}}
+
+"
+
+symhead_positive "{Symbols}"
+numhead_positive "{Numbers}"
diff --git a/documentation/latex/sphinx.sty b/documentation/latex/sphinx.sty
new file mode 100644
index 0000000..9b083cc
--- /dev/null
+++ b/documentation/latex/sphinx.sty
@@ -0,0 +1,520 @@
+%
+% sphinx.sty
+%
+% Adapted from the old python.sty, mostly written by Fred Drake,
+% by Georg Brandl.
+%
+
+\NeedsTeXFormat{LaTeX2e}[1995/12/01]
+\ProvidesPackage{sphinx}[2010/01/15 LaTeX package (Sphinx markup)]
+
+\@ifclassloaded{memoir}{}{\RequirePackage{fancyhdr}}
+
+\RequirePackage{textcomp}
+\RequirePackage{fancybox}
+\RequirePackage{titlesec}
+\RequirePackage{tabulary}
+\RequirePackage{amsmath} % for \text
+\RequirePackage{makeidx}
+\RequirePackage{framed}
+\RequirePackage{ifthen}
+\RequirePackage{color}
+% For highlighted code.
+\RequirePackage{fancyvrb}
+% For table captions.
+\RequirePackage{threeparttable}
+% Handle footnotes in tables.
+\RequirePackage{footnote}
+\makesavenoteenv{tabulary}
+% For floating figures in the text.
+\RequirePackage{wrapfig}
+% Separate paragraphs by space by default.
+\RequirePackage{parskip}
+
+% Redefine these colors to your liking in the preamble.
+\definecolor{TitleColor}{rgb}{0.126,0.263,0.361}
+\definecolor{InnerLinkColor}{rgb}{0.208,0.374,0.486}
+\definecolor{OuterLinkColor}{rgb}{0.216,0.439,0.388}
+% Redefine these colors to something not white if you want to have colored
+% background and border for code examples.
+\definecolor{VerbatimColor}{rgb}{1,1,1}
+\definecolor{VerbatimBorderColor}{rgb}{1,1,1}
+
+% Uncomment these two lines to ignore the paper size and make the page 
+% size more like a typical published manual.
+%\renewcommand{\paperheight}{9in}
+%\renewcommand{\paperwidth}{8.5in}   % typical squarish manual
+%\renewcommand{\paperwidth}{7in}     % O'Reilly ``Programmming Python''
+
+% use pdfoutput for pTeX and dvipdfmx
+\ifx\kanjiskip\undefined\else
+  \ifx\Gin at driver{dvipdfmx.def}\undefined\else
+    \newcount\pdfoutput\pdfoutput=0
+  \fi
+\fi
+
+% For graphicx, check if we are compiling under latex or pdflatex.
+\ifx\pdftexversion\undefined
+  \usepackage{graphicx}
+\else
+  \usepackage[pdftex]{graphicx}
+\fi
+
+% for PDF output, use colors and maximal compression
+\newif\ifsphinxpdfoutput\sphinxpdfoutputfalse
+\ifx\pdfoutput\undefined\else\ifcase\pdfoutput
+  \let\py at NormalColor\relax
+  \let\py at TitleColor\relax
+\else
+  \sphinxpdfoutputtrue
+  \input{pdfcolor}
+  \def\py at NormalColor{\color[rgb]{0.0,0.0,0.0}}
+  \def\py at TitleColor{\color{TitleColor}}
+  \pdfcompresslevel=9
+\fi\fi
+
+% XeLaTeX can do colors, too
+\ifx\XeTeXrevision\undefined\else
+  \def\py at NormalColor{\color[rgb]{0.0,0.0,0.0}}
+  \def\py at TitleColor{\color{TitleColor}}
+\fi
+
+% Increase printable page size (copied from fullpage.sty)
+\topmargin 0pt
+\advance \topmargin by -\headheight
+\advance \topmargin by -\headsep
+
+% attempt to work a little better for A4 users
+\textheight \paperheight
+\advance\textheight by -2in
+
+\oddsidemargin 0pt
+\evensidemargin 0pt
+%\evensidemargin -.25in  % for ``manual size'' documents
+\marginparwidth 0.5in
+
+\textwidth \paperwidth
+\advance\textwidth by -2in
+
+
+% Style parameters and macros used by most documents here
+\raggedbottom
+\sloppy
+\hbadness = 5000                % don't print trivial gripes
+
+\pagestyle{empty}               % start this way
+
+% Use this to set the font family for headers and other decor:
+\newcommand{\py at HeaderFamily}{\sffamily\bfseries}
+
+% Redefine the 'normal' header/footer style when using "fancyhdr" package:
+\@ifundefined{fancyhf}{}{
+  % Use \pagestyle{normal} as the primary pagestyle for text.
+  \fancypagestyle{normal}{
+    \fancyhf{}
+    \fancyfoot[LE,RO]{{\py at HeaderFamily\thepage}}
+    \fancyfoot[LO]{{\py at HeaderFamily\nouppercase{\rightmark}}}
+    \fancyfoot[RE]{{\py at HeaderFamily\nouppercase{\leftmark}}}
+    \fancyhead[LE,RO]{{\py at HeaderFamily \@title, \py at release}}
+    \renewcommand{\headrulewidth}{0.4pt}
+    \renewcommand{\footrulewidth}{0.4pt}
+    % define chaptermark with \@chappos when \@chappos is available for Japanese
+    \ifx\@chappos\undefined\else
+      \def\chaptermark##1{\markboth{\@chapapp\space\thechapter\space\@chappos\space ##1}{}}
+    \fi
+  }
+  % Update the plain style so we get the page number & footer line,
+  % but not a chapter or section title.  This is to keep the first
+  % page of a chapter and the blank page between chapters `clean.'
+  \fancypagestyle{plain}{
+    \fancyhf{}
+    \fancyfoot[LE,RO]{{\py at HeaderFamily\thepage}}
+    \renewcommand{\headrulewidth}{0pt}
+    \renewcommand{\footrulewidth}{0.4pt}
+  }
+}
+
+% Some custom font markup commands.
+%
+\newcommand{\strong}[1]{{\textbf{#1}}}
+\newcommand{\code}[1]{\texttt{#1}}
+\newcommand{\bfcode}[1]{\code{\bfseries#1}}
+\newcommand{\email}[1]{\textsf{#1}}
+
+% Redefine the Verbatim environment to allow border and background colors.
+% The original environment is still used for verbatims within tables.
+\let\OriginalVerbatim=\Verbatim
+\let\endOriginalVerbatim=\endVerbatim
+
+% Play with vspace to be able to keep the indentation.
+\newlength\distancetoright
+\def\mycolorbox#1{%
+  \setlength\distancetoright{\linewidth}%
+  \advance\distancetoright -\@totalleftmargin %
+  \fcolorbox{VerbatimBorderColor}{VerbatimColor}{%
+  \begin{minipage}{\distancetoright}%
+    #1
+  \end{minipage}%
+  }%
+}
+\def\FrameCommand{\mycolorbox}
+
+\renewcommand{\Verbatim}[1][1]{%
+  % list starts new par, but we don't want it to be set apart vertically
+  \bgroup\parskip=0pt%
+  \smallskip%
+  % The list environement is needed to control perfectly the vertical
+  % space.
+  \list{}{%
+  \setlength\parskip{0pt}%
+  \setlength\itemsep{0ex}%
+  \setlength\topsep{0ex}%
+  \setlength\partopsep{0pt}%
+  \setlength\leftmargin{0pt}%
+  }%
+  \item\MakeFramed {\FrameRestore}%
+     \small%
+    \OriginalVerbatim[#1]%
+}
+\renewcommand{\endVerbatim}{%
+    \endOriginalVerbatim%
+  \endMakeFramed%
+  \endlist%
+  % close group to restore \parskip
+  \egroup%
+}
+
+
+% \moduleauthor{name}{email}
+\newcommand{\moduleauthor}[2]{}
+
+% \sectionauthor{name}{email}
+\newcommand{\sectionauthor}[2]{}
+
+% Augment the sectioning commands used to get our own font family in place,
+% and reset some internal data items:
+\titleformat{\section}{\Large\py at HeaderFamily}%
+            {\py at TitleColor\thesection}{0.5em}{\py at TitleColor}{\py at NormalColor}
+\titleformat{\subsection}{\large\py at HeaderFamily}%
+            {\py at TitleColor\thesubsection}{0.5em}{\py at TitleColor}{\py at NormalColor}
+\titleformat{\subsubsection}{\py at HeaderFamily}%
+            {\py at TitleColor\thesubsubsection}{0.5em}{\py at TitleColor}{\py at NormalColor}
+\titleformat{\paragraph}{\small\py at HeaderFamily}%
+            {\py at TitleColor}{0em}{\py at TitleColor}{\py at NormalColor}
+
+% {fulllineitems} is the main environment for object descriptions.
+%
+\newcommand{\py at itemnewline}[1]{%
+  \@tempdima\linewidth%
+  \advance\@tempdima \leftmargin\makebox[\@tempdima][l]{#1}%
+}
+
+\newenvironment{fulllineitems}{
+  \begin{list}{}{\labelwidth \leftmargin \labelsep 0pt
+                 \rightmargin 0pt \topsep -\parskip \partopsep \parskip
+                 \itemsep -\parsep
+                 \let\makelabel=\py at itemnewline}
+}{\end{list}}
+
+% \optional is used for ``[, arg]``, i.e. desc_optional nodes.
+\newcommand{\optional}[1]{%
+  {\textnormal{\Large[}}{#1}\hspace{0.5mm}{\textnormal{\Large]}}}
+
+\newlength{\py at argswidth}
+\newcommand{\py at sigparams}[2]{%
+  \parbox[t]{\py at argswidth}{#1\code{)}#2}}
+\newcommand{\pysigline}[1]{\item[#1]\nopagebreak}
+\newcommand{\pysiglinewithargsret}[3]{%
+  \settowidth{\py at argswidth}{#1\code{(}}%
+  \addtolength{\py at argswidth}{-2\py at argswidth}%
+  \addtolength{\py at argswidth}{\linewidth}%
+  \item[#1\code{(}\py at sigparams{#2}{#3}]}
+
+% Production lists
+%
+\newenvironment{productionlist}{
+%  \def\optional##1{{\Large[}##1{\Large]}}
+  \def\production##1##2{\\\code{##1}&::=&\code{##2}}
+  \def\productioncont##1{\\& &\code{##1}}
+  \parindent=2em
+  \indent
+  \begin{tabular}{lcl}
+}{%
+  \end{tabular}
+}
+
+% Notices / Admonitions
+%
+\newlength{\py at noticelength}
+
+\newcommand{\py at heavybox}{
+  \setlength{\fboxrule}{1pt}
+  \setlength{\fboxsep}{6pt}
+  \setlength{\py at noticelength}{\linewidth}
+  \addtolength{\py at noticelength}{-2\fboxsep}
+  \addtolength{\py at noticelength}{-2\fboxrule}
+  %\setlength{\shadowsize}{3pt}
+  \noindent\Sbox
+  \minipage{\py at noticelength}
+}
+\newcommand{\py at endheavybox}{
+  \endminipage
+  \endSbox
+  \fbox{\TheSbox}
+}
+
+\newcommand{\py at lightbox}{{%
+  \setlength\parskip{0pt}\par
+  \noindent\rule[0ex]{\linewidth}{0.5pt}%
+  \par\noindent\vspace{-0.5ex}%
+  }}
+\newcommand{\py at endlightbox}{{%
+  \setlength{\parskip}{0pt}%
+  \par\noindent\rule[0.5ex]{\linewidth}{0.5pt}%
+  \par\vspace{-0.5ex}%
+  }}
+
+% Some are quite plain:
+\newcommand{\py at noticestart@note}{\py at lightbox}
+\newcommand{\py at noticeend@note}{\py at endlightbox}
+\newcommand{\py at noticestart@hint}{\py at lightbox}
+\newcommand{\py at noticeend@hint}{\py at endlightbox}
+\newcommand{\py at noticestart@important}{\py at lightbox}
+\newcommand{\py at noticeend@important}{\py at endlightbox}
+\newcommand{\py at noticestart@tip}{\py at lightbox}
+\newcommand{\py at noticeend@tip}{\py at endlightbox}
+
+% Others gets more visible distinction:
+\newcommand{\py at noticestart@warning}{\py at heavybox}
+\newcommand{\py at noticeend@warning}{\py at endheavybox}
+\newcommand{\py at noticestart@caution}{\py at heavybox}
+\newcommand{\py at noticeend@caution}{\py at endheavybox}
+\newcommand{\py at noticestart@attention}{\py at heavybox}
+\newcommand{\py at noticeend@attention}{\py at endheavybox}
+\newcommand{\py at noticestart@danger}{\py at heavybox}
+\newcommand{\py at noticeend@danger}{\py at endheavybox}
+\newcommand{\py at noticestart@error}{\py at heavybox}
+\newcommand{\py at noticeend@error}{\py at endheavybox}
+
+\newenvironment{notice}[2]{
+  \def\py at noticetype{#1}
+  \csname py at noticestart@#1\endcsname
+  \strong{#2}
+}{\csname py at noticeend@\py at noticetype\endcsname}
+
+% Allow the release number to be specified independently of the
+% \date{}.  This allows the date to reflect the document's date and
+% release to specify the release that is documented.
+%
+\newcommand{\py at release}{}
+\newcommand{\version}{}
+\newcommand{\shortversion}{}
+\newcommand{\releaseinfo}{}
+\newcommand{\releasename}{Release}
+\newcommand{\release}[1]{%
+  \renewcommand{\py at release}{\releasename\space\version}%
+  \renewcommand{\version}{#1}}
+\newcommand{\setshortversion}[1]{%
+  \renewcommand{\shortversion}{#1}}
+\newcommand{\setreleaseinfo}[1]{%
+  \renewcommand{\releaseinfo}{#1}}
+
+% Allow specification of the author's address separately from the
+% author's name.  This can be used to format them differently, which
+% is a good thing.
+%
+\newcommand{\py at authoraddress}{}
+\newcommand{\authoraddress}[1]{\renewcommand{\py at authoraddress}{#1}}
+
+% This sets up the fancy chapter headings that make the documents look
+% at least a little better than the usual LaTeX output.
+%
+\@ifundefined{ChTitleVar}{}{
+  \ChNameVar{\raggedleft\normalsize\py at HeaderFamily}
+  \ChNumVar{\raggedleft \bfseries\Large\py at HeaderFamily}
+  \ChTitleVar{\raggedleft \textrm{\Huge\py at HeaderFamily}}
+  % This creates chapter heads without the leading \vspace*{}:
+  \def\@makechapterhead#1{%
+    {\parindent \z@ \raggedright \normalfont
+      \ifnum \c at secnumdepth >\m at ne
+        \DOCH
+      \fi
+      \interlinepenalty\@M
+      \DOTI{#1}
+    }
+  }
+}
+
+% Redefine description environment so that it is usable inside fulllineitems.
+%
+\renewcommand{\description}{%
+  \list{}{\labelwidth\z@%
+          \itemindent-\leftmargin%
+	  \labelsep5pt%
+          \let\makelabel=\descriptionlabel}}
+
+% Definition lists; requested by AMK for HOWTO documents.  Probably useful
+% elsewhere as well, so keep in in the general style support.
+%
+\newenvironment{definitions}{%
+  \begin{description}%
+  \def\term##1{\item[##1]\mbox{}\\*[0mm]}
+}{%
+  \end{description}%
+}
+
+% Tell TeX about pathological hyphenation cases:
+\hyphenation{Base-HTTP-Re-quest-Hand-ler}
+
+
+% The following is stuff copied from docutils' latex writer.
+%
+\newcommand{\optionlistlabel}[1]{\bf #1 \hfill}
+\newenvironment{optionlist}[1]
+{\begin{list}{}
+  {\setlength{\labelwidth}{#1}
+   \setlength{\rightmargin}{1cm}
+   \setlength{\leftmargin}{\rightmargin}
+   \addtolength{\leftmargin}{\labelwidth}
+   \addtolength{\leftmargin}{\labelsep}
+   \renewcommand{\makelabel}{\optionlistlabel}}
+}{\end{list}}
+
+\newlength{\lineblockindentation}
+\setlength{\lineblockindentation}{2.5em}
+\newenvironment{lineblock}[1]
+{\begin{list}{}
+  {\setlength{\partopsep}{\parskip}
+   \addtolength{\partopsep}{\baselineskip}
+   \topsep0pt\itemsep0.15\baselineskip\parsep0pt
+   \leftmargin#1}
+ \raggedright}
+{\end{list}}
+
+% Redefine includgraphics for avoiding images larger than the screen size
+% If the size is not specified.
+\let\py at Oldincludegraphics\includegraphics
+
+\newbox\image at box%
+\newdimen\image at width%
+\renewcommand\includegraphics[2][\@empty]{%
+  \ifx#1\@empty%
+    \setbox\image at box=\hbox{\py at Oldincludegraphics{#2}}%
+    \image at width\wd\image at box%
+    \ifdim \image at width>\linewidth%
+      \setbox\image at box=\hbox{\py at Oldincludegraphics[width=\linewidth]{#2}}%
+      \box\image at box%
+    \else%
+      \py at Oldincludegraphics{#2}%
+    \fi%
+  \else%
+    \py at Oldincludegraphics[#1]{#2}%
+  \fi%
+}
+
+% to make pdf with correct encoded bookmarks in Japanese
+% this should precede the hyperref package
+\ifx\kanjiskip\undefined\else
+  \usepackage{atbegshi}
+  \ifx\ucs\undefined
+    \ifnum 42146=\euc"A4A2
+      \AtBeginShipoutFirst{\special{pdf:tounicode EUC-UCS2}}
+    \else
+      \AtBeginShipoutFirst{\special{pdf:tounicode 90ms-RKSJ-UCS2}}
+    \fi
+  \else
+    \AtBeginShipoutFirst{\special{pdf:tounicode UTF8-UCS2}}
+  \fi
+\fi
+
+% Include hyperref last.
+\RequirePackage[colorlinks,breaklinks,
+                linkcolor=InnerLinkColor,filecolor=OuterLinkColor,
+                menucolor=OuterLinkColor,urlcolor=OuterLinkColor,
+                citecolor=InnerLinkColor]{hyperref}
+% Fix anchor placement for figures with captions.
+% (Note: we don't use a package option here; instead, we give an explicit
+% \capstart for figures that actually have a caption.)
+\RequirePackage{hypcap}
+
+% From docutils.writers.latex2e
+\providecommand{\DUspan}[2]{%
+  {% group ("span") to limit the scope of styling commands
+    \@for\node at class@name:=#1\do{%
+    \ifcsname docutilsrole\node at class@name\endcsname%
+      \csname docutilsrole\node at class@name\endcsname%
+    \fi%
+    }%
+    {#2}% node content
+  }% close "span"
+}
+
+\providecommand*{\DUprovidelength}[2]{
+  \ifthenelse{\isundefined{#1}}{\newlength{#1}\setlength{#1}{#2}}{}
+}
+
+\DUprovidelength{\DUlineblockindent}{2.5em}
+\ifthenelse{\isundefined{\DUlineblock}}{
+  \newenvironment{DUlineblock}[1]{%
+    \list{}{\setlength{\partopsep}{\parskip}
+            \addtolength{\partopsep}{\baselineskip}
+            \setlength{\topsep}{0pt}
+            \setlength{\itemsep}{0.15\baselineskip}
+            \setlength{\parsep}{0pt}
+            \setlength{\leftmargin}{#1}}
+    \raggedright
+  }
+  {\endlist}
+}{}
+
+
+% From footmisc.sty: allows footnotes in titles
+\let\FN at sf@@footnote\footnote
+\def\footnote{\ifx\protect\@typeset at protect
+    \expandafter\FN at sf@@footnote
+  \else
+    \expandafter\FN at sf@gobble at opt
+  \fi
+}
+\edef\FN at sf@gobble at opt{\noexpand\protect
+  \expandafter\noexpand\csname FN at sf@gobble at opt \endcsname}
+\expandafter\def\csname FN at sf@gobble at opt \endcsname{%
+  \@ifnextchar[%]
+    \FN at sf@gobble at twobracket
+    \@gobble
+}
+\def\FN at sf@gobble at twobracket[#1]#2{}
+
+% adjust the margins for footer,
+% this works with the jsclasses only (Japanese standard document classes)
+\ifx\@jsc at uplatextrue\undefined\else
+  \hypersetup{setpagesize=false}
+  \setlength\footskip{2\baselineskip}
+  \addtolength{\textheight}{-2\baselineskip}
+\fi
+
+% fix the double index and bibliography on the table of contents
+% in jsclasses (Japanese standard document classes)
+\ifx\@jsc at uplatextrue\undefined\else
+  \renewcommand{\theindex}{
+    \cleardoublepage
+    \phantomsection
+    \py at OldTheindex
+  }
+  \renewcommand{\thebibliography}[1]{
+    \cleardoublepage
+    \phantomsection
+    \py at OldThebibliography{1}
+  }
+\fi
+
+% do not use \@chappos in Appendix in pTeX
+\ifx\kanjiskip\undefined\else
+  \renewcommand{\appendix}{\par
+    \setcounter{chapter}{0}
+      \setcounter{section}{0}
+      \gdef\@chapapp{\appendixname}
+      \gdef\@chappos{}
+      \gdef\thechapter{\@Alph\c at chapter}
+  }
+\fi
diff --git a/documentation/latex/sphinxhowto.cls b/documentation/latex/sphinxhowto.cls
new file mode 100644
index 0000000..26e63a7
--- /dev/null
+++ b/documentation/latex/sphinxhowto.cls
@@ -0,0 +1,104 @@
+%
+% sphinxhowto.cls for Sphinx (http://sphinx-doc.org/)
+%
+
+\NeedsTeXFormat{LaTeX2e}[1995/12/01]
+\ProvidesClass{sphinxhowto}[2009/06/02 Document class (Sphinx HOWTO)]
+
+% 'oneside' option overriding the 'twoside' default
+\newif\if at oneside
+\DeclareOption{oneside}{\@onesidetrue}
+% Pass remaining document options to the parent class.
+\DeclareOption*{\PassOptionsToClass{\CurrentOption}{\sphinxdocclass}}
+\ProcessOptions\relax
+
+% Default to two-side document
+\if at oneside
+% nothing to do (oneside is the default)
+\else
+\PassOptionsToClass{twoside}{\sphinxdocclass}
+\fi
+
+\LoadClass{\sphinxdocclass}
+
+% Set some sane defaults for section numbering depth and TOC depth.  You can
+% reset these counters in your preamble.
+%
+\setcounter{secnumdepth}{2}
+
+% Change the title page to look a bit better, and fit in with the fncychap
+% ``Bjarne'' style a bit better.
+%
+\renewcommand{\maketitle}{
+  \rule{\textwidth}{1pt}
+  \ifsphinxpdfoutput
+    \begingroup
+    % These \defs are required to deal with multi-line authors; it
+    % changes \\ to ', ' (comma-space), making it pass muster for
+    % generating document info in the PDF file.
+    \def\\{, }
+    \def\and{and }
+    \pdfinfo{
+      /Author (\@author)
+      /Title (\@title)
+    }
+    \endgroup
+  \fi
+  \begin{flushright}
+    \sphinxlogo%
+    {\rm\Huge\py at HeaderFamily \@title} \par
+    {\em\large\py at HeaderFamily \py at release\releaseinfo} \par
+    \vspace{25pt}
+    {\Large\py at HeaderFamily
+      \begin{tabular}[t]{c}
+        \@author
+      \end{tabular}} \par
+    \vspace{25pt}
+    \@date \par
+    \py at authoraddress \par
+  \end{flushright}
+  \@thanks
+  \setcounter{footnote}{0}
+  \let\thanks\relax\let\maketitle\relax
+  %\gdef\@thanks{}\gdef\@author{}\gdef\@title{}
+}
+
+\let\py at OldTableofcontents=\tableofcontents
+\renewcommand{\tableofcontents}{
+  \begingroup
+    \parskip = 0mm
+    \py at OldTableofcontents
+  \endgroup
+  \rule{\textwidth}{1pt}
+  \vspace{12pt}
+}  
+
+\@ifundefined{fancyhf}{
+  \pagestyle{plain}}{
+  \pagestyle{normal}}		% start this way; change for
+\pagenumbering{arabic}		% ToC & chapters
+
+\thispagestyle{empty}
+
+% Fix the bibliography environment to add an entry to the Table of
+% Contents.
+% For an article document class this environment is a section,
+% so no page break before it.
+\let\py at OldThebibliography=\thebibliography
+\renewcommand{\thebibliography}[1]{
+  \phantomsection
+  \py at OldThebibliography{1}
+  \addcontentsline{toc}{section}{\bibname}
+}
+
+% Same for the indices.
+% The memoir class already does this, so we don't duplicate it in that case.
+%
+\@ifclassloaded{memoir}{}{
+  \let\py at OldTheindex=\theindex
+  \renewcommand{\theindex}{
+    \phantomsection
+    \py at OldTheindex
+    \addcontentsline{toc}{section}{\indexname}
+  }
+}
diff --git a/documentation/latex/sphinxmanual.cls b/documentation/latex/sphinxmanual.cls
new file mode 100644
index 0000000..26df488
--- /dev/null
+++ b/documentation/latex/sphinxmanual.cls
@@ -0,0 +1,147 @@
+%
+% sphinxmanual.cls for Sphinx (http://sphinx-doc.org/)
+%
+
+\NeedsTeXFormat{LaTeX2e}[1995/12/01]
+\ProvidesClass{sphinxmanual}[2009/06/02 Document class (Sphinx manual)]
+
+% chapters starting at odd pages (overridden by 'openany' document option)
+\PassOptionsToClass{openright}{\sphinxdocclass}
+
+% 'oneside' option overriding the 'twoside' default
+\newif\if at oneside
+\DeclareOption{oneside}{\@onesidetrue}
+% Pass remaining document options to the parent class.
+\DeclareOption*{\PassOptionsToClass{\CurrentOption}{\sphinxdocclass}}
+\ProcessOptions\relax
+
+% Defaults two-side document
+\if at oneside
+% nothing to do (oneside is the default)
+\else
+\PassOptionsToClass{twoside}{\sphinxdocclass}
+\fi
+
+\LoadClass{\sphinxdocclass}
+
+% Set some sane defaults for section numbering depth and TOC depth.  You can
+% reset these counters in your preamble.
+%
+\setcounter{secnumdepth}{2}
+\setcounter{tocdepth}{1}
+
+% Change the title page to look a bit better, and fit in with the fncychap
+% ``Bjarne'' style a bit better.
+%
+\renewcommand{\maketitle}{%
+  \begin{titlepage}%
+    \let\footnotesize\small
+    \let\footnoterule\relax
+    \rule{\textwidth}{1pt}%
+    \ifsphinxpdfoutput
+      \begingroup
+      % These \defs are required to deal with multi-line authors; it
+      % changes \\ to ', ' (comma-space), making it pass muster for
+      % generating document info in the PDF file.
+      \def\\{, }
+      \def\and{and }
+      \pdfinfo{
+        /Author (\@author)
+        /Title (\@title)
+      }
+      \endgroup
+    \fi
+    \begin{flushright}%
+      \sphinxlogo%
+      {\rm\Huge\py at HeaderFamily \@title \par}%
+      {\em\LARGE\py at HeaderFamily \py at release\releaseinfo \par}
+      \vfill
+      {\LARGE\py at HeaderFamily
+        \begin{tabular}[t]{c}
+          \@author
+        \end{tabular}
+        \par}
+      \vfill\vfill
+      {\large
+       \@date \par
+       \vfill
+       \py at authoraddress \par
+      }%
+    \end{flushright}%\par
+    \@thanks
+  \end{titlepage}%
+  \cleardoublepage%
+  \setcounter{footnote}{0}%
+  \let\thanks\relax\let\maketitle\relax
+  %\gdef\@thanks{}\gdef\@author{}\gdef\@title{}
+}
+
+
+% Catch the end of the {abstract} environment, but here make sure the abstract
+% is followed by a blank page if the 'openright' option is used.
+%
+\let\py at OldEndAbstract=\endabstract
+\renewcommand{\endabstract}{
+  \if at openright
+    \ifodd\value{page}
+      \typeout{Adding blank page after the abstract.}
+      \vfil\pagebreak
+    \fi
+  \fi
+  \py at OldEndAbstract
+}
+
+% This wraps the \tableofcontents macro with all the magic to get the spacing
+% right and have the right number of pages if the 'openright' option has been
+% used.  This eliminates a fair amount of crud in the individual document files.
+%
+\let\py at OldTableofcontents=\tableofcontents
+\renewcommand{\tableofcontents}{%
+  \setcounter{page}{1}%
+  \pagebreak%
+  \pagestyle{plain}%
+  {%
+    \parskip = 0mm%
+    \py at OldTableofcontents%
+    \if at openright%
+      \ifodd\value{page}%
+        \typeout{Adding blank page after the table of contents.}%
+        \pagebreak\hspace{0pt}%
+      \fi%
+    \fi%
+    \cleardoublepage%
+  }%
+  \pagenumbering{arabic}%
+  \@ifundefined{fancyhf}{}{\pagestyle{normal}}%
+}
+\pagenumbering{roman}
+
+% This is needed to get the width of the section # area wide enough in the
+% library reference.  Doing it here keeps it the same for all the manuals.
+%
+\renewcommand*\l at section{\@dottedtocline{1}{1.5em}{2.6em}}
+\renewcommand*\l at subsection{\@dottedtocline{2}{4.1em}{3.5em}}
+
+% Fix the bibliography environment to add an entry to the Table of
+% Contents.
+% For a report document class this environment is a chapter.
+\let\py at OldThebibliography=\thebibliography
+\renewcommand{\thebibliography}[1]{
+  \cleardoublepage
+  \phantomsection
+  \py at OldThebibliography{1}
+  \addcontentsline{toc}{chapter}{\bibname}
+}
+
+% Same for the indices.
+% The memoir class already does this, so we don't duplicate it in that case.
+%
+\@ifclassloaded{memoir}{}{
+  \let\py at OldTheindex=\theindex
+  \renewcommand{\theindex}{
+    \cleardoublepage
+    \phantomsection
+    \py at OldTheindex
+    \addcontentsline{toc}{chapter}{\indexname}
+  }
+}
diff --git a/documentation/latex/tabulary.sty b/documentation/latex/tabulary.sty
new file mode 100644
index 0000000..ba83c0a
--- /dev/null
+++ b/documentation/latex/tabulary.sty
@@ -0,0 +1,452 @@
+%%
+%% This is file `tabulary.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% tabulary.dtx  (with options: `package')
+%% DRAFT VERSION
+%%
+%% File `tabulary.dtx'.
+%% Copyright (C) 1995 1996 2003 David Carlisle
+%% This file may be distributed under the terms of the LPPL.
+%% See 00readme.txt for details.
+%%
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{tabulary}
+          [2007/10/02 v0.9 tabulary package (DPC)]
+\RequirePackage{array}
+\catcode`\Z=14
+\DeclareOption{debugshow}{\catcode`\Z=9\relax}
+\ProcessOptions
+\def\arraybackslash{\let\\=\@arraycr}
+\def\@finalstrut#1{%
+  \unskip\ifhmode\nobreak\fi\vrule\@width\z@\@height\z@\@depth\dp#1}
+\newcount\TY at count
+\def\tabulary{%
+  \let\TY at final\tabular
+  \let\endTY at final\endtabular
+  \TY at tabular}
+\def\TY at tabular#1{%
+  \edef\TY@{\@currenvir}%
+  {\ifnum0=`}\fi
+  \@ovxx\TY at linewidth
+  \@ovyy\TY at tablewidth
+  \count@\z@
+  \@tempswatrue
+  \@whilesw\if at tempswa\fi{%
+  \advance\count@\@ne
+  \expandafter\ifx\csname TY at F\the\count@\endcsname\relax
+    \@tempswafalse
+  \else
+    \expandafter\let\csname TY at SF\the\count@\expandafter\endcsname
+                     \csname TY at F\the\count@\endcsname
+    \global\expandafter\let\csname TY at F\the\count@\endcsname\relax
+    \expandafter\let\csname TY at S\the\count@\expandafter\endcsname
+                     \csname TY@\the\count@\endcsname
+  \fi}%
+    \global\TY at count\@ne
+    \TY at width\xdef{0pt}%
+    \global\TY at tablewidth\z@
+    \global\TY at linewidth#1\relax
+Z\message{^^J^^JTable^^J%
+Z        Target Width: \the\TY at linewidth^^J%
+Z        \string\tabcolsep: \the\tabcolsep\space
+Z        \string\arrayrulewidth: \the\arrayrulewidth\space
+Z        \string\doublerulesep: \the\doublerulesep^^J%
+Z        \string\tymin: \the\tymin\space
+Z        \string\tymax: \the\tymax^^J}%
+    \let\@classz\TY at classz
+    \let\verb\TX at verb
+    \toks@{}\TY at get@body}
+\let\TY@@mkpream\@mkpream
+\def\TY at mkpream{%
+    \def\@addamp{%
+      \if at firstamp \@firstampfalse \else
+      \global\advance\TY at count\@ne
+      \edef\@preamble{\@preamble &}\fi
+      \TY at width\xdef{0pt}}%
+    \def\@acol{%
+      \TY at subwidth\col at sep
+      \@addtopreamble{\hskip\col at sep}}%
+    \let\@arrayrule\TY at arrayrule
+    \let\@classvi\TY at classvi
+    \def\@classv{\save at decl
+      \expandafter\NC at ecs\@nextchar\extracolsep{}\extracolsep\@@@
+      \sbox\z@{\d at llarbegin\@nextchar\d at llarend}%
+      \TY at subwidth{\wd\z@}%
+      \@addtopreamble{\d at llarbegin\the at toks\the\count@\relax\d at llarend}%
+      \prepnext at tok}%
+  \global\let\@mkpream\TY@@mkpream
+  \TY@@mkpream}
+\def\TY at arrayrule{%
+  \TY at subwidth\arrayrulewidth
+  \@addtopreamble \vline}
+\def\TY at classvi{\ifcase \@lastchclass
+  \@acol \or
+  \TY at subwidth\doublerulesep
+  \@addtopreamble{\hskip \doublerulesep}\or
+  \@acol \or
+  \@classvii
+  \fi}
+\def\TY at tab{%
+  \setbox\z@\hbox\bgroup
+  \let\[$\let\]$%
+  \let\equation$\let\endequation$%
+    \col at sep\tabcolsep
+    \let\d at llarbegin\begingroup\let\d at llarend\endgroup
+    \let\@mkpream\TY at mkpream
+      \def\multicolumn##1##2##3{\multispan##1\relax}%
+    \CT at start\TY at tabarray}
+\def\TY at tabarray{\@ifnextchar[{\TY at array}{\@array[t]}}
+\def\TY at array[#1]{\@array[t]}
+\def\TY at width#1{%
+  \expandafter#1\csname TY@\the\TY at count\endcsname}
+\def\TY at subwidth#1{%
+  \TY at width\dimen@
+  \advance\dimen at -#1\relax
+  \TY at width\xdef{\the\dimen@}%
+  \global\advance\TY at linewidth-#1\relax}
+\def\endtabulary{%
+  \gdef\@halignto{}%
+  \let\TY at footnote\footnote%
+  \def\footnote{}% prevent footnotes from doing anything
+  \expandafter\TY at tab\the\toks@
+  \crcr\omit
+  {\xdef\TY at save@row{}%
+     \loop
+    \advance\TY at count\m at ne
+    \ifnum\TY at count>\z@
+    \xdef\TY at save@row{\TY at save@row&\omit}%
+    \repeat}\TY at save@row
+  \endarray\global\setbox1=\lastbox\setbox0=\vbox{\unvbox1
+    \unskip\global\setbox1=\lastbox}\egroup
+  \dimen@\TY at linewidth
+  \divide\dimen@\TY at count
+  \ifdim\dimen@<\tymin
+    \TY at warn{tymin too large (\the\tymin), resetting to \the\dimen@}%
+    \tymin\dimen@
+  \fi
+  \setbox\tw@=\hbox{\unhbox\@ne
+    \loop
+\@tempdima=\lastskip
+\ifdim\@tempdima>\z@
+Z   \message{ecs=\the\@tempdima^^J}%
+   \global\advance\TY at linewidth-\@tempdima
+\fi
+    \unskip
+    \setbox\tw@=\lastbox
+    \ifhbox\tw@
+Z     \message{Col \the\TY at count: Initial=\the\wd\tw@\space}%
+      \ifdim\wd\tw@>\tymax
+        \wd\tw@\tymax
+Z       \message{> max\space}%
+Z     \else
+Z       \message{ \@spaces\space}%
+      \fi
+  \TY at width\dimen@
+Z \message{\the\dimen@\space}%
+  \advance\dimen@\wd\tw@
+Z \message{Final=\the\dimen@\space}%
+   \TY at width\xdef{\the\dimen@}%
+      \ifdim\dimen@<\tymin
+Z        \message{< tymin}%
+         \global\advance\TY at linewidth-\dimen@
+         \expandafter\xdef\csname TY at F\the\TY at count\endcsname
+                                                        {\the\dimen@}%
+       \else
+      \expandafter\ifx\csname TY at F\the\TY at count\endcsname\z@
+Z        \message{***}%
+         \global\advance\TY at linewidth-\dimen@
+         \expandafter\xdef\csname TY at F\the\TY at count\endcsname
+                                                        {\the\dimen@}%
+        \else
+Z        \message{> tymin}%
+         \global\advance\TY at tablewidth\dimen@
+         \global\expandafter\let\csname TY at F\the\TY at count\endcsname
+                                                               \maxdimen
+       \fi\fi
+       \advance\TY at count\m at ne
+    \repeat}%
+    \TY at checkmin
+    \TY at checkmin
+    \TY at checkmin
+    \TY at checkmin
+    \TY at count\z@
+    \let\TY at box\TY at box@v
+    \let\footnote\TY at footnote % restore footnotes
+  {\expandafter\TY at final\the\toks@\endTY at final}%
+  \count@\z@
+  \@tempswatrue
+  \@whilesw\if at tempswa\fi{%
+  \advance\count@\@ne
+  \expandafter\ifx\csname TY at SF\the\count@\endcsname\relax
+    \@tempswafalse
+  \else
+    \global\expandafter\let\csname TY at F\the\count@\expandafter\endcsname
+                   \csname TY at SF\the\count@\endcsname
+    \global\expandafter\let\csname TY@\the\count@\expandafter\endcsname
+                   \csname TY at S\the\count@\endcsname
+  \fi}%
+  \TY at linewidth\@ovxx
+  \TY at tablewidth\@ovyy
+    \ifnum0=`{\fi}}
+\def\TY at checkmin{%
+  \let\TY at checkmin\relax
+\ifdim\TY at tablewidth>\z@
+  \Gscale at div\TY at ratio\TY at linewidth\TY at tablewidth
+ \ifdim\TY at tablewidth <\linewidth
+   \def\TY at ratio{1}%
+ \fi
+\else
+  \TY at warn{No suitable columns!}%
+  \def\TY at ratio{1}%
+\fi
+\count@\z@
+Z \message{^^JLine Width: \the\TY at linewidth,
+Z             Natural Width: \the\TY at tablewidth,
+Z             Ratio: \TY at ratio^^J}%
+\@tempdima\z@
+\loop
+\ifnum\count@<\TY at count
+\advance\count@\@ne
+  \ifdim\csname TY at F\the\count@\endcsname>\tymin
+    \dimen@\csname TY@\the\count@\endcsname
+    \dimen@\TY at ratio\dimen@
+    \ifdim\dimen@<\tymin
+Z     \message{Column \the\count@\space ->}%
+      \global\expandafter\let\csname TY at F\the\count@\endcsname\tymin
+      \global\advance\TY at linewidth-\tymin
+      \global\advance\TY at tablewidth-\csname TY@\the\count@\endcsname
+      \let\TY at checkmin\TY@@checkmin
+    \else
+      \expandafter\xdef\csname TY at F\the\count@\endcsname{\the\dimen@}%
+      \advance\@tempdima\csname TY at F\the\count@\endcsname
+    \fi
+  \fi
+Z \dimen@\csname TY at F\the\count@\endcsname\message{\the\dimen@, }%
+\repeat
+Z \message{^^JTotal:\the\@tempdima^^J}%
+}
+\let\TY@@checkmin\TY at checkmin
+\newdimen\TY at linewidth
+\def\tyformat{\everypar{{\nobreak\hskip\z at skip}}}
+\newdimen\tymin
+\tymin=10pt
+\newdimen\tymax
+\tymax=2\textwidth
+\def\@testpach{\@chclass
+ \ifnum \@lastchclass=6 \@ne \@chnum \@ne \else
+  \ifnum \@lastchclass=7 5 \else
+   \ifnum \@lastchclass=8 \tw@ \else
+    \ifnum \@lastchclass=9 \thr@@
+   \else \z@
+   \ifnum \@lastchclass = 10 \else
+   \edef\@nextchar{\expandafter\string\@nextchar}%
+   \@chnum
+   \if \@nextchar c\z@ \else
+    \if \@nextchar l\@ne \else
+     \if \@nextchar r\tw@ \else
+   \if \@nextchar C7 \else
+    \if \@nextchar L8 \else
+     \if \@nextchar R9 \else
+     \if \@nextchar J10 \else
+   \z@ \@chclass
+   \if\@nextchar |\@ne \else
+    \if \@nextchar !6 \else
+     \if \@nextchar @7 \else
+      \if \@nextchar <8 \else
+       \if \@nextchar >9 \else
+  10
+  \@chnum
+  \if \@nextchar m\thr@@\else
+   \if \@nextchar p4 \else
+    \if \@nextchar b5 \else
+   \z@ \@chclass \z@ \@preamerr \z@ \fi \fi \fi \fi\fi \fi \fi\fi \fi
+     \fi  \fi  \fi  \fi  \fi  \fi \fi \fi \fi \fi \fi}
+\def\TY at classz{%
+  \@classx
+  \@tempcnta\count@
+  \ifx\TY at box\TY at box@v
+    \global\advance\TY at count\@ne
+  \fi
+  \let\centering c%
+  \let\raggedright\noindent
+  \let\raggedleft\indent
+  \let\arraybackslash\relax
+  \prepnext at tok
+  \ifnum\@chnum<4
+    \global\expandafter\let\csname TY at F\the\TY at count\endcsname\z@
+  \fi
+  \ifnum\@chnum=6
+    \global\expandafter\let\csname TY at F\the\TY at count\endcsname\z@
+  \fi
+  \@addtopreamble{%
+    \ifcase\@chnum
+      \hfil \d at llarbegin\insert at column\d at llarend \hfil \or
+      \kern\z@
+       \d at llarbegin \insert at column \d at llarend \hfil \or
+      \hfil\kern\z@ \d at llarbegin \insert at column \d at llarend \or
+      $\vcenter\@startpbox{\@nextchar}\insert at column \@endpbox $\or
+      \vtop \@startpbox{\@nextchar}\insert at column \@endpbox \or
+      \vbox \@startpbox{\@nextchar}\insert at column \@endpbox \or
+      \d at llarbegin \insert at column \d at llarend \or% dubious "s" case
+      \TY at box\centering\or
+      \TY at box\raggedright\or
+      \TY at box\raggedleft\or
+      \TY at box\relax
+    \fi}\prepnext at tok}
+\def\TY at box#1{%
+  \ifx\centering#1%
+      \hfil \d at llarbegin\insert at column\d at llarend \hfil \else
+  \ifx\raggedright#1%
+        \kern\z@%<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+      \d at llarbegin \insert at column \d at llarend \hfil \else
+  \ifx\raggedleft#1%
+      \hfil\kern\z@ \d at llarbegin \insert at column \d at llarend \else
+  \ifx\relax#1%
+       \d at llarbegin \insert at column \d at llarend
+  \fi  \fi  \fi  \fi}
+\def\TY at box@v#1{%
+      \vtop \@startpbox{\csname TY at F\the\TY at count\endcsname}%
+              #1\arraybackslash\tyformat
+                              \insert at column\@endpbox}
+\newdimen\TY at tablewidth
+\def\Gscale at div#1#2#3{%
+  \setlength\dimen@{#3}%
+  \ifdim\dimen@=\z@
+    \PackageError{graphics}{Division by 0}\@eha
+    \dimen@#2%
+  \fi
+  \edef\@tempd{\the\dimen@}%
+  \setlength\dimen@{#2}%
+  \count at 65536\relax
+  \ifdim\dimen@<\z@
+    \dimen at -\dimen@
+    \count at -\count@
+  \fi
+  \loop
+    \ifdim\dimen@<8192\p@
+      \dimen@\tw@\dimen@
+      \divide\count@\tw@
+  \repeat
+  \dimen at ii=\@tempd\relax
+  \divide\dimen at ii\count@
+  \divide\dimen@\dimen at ii
+  \edef#1{\strip at pt\dimen@}}
+\long\def\TY at get@body#1\end
+  {\toks@\expandafter{\the\toks@#1}\TY at find@end}
+\def\TY at find@end#1{%
+  \def\@tempa{#1}%
+  \ifx\@tempa\TY@\def\@tempa{\end{#1}}\expandafter\@tempa
+  \else\toks@\expandafter
+    {\the\toks@\end{#1}}\expandafter\TY at get@body\fi}
+\def\TY at warn{%
+  \PackageWarning{tabulary}}
+\catcode`\Z=11
+\AtBeginDocument{
+\@ifpackageloaded{colortbl}{%
+\expandafter\def\expandafter\@mkpream\expandafter#\expandafter1%
+  \expandafter{%
+    \expandafter\let\expandafter\CT at setup\expandafter\relax
+    \expandafter\let\expandafter\CT at color\expandafter\relax
+    \expandafter\let\expandafter\CT at do@color\expandafter\relax
+    \expandafter\let\expandafter\color\expandafter\relax
+    \expandafter\let\expandafter\CT at column@color\expandafter\relax
+    \expandafter\let\expandafter\CT at row@color\expandafter\relax
+    \@mkpream{#1}}
+\let\TY@@mkpream\@mkpream
+\def\TY at classz{%
+  \@classx
+  \@tempcnta\count@
+  \ifx\TY at box\TY at box@v
+    \global\advance\TY at count\@ne
+  \fi
+  \let\centering c%
+  \let\raggedright\noindent
+  \let\raggedleft\indent
+  \let\arraybackslash\relax
+  \prepnext at tok
+\expandafter\CT at extract\the\toks\@tempcnta\columncolor!\@nil
+  \ifnum\@chnum<4
+    \global\expandafter\let\csname TY at F\the\TY at count\endcsname\z@
+  \fi
+  \ifnum\@chnum=6
+    \global\expandafter\let\csname TY at F\the\TY at count\endcsname\z@
+  \fi
+  \@addtopreamble{%
+    \setbox\z@\hbox\bgroup\bgroup
+    \ifcase\@chnum
+      \hskip\stretch{.5}\kern\z@
+      \d at llarbegin\insert at column\d at llarend\hskip\stretch{.5}\or
+      \kern\z@%<<<<<<<<<<<<<<<<<<<<<<<<<<<
+       \d at llarbegin \insert at column \d at llarend \hfill \or
+      \hfill\kern\z@ \d at llarbegin \insert at column \d at llarend \or
+      $\vcenter\@startpbox{\@nextchar}\insert at column \@endpbox $\or
+      \vtop \@startpbox{\@nextchar}\insert at column \@endpbox \or
+      \vbox \@startpbox{\@nextchar}\insert at column \@endpbox \or
+      \d at llarbegin \insert at column \d at llarend \or% dubious s case
+      \TY at box\centering\or
+      \TY at box\raggedright\or
+      \TY at box\raggedleft\or
+      \TY at box\relax
+    \fi
+ \egroup\egroup
+\begingroup
+  \CT at setup
+  \CT at column@color
+  \CT at row@color
+  \CT at do@color
+\endgroup
+        \@tempdima\ht\z@
+        \advance\@tempdima\minrowclearance
+        \vrule\@height\@tempdima\@width\z@
+\unhbox\z@
+}\prepnext at tok}%
+    \def\TY at arrayrule{%
+      \TY at subwidth\arrayrulewidth
+      \@addtopreamble{{\CT at arc@\vline}}}%
+    \def\TY at classvi{\ifcase \@lastchclass
+      \@acol \or
+      \TY at subwidth\doublerulesep
+      \ifx\CT at drsc@\relax
+        \@addtopreamble{\hskip\doublerulesep}%
+      \else
+        \@addtopreamble{{\CT at drsc@\vrule\@width\doublerulesep}}%
+      \fi\or
+      \@acol \or
+      \@classvii
+      \fi}%
+}{%
+\let\CT at start\relax
+}
+}
+{\uccode`\*=`\ %
+\uppercase{\gdef\TX at verb{%
+  \leavevmode\null\TX at vwarn
+  {\ifnum0=`}\fi\ttfamily\let\\\ignorespaces
+  \@ifstar{\let~*\TX at vb}{\TX at vb}}}}
+\def\TX at vb#1{\def\@tempa##1#1{\toks@{##1}\edef\@tempa{\the\toks@}%
+    \expandafter\TX at v\meaning\@tempa\\ \\\ifnum0=`{\fi}}\@tempa!}
+\def\TX at v#1!{\afterassignment\TX at vfirst\let\@tempa= }
+\begingroup
+\catcode`\*=\catcode`\#
+\catcode`\#=12
+\gdef\TX at vfirst{%
+  \if\@tempa#%
+    \def\@tempb{\TX at v@#}%
+  \else
+    \let\@tempb\TX at v@
+    \if\@tempa\space~\else\@tempa\fi
+  \fi
+  \@tempb}
+\gdef\TX at v@*1 *2{%
+  \TX at v@hash*1##\relax\if*2\\\else~\expandafter\TX at v@\fi*2}
+\gdef\TX at v@hash*1##*2{*1\ifx*2\relax\else#\expandafter\TX at v@hash\fi*2}
+\endgroup
+\def\TX at vwarn{%
+  \@warning{\noexpand\verb may be unreliable inside tabularx/y}%
+  \global\let\TX at vwarn\@empty}
+\endinput
+%%
+%% End of file `tabulary.sty'.
diff --git a/documentation/latex/xmds2.aux b/documentation/latex/xmds2.aux
new file mode 100644
index 0000000..4d2cdc7
--- /dev/null
+++ b/documentation/latex/xmds2.aux
@@ -0,0 +1,424 @@
+\relax 
+\providecommand\hyper at newdestlabel[2]{}
+\providecommand\HyperFirstAtBeginDocument{\AtBeginDocument}
+\HyperFirstAtBeginDocument{\ifx\hyper at anchor\@undefined
+\global\let\oldcontentsline\contentsline
+\gdef\contentsline#1#2#3#4{\oldcontentsline{#1}{#2}{#3}}
+\global\let\oldnewlabel\newlabel
+\gdef\newlabel#1#2{\newlabelxx{#1}#2}
+\gdef\newlabelxx#1#2#3#4#5#6{\oldnewlabel{#1}{{#2}{#3}}}
+\AtEndDocument{\ifx\hyper at anchor\@undefined
+\let\contentsline\oldcontentsline
+\let\newlabel\oldnewlabel
+\fi}
+\fi}
+\global\let\hyper at last\relax 
+\gdef\HyperFirstAtBeginDocument#1{#1}
+\providecommand\HyField at AuxAddToFields[1]{}
+\providecommand\HyField at AuxAddToCoFields[2]{}
+\select at language{english}
+\@writefile{toc}{\select at language{english}}
+\@writefile{lof}{\select at language{english}}
+\@writefile{lot}{\select at language{english}}
+\newlabel{documentation_toc::doc}{{}{1}{}{section*.2}{}}
+\@writefile{toc}{\contentsline {chapter}{\numberline {1}Introduction}{1}{chapter.1}}
+\@writefile{lof}{\addvspace {10\p@ }}
+\@writefile{lot}{\addvspace {10\p@ }}
+\newlabel{introduction:introduction}{{1}{1}{Introduction}{chapter.1}{}}
+\newlabel{introduction:documentation}{{1}{1}{Introduction}{chapter.1}{}}
+\newlabel{introduction::doc}{{1}{1}{Introduction}{chapter.1}{}}
+\newlabel{introduction:welcome-to-the-documentation-for-xmds2}{{1}{1}{Introduction}{chapter.1}{}}
+\newlabel{introduction:xmdshistory}{{1}{1}{Introduction}{section*.3}{}}
+\@writefile{toc}{\contentsline {chapter}{\numberline {2}Installation}{3}{chapter.2}}
+\@writefile{lof}{\addvspace {10\p@ }}
+\@writefile{lot}{\addvspace {10\p@ }}
+\newlabel{installation:installation}{{2}{3}{Installation}{chapter.2}{}}
+\newlabel{installation::doc}{{2}{3}{Installation}{chapter.2}{}}
+\newlabel{installation:id1}{{2}{3}{Installation}{chapter.2}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {2.1}Installers}{3}{section.2.1}}
+\newlabel{installation:installers}{{2.1}{3}{Installers}{section.2.1}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {2.2}Linux installer instructions}{3}{section.2.2}}
+\newlabel{installation:linux-installation}{{2.2}{3}{Linux installer instructions}{section.2.2}{}}
+\newlabel{installation:linux-installer-instructions}{{2.2}{3}{Linux installer instructions}{section.2.2}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {2.3}Mac OS X Installation}{4}{section.2.3}}
+\newlabel{installation:mac-os-x-installation}{{2.3}{4}{Mac OS X Installation}{section.2.3}{}}
+\newlabel{installation:mac-installation}{{2.3}{4}{Mac OS X Installation}{section.2.3}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {2.3.1}Download}{4}{subsection.2.3.1}}
+\newlabel{installation:download}{{2.3.1}{4}{Download}{subsection.2.3.1}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {2.3.2}Using the Mac OS X Installer}{4}{subsection.2.3.2}}
+\newlabel{installation:using-the-mac-os-x-installer}{{2.3.2}{4}{Using the Mac OS X Installer}{subsection.2.3.2}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {2.4}Manual installation from source}{4}{section.2.4}}
+\newlabel{installation:manualinstallation}{{2.4}{4}{Manual installation from source}{section.2.4}{}}
+\newlabel{installation:manual-installation-from-source}{{2.4}{4}{Manual installation from source}{section.2.4}{}}
+\newlabel{installation:hdf5-installation}{{4}{5}{Manual installation from source}{section*.4}{}}
+\@writefile{toc}{\contentsline {chapter}{\numberline {3}Quickstart Tutorial}{9}{chapter.3}}
+\@writefile{lof}{\addvspace {10\p@ }}
+\@writefile{lot}{\addvspace {10\p@ }}
+\newlabel{tutorial::doc}{{3}{9}{Quickstart Tutorial}{chapter.3}{}}
+\newlabel{tutorial:quickstart-tutorial}{{3}{9}{Quickstart Tutorial}{chapter.3}{}}
+\newlabel{tutorial:quickstarttutorial}{{3}{9}{Quickstart Tutorial}{chapter.3}{}}
+\@writefile{toc}{\contentsline {chapter}{\numberline {4}Worked Examples}{15}{chapter.4}}
+\@writefile{lof}{\addvspace {10\p@ }}
+\@writefile{lot}{\addvspace {10\p@ }}
+\newlabel{worked_examples:worked-examples}{{4}{15}{Worked Examples}{chapter.4}{}}
+\newlabel{worked_examples::doc}{{4}{15}{Worked Examples}{chapter.4}{}}
+\newlabel{worked_examples:workedexamples}{{4}{15}{Worked Examples}{chapter.4}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {4.1}The nonlinear Schr\IeC {\"o}dinger equation}{15}{section.4.1}}
+\newlabel{worked_examples:nonlinearschrodingerequation}{{4.1}{15}{The nonlinear Schrödinger equation}{section.4.1}{}}
+\newlabel{worked_examples:the-nonlinear-schrodinger-equation}{{4.1}{15}{The nonlinear Schrödinger equation}{section.4.1}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {4.2}Kubo Oscillator}{19}{section.4.2}}
+\newlabel{worked_examples:kubo}{{4.2}{19}{Kubo Oscillator}{section.4.2}{}}
+\newlabel{worked_examples:kubo-oscillator}{{4.2}{19}{Kubo Oscillator}{section.4.2}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {4.3}Fibre Noise}{21}{section.4.3}}
+\newlabel{worked_examples:fibre}{{4.3}{21}{Fibre Noise}{section.4.3}{}}
+\newlabel{worked_examples:fibre-noise}{{4.3}{21}{Fibre Noise}{section.4.3}{}}
+\@writefile{lof}{\contentsline {figure}{\numberline {4.1}{\ignorespaces The mean value of the real and imaginary components of the z variable for a single path of the simulation.}}{22}{figure.4.1}}
+\@writefile{lof}{\contentsline {figure}{\numberline {4.2}{\ignorespaces The mean and standard error of the z variable averaged over 10000 paths, as given by this simulation. It agrees within the standard error with the expected result of $\qopname  \relax o{exp}(-t/2)$.}}{22}{figure.4.2}}
+\@writefile{lof}{\contentsline {figure}{\numberline {4.3}{\ignorespaces The momentum space density of the field as a function of time for a single path realisation.}}{25}{figure.4.3}}
+\@writefile{toc}{\contentsline {section}{\numberline {4.4}Integer Dimensions}{25}{section.4.4}}
+\newlabel{worked_examples:integer-dimensions}{{4.4}{25}{Integer Dimensions}{section.4.4}{}}
+\newlabel{worked_examples:integerdimensionexample}{{4.4}{25}{Integer Dimensions}{section.4.4}{}}
+\@writefile{lof}{\contentsline {figure}{\numberline {4.4}{\ignorespaces The momentum space density of the field as a function of time for an average of 1024 paths.}}{26}{figure.4.4}}
+\@writefile{toc}{\contentsline {section}{\numberline {4.5}Wigner Function}{28}{section.4.5}}
+\newlabel{worked_examples:wigner-function}{{4.5}{28}{Wigner Function}{section.4.5}{}}
+\newlabel{worked_examples:wignerarguments}{{4.5}{28}{Wigner Function}{section.4.5}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {4.6}Finding the Ground State of a BEC (continuous renormalisation)}{31}{section.4.6}}
+\newlabel{worked_examples:groundstatebec}{{4.6}{31}{Finding the Ground State of a BEC (continuous renormalisation)}{section.4.6}{}}
+\newlabel{worked_examples:finding-the-ground-state-of-a-bec-continuous-renormalisation}{{4.6}{31}{Finding the Ground State of a BEC (continuous renormalisation)}{section.4.6}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {4.7}Finding the Ground State of a BEC again}{35}{section.4.7}}
+\newlabel{worked_examples:finding-the-ground-state-of-a-bec-again}{{4.7}{35}{Finding the Ground State of a BEC again}{section.4.7}{}}
+\newlabel{worked_examples:hermitegaussgroundstatebec}{{4.7}{35}{Finding the Ground State of a BEC again}{section.4.7}{}}
+\@writefile{lof}{\contentsline {figure}{\numberline {4.5}{\ignorespaces The shape of the ground state rapidly approaches the lowest eigenstate. For weak nonlinearities, it is nearly Gaussian.}}{36}{figure.4.5}}
+\@writefile{lof}{\contentsline {figure}{\numberline {4.6}{\ignorespaces When the nonlinear term is larger ($U=20$), the ground state is wider and more parabolic.}}{37}{figure.4.6}}
+\@writefile{toc}{\contentsline {section}{\numberline {4.8}Multi-component Schr\IeC {\"o}dinger equation}{39}{section.4.8}}
+\newlabel{worked_examples:dmultistatese}{{4.8}{39}{Multi-component Schrödinger equation}{section.4.8}{}}
+\newlabel{worked_examples:multi-component-schrodinger-equation}{{4.8}{39}{Multi-component Schrödinger equation}{section.4.8}{}}
+\@writefile{toc}{\contentsline {chapter}{\numberline {5}Reference section}{43}{chapter.5}}
+\@writefile{lof}{\addvspace {10\p@ }}
+\@writefile{lot}{\addvspace {10\p@ }}
+\newlabel{reference_index:reference-section}{{5}{43}{Reference section}{chapter.5}{}}
+\newlabel{reference_index::doc}{{5}{43}{Reference section}{chapter.5}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {5.1}Configuration, installation and runtime options}{43}{section.5.1}}
+\newlabel{reference_installation_and_configuration:referenceconfigurationinstallationruntime}{{5.1}{43}{Configuration, installation and runtime options}{section.5.1}{}}
+\newlabel{reference_installation_and_configuration::doc}{{5.1}{43}{Configuration, installation and runtime options}{section.5.1}{}}
+\newlabel{reference_installation_and_configuration:configuration-installation-and-runtime-options}{{5.1}{43}{Configuration, installation and runtime options}{section.5.1}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {5.2}Useful XML Syntax}{44}{section.5.2}}
+\newlabel{reference_usefulXMLSyntax::doc}{{5.2}{44}{Useful XML Syntax}{section.5.2}{}}
+\newlabel{reference_usefulXMLSyntax:referenceusefulxmlsyntax}{{5.2}{44}{Useful XML Syntax}{section.5.2}{}}
+\newlabel{reference_usefulXMLSyntax:useful-xml-syntax}{{5.2}{44}{Useful XML Syntax}{section.5.2}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {5.3}XMDS2 XML Schema}{44}{section.5.3}}
+\newlabel{reference_schema:xmds2-xml-schema}{{5.3}{44}{XMDS2 XML Schema}{section.5.3}{}}
+\newlabel{reference_schema::doc}{{5.3}{44}{XMDS2 XML Schema}{section.5.3}{}}
+\newlabel{reference_schema:referenceschema}{{5.3}{44}{XMDS2 XML Schema}{section.5.3}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {5.4}XMDS2 script elements}{46}{section.5.4}}
+\newlabel{reference_elements:xmds2-script-elements}{{5.4}{46}{XMDS2 script elements}{section.5.4}{}}
+\newlabel{reference_elements::doc}{{5.4}{46}{XMDS2 script elements}{section.5.4}{}}
+\newlabel{reference_elements:referenceelements}{{5.4}{46}{XMDS2 script elements}{section.5.4}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {5.4.1}Simulation element}{47}{subsection.5.4.1}}
+\newlabel{reference_elements:simulation-element}{{5.4.1}{47}{Simulation element}{subsection.5.4.1}{}}
+\newlabel{reference_elements:simulationelement}{{5.4.1}{47}{Simulation element}{subsection.5.4.1}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {5.4.2}Name element}{47}{subsection.5.4.2}}
+\newlabel{reference_elements:name-element}{{5.4.2}{47}{Name element}{subsection.5.4.2}{}}
+\newlabel{reference_elements:nameelement}{{5.4.2}{47}{Name element}{subsection.5.4.2}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {5.4.3}Author element}{47}{subsection.5.4.3}}
+\newlabel{reference_elements:author-element}{{5.4.3}{47}{Author element}{subsection.5.4.3}{}}
+\newlabel{reference_elements:authorelement}{{5.4.3}{47}{Author element}{subsection.5.4.3}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {5.4.4}Description element}{47}{subsection.5.4.4}}
+\newlabel{reference_elements:descriptionelement}{{5.4.4}{47}{Description element}{subsection.5.4.4}{}}
+\newlabel{reference_elements:description-element}{{5.4.4}{47}{Description element}{subsection.5.4.4}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {5.4.5}Features Elements}{47}{subsection.5.4.5}}
+\newlabel{reference_elements:features-elements}{{5.4.5}{47}{Features Elements}{subsection.5.4.5}{}}
+\newlabel{reference_elements:featureselement}{{5.4.5}{47}{Features Elements}{subsection.5.4.5}{}}
+\@writefile{toc}{\contentsline {subsubsection}{Arguments Element}{48}{subsubsection*.5}}
+\newlabel{reference_elements:argumentselement}{{5.4.5}{48}{Arguments Element}{subsubsection*.5}{}}
+\newlabel{reference_elements:arguments-element}{{5.4.5}{48}{Arguments Element}{subsubsection*.5}{}}
+\@writefile{toc}{\contentsline {paragraph}{Argument element}{49}{paragraph*.6}}
+\newlabel{reference_elements:argument-element}{{5.4.5}{49}{Argument element}{paragraph*.6}{}}
+\newlabel{reference_elements:argumentelement}{{5.4.5}{49}{Argument element}{paragraph*.6}{}}
+\@writefile{toc}{\contentsline {subsubsection}{Auto\_vectorise element}{49}{subsubsection*.7}}
+\newlabel{reference_elements:autovectorise}{{5.4.5}{49}{Auto\_vectorise element}{subsubsection*.7}{}}
+\newlabel{reference_elements:auto-vectorise-element}{{5.4.5}{49}{Auto\_vectorise element}{subsubsection*.7}{}}
+\@writefile{toc}{\contentsline {subsubsection}{Benchmark}{49}{subsubsection*.8}}
+\newlabel{reference_elements:benchmark}{{5.4.5}{49}{Benchmark}{subsubsection*.8}{}}
+\newlabel{reference_elements:id1}{{5.4.5}{49}{Benchmark}{subsubsection*.8}{}}
+\@writefile{toc}{\contentsline {subsubsection}{Bing}{49}{subsubsection*.9}}
+\newlabel{reference_elements:bing}{{5.4.5}{49}{Bing}{subsubsection*.9}{}}
+\newlabel{reference_elements:id2}{{5.4.5}{49}{Bing}{subsubsection*.9}{}}
+\@writefile{toc}{\contentsline {subsubsection}{C Flags}{49}{subsubsection*.10}}
+\newlabel{reference_elements:c-flags}{{5.4.5}{49}{C Flags}{subsubsection*.10}{}}
+\newlabel{reference_elements:cflags}{{5.4.5}{49}{C Flags}{subsubsection*.10}{}}
+\@writefile{toc}{\contentsline {subsubsection}{Chunked Output}{49}{subsubsection*.11}}
+\newlabel{reference_elements:chunked-output}{{5.4.5}{49}{Chunked Output}{subsubsection*.11}{}}
+\newlabel{reference_elements:chunkedoutput}{{5.4.5}{49}{Chunked Output}{subsubsection*.11}{}}
+\@writefile{toc}{\contentsline {subsubsection}{Diagnostics}{50}{subsubsection*.12}}
+\newlabel{reference_elements:id3}{{5.4.5}{50}{Diagnostics}{subsubsection*.12}{}}
+\newlabel{reference_elements:diagnostics}{{5.4.5}{50}{Diagnostics}{subsubsection*.12}{}}
+\@writefile{toc}{\contentsline {subsubsection}{Error Check}{50}{subsubsection*.13}}
+\newlabel{reference_elements:errorcheck}{{5.4.5}{50}{Error Check}{subsubsection*.13}{}}
+\newlabel{reference_elements:error-check}{{5.4.5}{50}{Error Check}{subsubsection*.13}{}}
+\@writefile{toc}{\contentsline {subsubsection}{Halt\_Non\_Finite}{50}{subsubsection*.14}}
+\newlabel{reference_elements:halt-non-finite}{{5.4.5}{50}{Halt\_Non\_Finite}{subsubsection*.14}{}}
+\newlabel{reference_elements:haltnonfinite}{{5.4.5}{50}{Halt\_Non\_Finite}{subsubsection*.14}{}}
+\@writefile{toc}{\contentsline {subsubsection}{fftw element}{50}{subsubsection*.15}}
+\newlabel{reference_elements:fftw}{{5.4.5}{50}{fftw element}{subsubsection*.15}{}}
+\newlabel{reference_elements:fftw-element}{{5.4.5}{50}{fftw element}{subsubsection*.15}{}}
+\@writefile{toc}{\contentsline {subsubsection}{Globals}{51}{subsubsection*.16}}
+\newlabel{reference_elements:id4}{{5.4.5}{51}{Globals}{subsubsection*.16}{}}
+\newlabel{reference_elements:globals}{{5.4.5}{51}{Globals}{subsubsection*.16}{}}
+\@writefile{toc}{\contentsline {subsubsection}{OpenMP}{51}{subsubsection*.17}}
+\newlabel{reference_elements:openmp}{{5.4.5}{51}{OpenMP}{subsubsection*.17}{}}
+\newlabel{reference_elements:id5}{{5.4.5}{51}{OpenMP}{subsubsection*.17}{}}
+\@writefile{toc}{\contentsline {subsubsection}{Precision}{51}{subsubsection*.18}}
+\newlabel{reference_elements:id6}{{5.4.5}{51}{Precision}{subsubsection*.18}{}}
+\newlabel{reference_elements:precision}{{5.4.5}{51}{Precision}{subsubsection*.18}{}}
+\@writefile{toc}{\contentsline {subsubsection}{Validation}{52}{subsubsection*.19}}
+\newlabel{reference_elements:id7}{{5.4.5}{52}{Validation}{subsubsection*.19}{}}
+\newlabel{reference_elements:validation}{{5.4.5}{52}{Validation}{subsubsection*.19}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {5.4.6}Driver Element}{52}{subsection.5.4.6}}
+\newlabel{reference_elements:driver-element}{{5.4.6}{52}{Driver Element}{subsection.5.4.6}{}}
+\newlabel{reference_elements:driverelement}{{5.4.6}{52}{Driver Element}{subsection.5.4.6}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {5.4.7}Geometry Element}{53}{subsection.5.4.7}}
+\newlabel{reference_elements:geometry-element}{{5.4.7}{53}{Geometry Element}{subsection.5.4.7}{}}
+\newlabel{reference_elements:geometryelement}{{5.4.7}{53}{Geometry Element}{subsection.5.4.7}{}}
+\newlabel{reference_elements:propagationdimensionelement}{{5.4.7}{53}{Geometry Element}{section*.20}{}}
+\newlabel{reference_elements:transversedimensionselement}{{5.4.7}{53}{Geometry Element}{section*.21}{}}
+\newlabel{reference_elements:dimensionelement}{{5.4.7}{53}{Geometry Element}{section*.22}{}}
+\newlabel{reference_elements:transforms}{{5.4.7}{53}{Geometry Element}{section*.23}{}}
+\@writefile{toc}{\contentsline {subsubsection}{The ``dft'' transform}{54}{subsubsection*.24}}
+\newlabel{reference_elements:dft-transform}{{5.4.7}{54}{The ``dft'' transform}{subsubsection*.24}{}}
+\newlabel{reference_elements:the-dft-transform}{{5.4.7}{54}{The ``dft'' transform}{subsubsection*.24}{}}
+\@writefile{toc}{\contentsline {subsubsection}{The ``dct'' transform}{55}{subsubsection*.25}}
+\newlabel{reference_elements:the-dct-transform}{{5.4.7}{55}{The ``dct'' transform}{subsubsection*.25}{}}
+\@writefile{toc}{\contentsline {subsubsection}{The ``dst'' transform}{55}{subsubsection*.26}}
+\newlabel{reference_elements:the-dst-transform}{{5.4.7}{55}{The ``dst'' transform}{subsubsection*.26}{}}
+\@writefile{toc}{\contentsline {subsubsection}{The ``bessel'' transform}{56}{subsubsection*.27}}
+\newlabel{reference_elements:the-bessel-transform}{{5.4.7}{56}{The ``bessel'' transform}{subsubsection*.27}{}}
+\newlabel{reference_elements:besseltransform}{{5.4.7}{56}{The ``bessel'' transform}{subsubsection*.27}{}}
+\@writefile{toc}{\contentsline {subsubsection}{The ``spherical-bessel'' transform}{57}{subsubsection*.28}}
+\newlabel{reference_elements:the-spherical-bessel-transform}{{5.4.7}{57}{The ``spherical-bessel'' transform}{subsubsection*.28}{}}
+\@writefile{toc}{\contentsline {subsubsection}{The ``hermite-gauss'' transform}{58}{subsubsection*.29}}
+\newlabel{reference_elements:the-hermite-gauss-transform}{{5.4.7}{58}{The ``hermite-gauss'' transform}{subsubsection*.29}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {5.4.8}Vector Element}{59}{subsection.5.4.8}}
+\newlabel{reference_elements:vector-element}{{5.4.8}{59}{Vector Element}{subsection.5.4.8}{}}
+\newlabel{reference_elements:vectorelement}{{5.4.8}{59}{Vector Element}{subsection.5.4.8}{}}
+\newlabel{reference_elements:componentselement}{{5.4.8}{59}{Vector Element}{section*.30}{}}
+\newlabel{reference_elements:initialisationelement}{{5.4.8}{59}{Vector Element}{section*.31}{}}
+\newlabel{reference_elements:referencingnonlocal}{{5.4.8}{59}{Vector Element}{section*.32}{}}
+\newlabel{reference_elements:filenameelement}{{5.4.8}{60}{Vector Element}{section*.33}{}}
+\@writefile{toc}{\contentsline {subsubsection}{The dependencies element}{60}{subsubsection*.34}}
+\newlabel{reference_elements:the-dependencies-element}{{5.4.8}{60}{The dependencies element}{subsubsection*.34}{}}
+\newlabel{reference_elements:dependencies}{{5.4.8}{60}{The dependencies element}{subsubsection*.34}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {5.4.9}Computed Vector Element}{61}{subsection.5.4.9}}
+\newlabel{reference_elements:computedvectorelement}{{5.4.9}{61}{Computed Vector Element}{subsection.5.4.9}{}}
+\newlabel{reference_elements:computed-vector-element}{{5.4.9}{61}{Computed Vector Element}{subsection.5.4.9}{}}
+\newlabel{reference_elements:evaluationelement}{{5.4.9}{61}{Computed Vector Element}{section*.35}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {5.4.10}Noise Vector Element}{62}{subsection.5.4.10}}
+\newlabel{reference_elements:noise-vector-element}{{5.4.10}{62}{Noise Vector Element}{subsection.5.4.10}{}}
+\newlabel{reference_elements:noisevectorelement}{{5.4.10}{62}{Noise Vector Element}{subsection.5.4.10}{}}
+\@writefile{toc}{\contentsline {subsubsection}{Uniform noise}{63}{subsubsection*.36}}
+\newlabel{reference_elements:uniformnoise}{{5.4.10}{63}{Uniform noise}{subsubsection*.36}{}}
+\newlabel{reference_elements:uniform-noise}{{5.4.10}{63}{Uniform noise}{subsubsection*.36}{}}
+\@writefile{toc}{\contentsline {subsubsection}{Gaussian noise}{63}{subsubsection*.37}}
+\newlabel{reference_elements:gaussiannoise}{{5.4.10}{63}{Gaussian noise}{subsubsection*.37}{}}
+\newlabel{reference_elements:gaussian-noise}{{5.4.10}{63}{Gaussian noise}{subsubsection*.37}{}}
+\@writefile{toc}{\contentsline {subsubsection}{Wiener noise}{64}{subsubsection*.38}}
+\newlabel{reference_elements:wienernoise}{{5.4.10}{64}{Wiener noise}{subsubsection*.38}{}}
+\newlabel{reference_elements:wiener-noise}{{5.4.10}{64}{Wiener noise}{subsubsection*.38}{}}
+\@writefile{toc}{\contentsline {subsubsection}{Poissonian noise}{64}{subsubsection*.39}}
+\newlabel{reference_elements:poissioniannoise}{{5.4.10}{64}{Poissonian noise}{subsubsection*.39}{}}
+\newlabel{reference_elements:poissonian-noise}{{5.4.10}{64}{Poissonian noise}{subsubsection*.39}{}}
+\@writefile{toc}{\contentsline {subsubsection}{Jump noise}{64}{subsubsection*.40}}
+\newlabel{reference_elements:jumpnoise}{{5.4.10}{64}{Jump noise}{subsubsection*.40}{}}
+\newlabel{reference_elements:jump-noise}{{5.4.10}{64}{Jump noise}{subsubsection*.40}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {5.4.11}Sequence Element}{65}{subsection.5.4.11}}
+\newlabel{reference_elements:sequence-element}{{5.4.11}{65}{Sequence Element}{subsection.5.4.11}{}}
+\newlabel{reference_elements:sequenceelement}{{5.4.11}{65}{Sequence Element}{subsection.5.4.11}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {5.4.12}Filter element}{65}{subsection.5.4.12}}
+\newlabel{reference_elements:filterelement}{{5.4.12}{65}{Filter element}{subsection.5.4.12}{}}
+\newlabel{reference_elements:filter-element}{{5.4.12}{65}{Filter element}{subsection.5.4.12}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {5.4.13}Integrate element}{66}{subsection.5.4.13}}
+\newlabel{reference_elements:integrate-element}{{5.4.13}{66}{Integrate element}{subsection.5.4.13}{}}
+\newlabel{reference_elements:integrateelement}{{5.4.13}{66}{Integrate element}{subsection.5.4.13}{}}
+\newlabel{reference_elements:sampleselement}{{5.4.13}{66}{Integrate element}{section*.41}{}}
+\@writefile{toc}{\contentsline {subsubsection}{Operators and operator elements}{67}{subsubsection*.42}}
+\newlabel{reference_elements:operatorselement}{{5.4.13}{67}{Operators and operator elements}{subsubsection*.42}{}}
+\newlabel{reference_elements:operators-and-operator-elements}{{5.4.13}{67}{Operators and operator elements}{subsubsection*.42}{}}
+\newlabel{reference_elements:integrationvectorselement}{{5.4.13}{67}{Operators and operator elements}{section*.43}{}}
+\newlabel{reference_elements:operatorelement}{{5.4.13}{67}{Operators and operator elements}{section*.44}{}}
+\newlabel{reference_elements:operatornameselement}{{5.4.13}{67}{Operators and operator elements}{section*.45}{}}
+\newlabel{reference_elements:boundaryconditionelement}{{5.4.13}{68}{Operators and operator elements}{section*.46}{}}
+\@writefile{toc}{\contentsline {subsubsection}{Algorithms}{68}{subsubsection*.47}}
+\newlabel{reference_elements:algorithms}{{5.4.13}{68}{Algorithms}{subsubsection*.47}{}}
+\newlabel{reference_elements:id8}{{5.4.13}{68}{Algorithms}{subsubsection*.47}{}}
+\@writefile{toc}{\contentsline {paragraph}{SI and SIC algorithms}{69}{paragraph*.48}}
+\newlabel{reference_elements:si}{{5.4.13}{69}{SI and SIC algorithms}{paragraph*.48}{}}
+\newlabel{reference_elements:si-and-sic-algorithms}{{5.4.13}{69}{SI and SIC algorithms}{paragraph*.48}{}}
+\@writefile{toc}{\contentsline {paragraph}{Runge-Kutta algorithms}{69}{paragraph*.49}}
+\newlabel{reference_elements:rk4}{{5.4.13}{69}{Runge-Kutta algorithms}{paragraph*.49}{}}
+\newlabel{reference_elements:runge-kutta-algorithms}{{5.4.13}{69}{Runge-Kutta algorithms}{paragraph*.49}{}}
+\@writefile{toc}{\contentsline {paragraph}{Adaptive Runge-Kutta algorithms}{69}{paragraph*.50}}
+\newlabel{reference_elements:adaptive-runge-kutta-algorithms}{{5.4.13}{69}{Adaptive Runge-Kutta algorithms}{paragraph*.50}{}}
+\newlabel{reference_elements:ark45}{{5.4.13}{69}{Adaptive Runge-Kutta algorithms}{paragraph*.50}{}}
+\@writefile{toc}{\contentsline {subsubsection}{Filters element}{70}{subsubsection*.51}}
+\newlabel{reference_elements:filterselement}{{5.4.13}{70}{Filters element}{subsubsection*.51}{}}
+\newlabel{reference_elements:filters-element}{{5.4.13}{70}{Filters element}{subsubsection*.51}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {5.4.14}Breakpoint element}{70}{subsection.5.4.14}}
+\newlabel{reference_elements:breakpoint-element}{{5.4.14}{70}{Breakpoint element}{subsection.5.4.14}{}}
+\newlabel{reference_elements:breakpointelement}{{5.4.14}{70}{Breakpoint element}{subsection.5.4.14}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {5.4.15}Output element}{71}{subsection.5.4.15}}
+\newlabel{reference_elements:outputelement}{{5.4.15}{71}{Output element}{subsection.5.4.15}{}}
+\newlabel{reference_elements:output-element}{{5.4.15}{71}{Output element}{subsection.5.4.15}{}}
+\@writefile{toc}{\contentsline {subsubsection}{Sampling Group Element}{71}{subsubsection*.52}}
+\newlabel{reference_elements:samplinggroupelement}{{5.4.15}{71}{Sampling Group Element}{subsubsection*.52}{}}
+\newlabel{reference_elements:sampling-group-element}{{5.4.15}{71}{Sampling Group Element}{subsubsection*.52}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {5.4.16}XMDS-specific C syntax}{72}{subsection.5.4.16}}
+\newlabel{reference_elements:xmds-specific-c-syntax}{{5.4.16}{72}{XMDS-specific C syntax}{subsection.5.4.16}{}}
+\newlabel{reference_elements:xmdscsyntax}{{5.4.16}{72}{XMDS-specific C syntax}{subsection.5.4.16}{}}
+\@writefile{toc}{\contentsline {chapter}{\numberline {6}Advanced Topics}{73}{chapter.6}}
+\@writefile{lof}{\addvspace {10\p@ }}
+\@writefile{lot}{\addvspace {10\p@ }}
+\newlabel{advanced_topics:advancedtopics}{{6}{73}{Advanced Topics}{chapter.6}{}}
+\newlabel{advanced_topics:advanced-topics}{{6}{73}{Advanced Topics}{chapter.6}{}}
+\newlabel{advanced_topics::doc}{{6}{73}{Advanced Topics}{chapter.6}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {6.1}Importing data}{73}{section.6.1}}
+\newlabel{advanced_topics:importing}{{6.1}{73}{Importing data}{section.6.1}{}}
+\newlabel{advanced_topics:importing-data}{{6.1}{73}{Importing data}{section.6.1}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {6.2}Convolutions and Fourier transforms}{75}{section.6.2}}
+\newlabel{advanced_topics:convolutions-and-fourier-transforms}{{6.2}{75}{Convolutions and Fourier transforms}{section.6.2}{}}
+\newlabel{advanced_topics:convolutions}{{6.2}{75}{Convolutions and Fourier transforms}{section.6.2}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {6.2.1}Example 1}{76}{subsection.6.2.1}}
+\newlabel{advanced_topics:example-1}{{6.2.1}{76}{Example 1}{subsection.6.2.1}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {6.2.2}Example 2}{77}{subsection.6.2.2}}
+\newlabel{advanced_topics:example-2}{{6.2.2}{77}{Example 2}{subsection.6.2.2}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {6.2.3}Example 3}{77}{subsection.6.2.3}}
+\newlabel{advanced_topics:example-3}{{6.2.3}{77}{Example 3}{subsection.6.2.3}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {6.3}`Loose' \texttt  {geometry\_matching\_mode}}{78}{section.6.3}}
+\newlabel{advanced_topics:loosegeometrymatchingmode}{{6.3}{78}{`Loose' \texttt {geometry\_matching\_mode}}{section.6.3}{}}
+\newlabel{advanced_topics:loose-geometry-matching-mode}{{6.3}{78}{`Loose' \texttt {geometry\_matching\_mode}}{section.6.3}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {6.4}Dimension aliases}{78}{section.6.4}}
+\newlabel{advanced_topics:dimension-aliases}{{6.4}{78}{Dimension aliases}{section.6.4}{}}
+\newlabel{advanced_topics:dimensionaliases}{{6.4}{78}{Dimension aliases}{section.6.4}{}}
+\@writefile{toc}{\contentsline {chapter}{\numberline {7}Frequently Asked Questions}{79}{chapter.7}}
+\@writefile{lof}{\addvspace {10\p@ }}
+\@writefile{lot}{\addvspace {10\p@ }}
+\newlabel{faq:faq}{{7}{79}{Frequently Asked Questions}{chapter.7}{}}
+\newlabel{faq::doc}{{7}{79}{Frequently Asked Questions}{chapter.7}{}}
+\newlabel{faq:frequently-asked-questions}{{7}{79}{Frequently Asked Questions}{chapter.7}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {7.1}XMDS scripts look complicated! How do I start?}{79}{section.7.1}}
+\newlabel{faq:xmds-scripts-look-complicated-how-do-i-start}{{7.1}{79}{XMDS scripts look complicated! How do I start?}{section.7.1}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {7.2}Where can I get help?}{79}{section.7.2}}
+\newlabel{faq:where-can-i-get-help}{{7.2}{79}{Where can I get help?}{section.7.2}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {7.3}How should I cite XMDS2?}{79}{section.7.3}}
+\newlabel{faq:how-should-i-cite-xmds2}{{7.3}{79}{How should I cite XMDS2?}{section.7.3}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {7.4}I think I found a bug! Where should I report it?}{79}{section.7.4}}
+\newlabel{faq:i-think-i-found-a-bug-where-should-i-report-it}{{7.4}{79}{I think I found a bug! Where should I report it?}{section.7.4}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {7.5}How do I put time dependence into my vectors?}{79}{section.7.5}}
+\newlabel{faq:how-do-i-put-time-dependence-into-my-vectors}{{7.5}{79}{How do I put time dependence into my vectors?}{section.7.5}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {7.6}Can I specify the range of my domain and number of grid points at run-time?}{80}{section.7.6}}
+\newlabel{faq:can-i-specify-the-range-of-my-domain-and-number-of-grid-points-at-run-time}{{7.6}{80}{Can I specify the range of my domain and number of grid points at run-time?}{section.7.6}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {7.7}When can I use IP operators (and why should I) and when must I use EX operators?}{80}{section.7.7}}
+\newlabel{faq:when-can-i-use-ip-operators-and-why-should-i-and-when-must-i-use-ex-operators}{{7.7}{80}{When can I use IP operators (and why should I) and when must I use EX operators?}{section.7.7}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {7.8}Visual Editors}{80}{section.7.8}}
+\newlabel{faq:visual-editors}{{7.8}{80}{Visual Editors}{section.7.8}{}}
+\@writefile{toc}{\contentsline {chapter}{\numberline {8}Upgrading From XMDS 1.X}{81}{chapter.8}}
+\@writefile{lof}{\addvspace {10\p@ }}
+\@writefile{lot}{\addvspace {10\p@ }}
+\newlabel{upgrade:upgradefromxmds1}{{8}{81}{Upgrading From XMDS 1.X}{chapter.8}{}}
+\newlabel{upgrade::doc}{{8}{81}{Upgrading From XMDS 1.X}{chapter.8}{}}
+\newlabel{upgrade:upgrading-from-xmds-1-x}{{8}{81}{Upgrading From XMDS 1.X}{chapter.8}{}}
+\@writefile{toc}{\contentsline {chapter}{\numberline {9}Optimisation Hints}{83}{chapter.9}}
+\@writefile{lof}{\addvspace {10\p@ }}
+\@writefile{lot}{\addvspace {10\p@ }}
+\newlabel{optimisation_hints::doc}{{9}{83}{Optimisation Hints}{chapter.9}{}}
+\newlabel{optimisation_hints:optimisation-hints}{{9}{83}{Optimisation Hints}{chapter.9}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {9.1}Geometry and transform-based tricks}{83}{section.9.1}}
+\newlabel{optimisation_hints:geometry-and-transform-based-tricks}{{9.1}{83}{Geometry and transform-based tricks}{section.9.1}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {9.1.1}Simpler simulation geometries}{83}{subsection.9.1.1}}
+\newlabel{optimisation_hints:simpler-simulation-geometries}{{9.1.1}{83}{Simpler simulation geometries}{subsection.9.1.1}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {9.1.2}Tricks for Bessel and Hermite-Gauss transforms}{83}{subsection.9.1.2}}
+\newlabel{optimisation_hints:tricks-for-bessel-and-hermite-gauss-transforms}{{9.1.2}{83}{Tricks for Bessel and Hermite-Gauss transforms}{subsection.9.1.2}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {9.2}Reduce code complexity}{83}{section.9.2}}
+\newlabel{optimisation_hints:reduce-code-complexity}{{9.2}{83}{Reduce code complexity}{section.9.2}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {9.2.1}Use the Interaction Picture (IP) operator}{83}{subsection.9.2.1}}
+\newlabel{optimisation_hints:use-the-interaction-picture-ip-operator}{{9.2.1}{83}{Use the Interaction Picture (IP) operator}{subsection.9.2.1}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {9.2.2}Consider writing the evolution in spectral basis}{83}{subsection.9.2.2}}
+\newlabel{optimisation_hints:consider-writing-the-evolution-in-spectral-basis}{{9.2.2}{83}{Consider writing the evolution in spectral basis}{subsection.9.2.2}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {9.2.3}Don't recalculate things you don't have to}{85}{subsection.9.2.3}}
+\newlabel{optimisation_hints:don-t-recalculate-things-you-don-t-have-to}{{9.2.3}{85}{Don't recalculate things you don't have to}{subsection.9.2.3}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {9.3}Compiler and library tricks}{85}{section.9.3}}
+\newlabel{optimisation_hints:compiler-and-library-tricks}{{9.3}{85}{Compiler and library tricks}{section.9.3}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {9.3.1}Faster compiler}{85}{subsection.9.3.1}}
+\newlabel{optimisation_hints:faster-compiler}{{9.3.1}{85}{Faster compiler}{subsection.9.3.1}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {9.3.2}Faster libraries}{85}{subsection.9.3.2}}
+\newlabel{optimisation_hints:faster-libraries}{{9.3.2}{85}{Faster libraries}{subsection.9.3.2}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {9.3.3}Auto-vectorisation}{85}{subsection.9.3.3}}
+\newlabel{optimisation_hints:auto-vectorisation}{{9.3.3}{85}{Auto-vectorisation}{subsection.9.3.3}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {9.3.4}OpenMP}{85}{subsection.9.3.4}}
+\newlabel{optimisation_hints:openmp}{{9.3.4}{85}{OpenMP}{subsection.9.3.4}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {9.3.5}Parallelisation with MPI}{86}{subsection.9.3.5}}
+\newlabel{optimisation_hints:parallelisation-with-mpi}{{9.3.5}{86}{Parallelisation with MPI}{subsection.9.3.5}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {9.4}Atom-optics-specific hints}{86}{section.9.4}}
+\newlabel{optimisation_hints:atom-optics-specific-hints}{{9.4}{86}{Atom-optics-specific hints}{section.9.4}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {9.4.1}Separate out imaginary-time calculation code}{86}{subsection.9.4.1}}
+\newlabel{optimisation_hints:separate-out-imaginary-time-calculation-code}{{9.4.1}{86}{Separate out imaginary-time calculation code}{subsection.9.4.1}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {9.4.2}Use an energy or momentum offset}{86}{subsection.9.4.2}}
+\newlabel{optimisation_hints:use-an-energy-or-momentum-offset}{{9.4.2}{86}{Use an energy or momentum offset}{subsection.9.4.2}{}}
+\@writefile{toc}{\contentsline {chapter}{\numberline {10}xsil2graphics2}{87}{chapter.10}}
+\@writefile{lof}{\addvspace {10\p@ }}
+\@writefile{lot}{\addvspace {10\p@ }}
+\newlabel{xsil2graphics2:xsil2graphics2}{{10}{87}{xsil2graphics2}{chapter.10}{}}
+\newlabel{xsil2graphics2::doc}{{10}{87}{xsil2graphics2}{chapter.10}{}}
+\newlabel{xsil2graphics2:id1}{{10}{87}{xsil2graphics2}{chapter.10}{}}
+\@writefile{toc}{\contentsline {chapter}{\numberline {11}Developer Documentation}{89}{chapter.11}}
+\@writefile{lof}{\addvspace {10\p@ }}
+\@writefile{lot}{\addvspace {10\p@ }}
+\newlabel{developer:developer-documentation}{{11}{89}{Developer Documentation}{chapter.11}{}}
+\newlabel{developer::doc}{{11}{89}{Developer Documentation}{chapter.11}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {11.1}Test scripts}{89}{section.11.1}}
+\newlabel{developer:test-scripts}{{11.1}{89}{Test scripts}{section.11.1}{}}
+\newlabel{developer:testscripts}{{11.1}{89}{Test scripts}{section.11.1}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {11.1.1}Testing element}{90}{subsection.11.1.1}}
+\newlabel{developer:testing-element}{{11.1.1}{90}{Testing element}{subsection.11.1.1}{}}
+\newlabel{developer:testingelement}{{11.1.1}{90}{Testing element}{subsection.11.1.1}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {11.1.2}command\_line element}{90}{subsection.11.1.2}}
+\newlabel{developer:commandlineelement}{{11.1.2}{90}{command\_line element}{subsection.11.1.2}{}}
+\newlabel{developer:command-line-element}{{11.1.2}{90}{command\_line element}{subsection.11.1.2}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {11.1.3}input\_xsil\_file element}{90}{subsection.11.1.3}}
+\newlabel{developer:input-xsil-file-element}{{11.1.3}{90}{input\_xsil\_file element}{subsection.11.1.3}{}}
+\newlabel{developer:inputxsilfileelement}{{11.1.3}{90}{input\_xsil\_file element}{subsection.11.1.3}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {11.1.4}xsil\_file element}{90}{subsection.11.1.4}}
+\newlabel{developer:xsilfileelement}{{11.1.4}{90}{xsil\_file element}{subsection.11.1.4}{}}
+\newlabel{developer:xsil-file-element}{{11.1.4}{90}{xsil\_file element}{subsection.11.1.4}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {11.1.5}moment\_group element}{90}{subsection.11.1.5}}
+\newlabel{developer:momentgroupelement}{{11.1.5}{90}{moment\_group element}{subsection.11.1.5}{}}
+\newlabel{developer:moment-group-element}{{11.1.5}{90}{moment\_group element}{subsection.11.1.5}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {11.2}Steps to update \texttt  {XMDS} script validator (XML schema)}{90}{section.11.2}}
+\newlabel{developer:steps-to-update-xmds-script-validator-xml-schema}{{11.2}{90}{Steps to update \texttt {XMDS} script validator (XML schema)}{section.11.2}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {11.3}Directory layout}{90}{section.11.3}}
+\newlabel{developer:directory-layout}{{11.3}{90}{Directory layout}{section.11.3}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {11.3.1}XMDS2's code and templates}{90}{subsection.11.3.1}}
+\newlabel{developer:xmds2-s-code-and-templates}{{11.3.1}{90}{XMDS2's code and templates}{subsection.11.3.1}{}}
+\@writefile{toc}{\contentsline {subsection}{\numberline {11.3.2}Support files}{91}{subsection.11.3.2}}
+\newlabel{developer:support-files}{{11.3.2}{91}{Support files}{subsection.11.3.2}{}}
+\@writefile{toc}{\contentsline {chapter}{\numberline {12}Licensing}{93}{chapter.12}}
+\@writefile{lof}{\addvspace {10\p@ }}
+\@writefile{lot}{\addvspace {10\p@ }}
+\newlabel{licensing::doc}{{12}{93}{Licensing}{chapter.12}{}}
+\newlabel{licensing:licensing}{{12}{93}{Licensing}{chapter.12}{}}
+\newlabel{licensing:id1}{{12}{93}{Licensing}{chapter.12}{}}
+\@writefile{toc}{\contentsline {chapter}{\numberline {13}News}{95}{chapter.13}}
+\@writefile{lof}{\addvspace {10\p@ }}
+\@writefile{lot}{\addvspace {10\p@ }}
+\newlabel{news:news}{{13}{95}{News}{chapter.13}{}}
+\newlabel{news::doc}{{13}{95}{News}{chapter.13}{}}
+\newlabel{news:id1}{{13}{95}{News}{chapter.13}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {13.1}XMDS 2.1.4 ``Well if this isn't nice, I don't know what is'' (September 27, 2013)}{95}{section.13.1}}
+\newlabel{news:xmds-2-1-4-well-if-this-isn-t-nice-i-don-t-know-what-is-september-27-2013}{{13.1}{95}{XMDS 2.1.4 ``Well if this isn't nice, I don't know what is'' (September 27, 2013)}{section.13.1}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {13.2}XMDS 2.1.3 ``Happy Mollusc'' (June 7, 2013)}{95}{section.13.2}}
+\newlabel{news:xmds-2-1-3-happy-mollusc-june-7-2013}{{13.2}{95}{XMDS 2.1.3 ``Happy Mollusc'' (June 7, 2013)}{section.13.2}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {13.3}XMDS 2.1.2 ``Happy Mollusc'' (October 15, 2012)}{95}{section.13.3}}
+\newlabel{news:xmds-2-1-2-happy-mollusc-october-15-2012}{{13.3}{95}{XMDS 2.1.2 ``Happy Mollusc'' (October 15, 2012)}{section.13.3}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {13.4}XMDS 2.1 ``Happy Mollusc'' (June 14, 2012)}{96}{section.13.4}}
+\newlabel{news:xmds-2-1-happy-mollusc-june-14-2012}{{13.4}{96}{XMDS 2.1 ``Happy Mollusc'' (June 14, 2012)}{section.13.4}{}}
+\@writefile{toc}{\contentsline {section}{\numberline {13.5}XMDS 2.0 ``Shiny!'' (September 13, 2010)}{97}{section.13.5}}
+\newlabel{news:xmds-2-0-shiny-september-13-2010}{{13.5}{97}{XMDS 2.0 ``Shiny!'' (September 13, 2010)}{section.13.5}{}}
diff --git a/documentation/latex/xmds2.idx b/documentation/latex/xmds2.idx
new file mode 100644
index 0000000..e69de29
diff --git a/documentation/latex/xmds2.ilg b/documentation/latex/xmds2.ilg
new file mode 100644
index 0000000..c56dd8d
--- /dev/null
+++ b/documentation/latex/xmds2.ilg
@@ -0,0 +1,5 @@
+This is makeindex, version 2.15 [TeX Live 2012] (kpathsea + Thai support).
+Scanning style file ./python.ist......done (6 attributes redefined, 0 ignored).
+Scanning input file xmds2.idx...done (0 entries accepted, 0 rejected).
+Nothing written in xmds2.ind.
+Transcript written in xmds2.ilg.
diff --git a/documentation/latex/xmds2.ind b/documentation/latex/xmds2.ind
new file mode 100644
index 0000000..e69de29
diff --git a/documentation/latex/xmds2.log b/documentation/latex/xmds2.log
new file mode 100644
index 0000000..a7589f5
--- /dev/null
+++ b/documentation/latex/xmds2.log
@@ -0,0 +1,1333 @@
+This is pdfTeX, Version 3.1415926-2.4-1.40.13 (TeX Live 2012) (format=pdflatex 2013.4.1)  28 SEP 2013 09:00
+entering extended mode
+ restricted \write18 enabled.
+ %&-line parsing enabled.
+**xmds2.tex
+(./xmds2.tex
+LaTeX2e <2011/06/27>
+Babel <v3.8m> and hyphenation patterns for english, dumylang, nohyphenation, ge
+rman-x-2012-05-30, ngerman-x-2012-05-30, afrikaans, ancientgreek, ibycus, arabi
+c, armenian, basque, bulgarian, catalan, pinyin, coptic, croatian, czech, danis
+h, dutch, ukenglish, usenglishmax, esperanto, estonian, ethiopic, farsi, finnis
+h, french, friulan, galician, german, ngerman, swissgerman, monogreek, greek, h
+ungarian, icelandic, assamese, bengali, gujarati, hindi, kannada, malayalam, ma
+rathi, oriya, panjabi, tamil, telugu, indonesian, interlingua, irish, italian, 
+kurmanji, latin, latvian, lithuanian, mongolian, mongolianlmc, bokmal, nynorsk,
+ piedmontese, polish, portuguese, romanian, romansh, russian, sanskrit, serbian
+, serbianc, slovak, slovenian, spanish, swedish, turkish, turkmen, ukrainian, u
+ppersorbian, welsh, loaded.
+(./sphinxmanual.cls
+Document Class: sphinxmanual 2009/06/02 Document class (Sphinx manual)
+(/usr/local/texlive/2012/texmf-dist/tex/latex/base/report.cls
+Document Class: report 2007/10/19 v1.4h Standard LaTeX document class
+(/usr/local/texlive/2012/texmf-dist/tex/latex/base/size10.clo
+File: size10.clo 2007/10/19 v1.4h Standard LaTeX file (size option)
+)
+\c at part=\count79
+\c at chapter=\count80
+\c at section=\count81
+\c at subsection=\count82
+\c at subsubsection=\count83
+\c at paragraph=\count84
+\c at subparagraph=\count85
+\c at figure=\count86
+\c at table=\count87
+\abovecaptionskip=\skip41
+\belowcaptionskip=\skip42
+\bibindent=\dimen102
+))
+(/usr/local/texlive/2012/texmf-dist/tex/latex/base/inputenc.sty
+Package: inputenc 2008/03/30 v1.1d Input encoding file
+\inpenc at prehook=\toks14
+\inpenc at posthook=\toks15
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/base/utf8.def
+File: utf8.def 2008/04/05 v1.1m UTF-8 support for inputenc
+Now handling font encoding OML ...
+... no UTF-8 mapping file for font encoding OML
+Now handling font encoding T1 ...
+... processing UTF-8 mapping file for font encoding T1
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/base/t1enc.dfu
+File: t1enc.dfu 2008/04/05 v1.1m UTF-8 support for inputenc
+   defining Unicode char U+00A1 (decimal 161)
+   defining Unicode char U+00A3 (decimal 163)
+   defining Unicode char U+00AB (decimal 171)
+   defining Unicode char U+00BB (decimal 187)
+   defining Unicode char U+00BF (decimal 191)
+   defining Unicode char U+00C0 (decimal 192)
+   defining Unicode char U+00C1 (decimal 193)
+   defining Unicode char U+00C2 (decimal 194)
+   defining Unicode char U+00C3 (decimal 195)
+   defining Unicode char U+00C4 (decimal 196)
+   defining Unicode char U+00C5 (decimal 197)
+   defining Unicode char U+00C6 (decimal 198)
+   defining Unicode char U+00C7 (decimal 199)
+   defining Unicode char U+00C8 (decimal 200)
+   defining Unicode char U+00C9 (decimal 201)
+   defining Unicode char U+00CA (decimal 202)
+   defining Unicode char U+00CB (decimal 203)
+   defining Unicode char U+00CC (decimal 204)
+   defining Unicode char U+00CD (decimal 205)
+   defining Unicode char U+00CE (decimal 206)
+   defining Unicode char U+00CF (decimal 207)
+   defining Unicode char U+00D0 (decimal 208)
+   defining Unicode char U+00D1 (decimal 209)
+   defining Unicode char U+00D2 (decimal 210)
+   defining Unicode char U+00D3 (decimal 211)
+   defining Unicode char U+00D4 (decimal 212)
+   defining Unicode char U+00D5 (decimal 213)
+   defining Unicode char U+00D6 (decimal 214)
+   defining Unicode char U+00D8 (decimal 216)
+   defining Unicode char U+00D9 (decimal 217)
+   defining Unicode char U+00DA (decimal 218)
+   defining Unicode char U+00DB (decimal 219)
+   defining Unicode char U+00DC (decimal 220)
+   defining Unicode char U+00DD (decimal 221)
+   defining Unicode char U+00DE (decimal 222)
+   defining Unicode char U+00DF (decimal 223)
+   defining Unicode char U+00E0 (decimal 224)
+   defining Unicode char U+00E1 (decimal 225)
+   defining Unicode char U+00E2 (decimal 226)
+   defining Unicode char U+00E3 (decimal 227)
+   defining Unicode char U+00E4 (decimal 228)
+   defining Unicode char U+00E5 (decimal 229)
+   defining Unicode char U+00E6 (decimal 230)
+   defining Unicode char U+00E7 (decimal 231)
+   defining Unicode char U+00E8 (decimal 232)
+   defining Unicode char U+00E9 (decimal 233)
+   defining Unicode char U+00EA (decimal 234)
+   defining Unicode char U+00EB (decimal 235)
+   defining Unicode char U+00EC (decimal 236)
+   defining Unicode char U+00ED (decimal 237)
+   defining Unicode char U+00EE (decimal 238)
+   defining Unicode char U+00EF (decimal 239)
+   defining Unicode char U+00F0 (decimal 240)
+   defining Unicode char U+00F1 (decimal 241)
+   defining Unicode char U+00F2 (decimal 242)
+   defining Unicode char U+00F3 (decimal 243)
+   defining Unicode char U+00F4 (decimal 244)
+   defining Unicode char U+00F5 (decimal 245)
+   defining Unicode char U+00F6 (decimal 246)
+   defining Unicode char U+00F8 (decimal 248)
+   defining Unicode char U+00F9 (decimal 249)
+   defining Unicode char U+00FA (decimal 250)
+   defining Unicode char U+00FB (decimal 251)
+   defining Unicode char U+00FC (decimal 252)
+   defining Unicode char U+00FD (decimal 253)
+   defining Unicode char U+00FE (decimal 254)
+   defining Unicode char U+00FF (decimal 255)
+   defining Unicode char U+0102 (decimal 258)
+   defining Unicode char U+0103 (decimal 259)
+   defining Unicode char U+0104 (decimal 260)
+   defining Unicode char U+0105 (decimal 261)
+   defining Unicode char U+0106 (decimal 262)
+   defining Unicode char U+0107 (decimal 263)
+   defining Unicode char U+010C (decimal 268)
+   defining Unicode char U+010D (decimal 269)
+   defining Unicode char U+010E (decimal 270)
+   defining Unicode char U+010F (decimal 271)
+   defining Unicode char U+0110 (decimal 272)
+   defining Unicode char U+0111 (decimal 273)
+   defining Unicode char U+0118 (decimal 280)
+   defining Unicode char U+0119 (decimal 281)
+   defining Unicode char U+011A (decimal 282)
+   defining Unicode char U+011B (decimal 283)
+   defining Unicode char U+011E (decimal 286)
+   defining Unicode char U+011F (decimal 287)
+   defining Unicode char U+0130 (decimal 304)
+   defining Unicode char U+0131 (decimal 305)
+   defining Unicode char U+0132 (decimal 306)
+   defining Unicode char U+0133 (decimal 307)
+   defining Unicode char U+0139 (decimal 313)
+   defining Unicode char U+013A (decimal 314)
+   defining Unicode char U+013D (decimal 317)
+   defining Unicode char U+013E (decimal 318)
+   defining Unicode char U+0141 (decimal 321)
+   defining Unicode char U+0142 (decimal 322)
+   defining Unicode char U+0143 (decimal 323)
+   defining Unicode char U+0144 (decimal 324)
+   defining Unicode char U+0147 (decimal 327)
+   defining Unicode char U+0148 (decimal 328)
+   defining Unicode char U+014A (decimal 330)
+   defining Unicode char U+014B (decimal 331)
+   defining Unicode char U+0150 (decimal 336)
+   defining Unicode char U+0151 (decimal 337)
+   defining Unicode char U+0152 (decimal 338)
+   defining Unicode char U+0153 (decimal 339)
+   defining Unicode char U+0154 (decimal 340)
+   defining Unicode char U+0155 (decimal 341)
+   defining Unicode char U+0158 (decimal 344)
+   defining Unicode char U+0159 (decimal 345)
+   defining Unicode char U+015A (decimal 346)
+   defining Unicode char U+015B (decimal 347)
+   defining Unicode char U+015E (decimal 350)
+   defining Unicode char U+015F (decimal 351)
+   defining Unicode char U+0160 (decimal 352)
+   defining Unicode char U+0161 (decimal 353)
+   defining Unicode char U+0162 (decimal 354)
+   defining Unicode char U+0163 (decimal 355)
+   defining Unicode char U+0164 (decimal 356)
+   defining Unicode char U+0165 (decimal 357)
+   defining Unicode char U+016E (decimal 366)
+   defining Unicode char U+016F (decimal 367)
+   defining Unicode char U+0170 (decimal 368)
+   defining Unicode char U+0171 (decimal 369)
+   defining Unicode char U+0178 (decimal 376)
+   defining Unicode char U+0179 (decimal 377)
+   defining Unicode char U+017A (decimal 378)
+   defining Unicode char U+017B (decimal 379)
+   defining Unicode char U+017C (decimal 380)
+   defining Unicode char U+017D (decimal 381)
+   defining Unicode char U+017E (decimal 382)
+   defining Unicode char U+200C (decimal 8204)
+   defining Unicode char U+2013 (decimal 8211)
+   defining Unicode char U+2014 (decimal 8212)
+   defining Unicode char U+2018 (decimal 8216)
+   defining Unicode char U+2019 (decimal 8217)
+   defining Unicode char U+201A (decimal 8218)
+   defining Unicode char U+201C (decimal 8220)
+   defining Unicode char U+201D (decimal 8221)
+   defining Unicode char U+201E (decimal 8222)
+   defining Unicode char U+2030 (decimal 8240)
+   defining Unicode char U+2031 (decimal 8241)
+   defining Unicode char U+2039 (decimal 8249)
+   defining Unicode char U+203A (decimal 8250)
+   defining Unicode char U+2423 (decimal 9251)
+)
+Now handling font encoding OT1 ...
+... processing UTF-8 mapping file for font encoding OT1
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/base/ot1enc.dfu
+File: ot1enc.dfu 2008/04/05 v1.1m UTF-8 support for inputenc
+   defining Unicode char U+00A1 (decimal 161)
+   defining Unicode char U+00A3 (decimal 163)
+   defining Unicode char U+00B8 (decimal 184)
+   defining Unicode char U+00BF (decimal 191)
+   defining Unicode char U+00C5 (decimal 197)
+   defining Unicode char U+00C6 (decimal 198)
+   defining Unicode char U+00D8 (decimal 216)
+   defining Unicode char U+00DF (decimal 223)
+   defining Unicode char U+00E6 (decimal 230)
+   defining Unicode char U+00EC (decimal 236)
+   defining Unicode char U+00ED (decimal 237)
+   defining Unicode char U+00EE (decimal 238)
+   defining Unicode char U+00EF (decimal 239)
+   defining Unicode char U+00F8 (decimal 248)
+   defining Unicode char U+0131 (decimal 305)
+   defining Unicode char U+0141 (decimal 321)
+   defining Unicode char U+0142 (decimal 322)
+   defining Unicode char U+0152 (decimal 338)
+   defining Unicode char U+0153 (decimal 339)
+   defining Unicode char U+2013 (decimal 8211)
+   defining Unicode char U+2014 (decimal 8212)
+   defining Unicode char U+2018 (decimal 8216)
+   defining Unicode char U+2019 (decimal 8217)
+   defining Unicode char U+201C (decimal 8220)
+   defining Unicode char U+201D (decimal 8221)
+)
+Now handling font encoding OMS ...
+... processing UTF-8 mapping file for font encoding OMS
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/base/omsenc.dfu
+File: omsenc.dfu 2008/04/05 v1.1m UTF-8 support for inputenc
+   defining Unicode char U+00A7 (decimal 167)
+   defining Unicode char U+00B6 (decimal 182)
+   defining Unicode char U+00B7 (decimal 183)
+   defining Unicode char U+2020 (decimal 8224)
+   defining Unicode char U+2021 (decimal 8225)
+   defining Unicode char U+2022 (decimal 8226)
+)
+Now handling font encoding OMX ...
+... no UTF-8 mapping file for font encoding OMX
+Now handling font encoding U ...
+... no UTF-8 mapping file for font encoding U
+   defining Unicode char U+00A9 (decimal 169)
+   defining Unicode char U+00AA (decimal 170)
+   defining Unicode char U+00AE (decimal 174)
+   defining Unicode char U+00BA (decimal 186)
+   defining Unicode char U+02C6 (decimal 710)
+   defining Unicode char U+02DC (decimal 732)
+   defining Unicode char U+200C (decimal 8204)
+   defining Unicode char U+2026 (decimal 8230)
+   defining Unicode char U+2122 (decimal 8482)
+   defining Unicode char U+2423 (decimal 9251)
+))
+   defining Unicode char U+00A0 (decimal 160)
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/cmap/cmap.sty
+Package: cmap 2008/03/06 v1.0h CMap support: searchable PDF
+)
+(/usr/local/texlive/2012/texmf-dist/tex/latex/base/fontenc.sty
+Package: fontenc 2005/09/27 v1.99g Standard LaTeX package
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/base/t1enc.def
+File: t1enc.def 2005/09/27 v1.99g Standard LaTeX file
+LaTeX Font Info:    Redeclaring font encoding T1 on input line 43.
+)<<t1.cmap>>)
+(/usr/local/texlive/2012/texmf-dist/tex/generic/babel/babel.sty
+Package: babel 2008/07/08 v3.8m The Babel package
+
+(/usr/local/texlive/2012/texmf-dist/tex/generic/babel/english.ldf
+Language: english 2005/03/30 v3.3o English support from the babel system
+
+(/usr/local/texlive/2012/texmf-dist/tex/generic/babel/babel.def
+File: babel.def 2008/07/08 v3.8m Babel common definitions
+\babel at savecnt=\count88
+\U at D=\dimen103
+)
+\l at canadian = a dialect from \language\l at american 
+\l at australian = a dialect from \language\l at british 
+\l at newzealand = a dialect from \language\l at british 
+))
+(/usr/local/texlive/2012/texmf-dist/tex/latex/psnfss/times.sty
+Package: times 2005/04/12 PSNFSS-v9.2a (SPQR) 
+) (./fncychap.sty
+Package: fncychap 2007/07/30 v1.34 LaTeX package (Revised chapters)
+\RW=\skip43
+\mylen=\skip44
+\myhi=\skip45
+\px=\skip46
+\py=\skip47
+\pyy=\skip48
+\pxx=\skip49
+\c at AlphaCnt=\count89
+\c at AlphaDecCnt=\count90
+) (/usr/local/texlive/2012/texmf-dist/tex/latex/tools/longtable.sty
+Package: longtable 2004/02/01 v4.11 Multi-page Table package (DPC)
+\LTleft=\skip50
+\LTright=\skip51
+\LTpre=\skip52
+\LTpost=\skip53
+\LTchunksize=\count91
+\LTcapwidth=\dimen104
+\LT at head=\box26
+\LT at firsthead=\box27
+\LT at foot=\box28
+\LT at lastfoot=\box29
+\LT at cols=\count92
+\LT at rows=\count93
+\c at LT@tables=\count94
+\c at LT@chunks=\count95
+\LT at p@ftn=\toks16
+)
+(./sphinx.sty
+Package: sphinx 2010/01/15 LaTeX package (Sphinx markup)
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/fancyhdr/fancyhdr.sty
+\fancy at headwidth=\skip54
+\f at ncyO@elh=\skip55
+\f at ncyO@erh=\skip56
+\f at ncyO@olh=\skip57
+\f at ncyO@orh=\skip58
+\f at ncyO@elf=\skip59
+\f at ncyO@erf=\skip60
+\f at ncyO@olf=\skip61
+\f at ncyO@orf=\skip62
+)
+(/usr/local/texlive/2012/texmf-dist/tex/latex/base/textcomp.sty
+Package: textcomp 2005/09/27 v1.99g Standard LaTeX package
+Package textcomp Info: Sub-encoding information:
+(textcomp)               5 = only ISO-Adobe without \textcurrency
+(textcomp)               4 = 5 + \texteuro
+(textcomp)               3 = 4 + \textohm
+(textcomp)               2 = 3 + \textestimated + \textcurrency
+(textcomp)               1 = TS1 - \textcircled - \t
+(textcomp)               0 = TS1 (full)
+(textcomp)             Font families with sub-encoding setting implement
+(textcomp)             only a restricted character set as indicated.
+(textcomp)             Family '?' is the default used for unknown fonts.
+(textcomp)             See the documentation for details.
+Package textcomp Info: Setting ? sub-encoding to TS1/1 on input line 71.
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/base/ts1enc.def
+File: ts1enc.def 2001/06/05 v3.0e (jk/car/fm) Standard LaTeX file
+Now handling font encoding TS1 ...
+... processing UTF-8 mapping file for font encoding TS1
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/base/ts1enc.dfu
+File: ts1enc.dfu 2008/04/05 v1.1m UTF-8 support for inputenc
+   defining Unicode char U+00A2 (decimal 162)
+   defining Unicode char U+00A3 (decimal 163)
+   defining Unicode char U+00A4 (decimal 164)
+   defining Unicode char U+00A5 (decimal 165)
+   defining Unicode char U+00A6 (decimal 166)
+   defining Unicode char U+00A7 (decimal 167)
+   defining Unicode char U+00A8 (decimal 168)
+   defining Unicode char U+00A9 (decimal 169)
+   defining Unicode char U+00AA (decimal 170)
+   defining Unicode char U+00AC (decimal 172)
+   defining Unicode char U+00AE (decimal 174)
+   defining Unicode char U+00AF (decimal 175)
+   defining Unicode char U+00B0 (decimal 176)
+   defining Unicode char U+00B1 (decimal 177)
+   defining Unicode char U+00B2 (decimal 178)
+   defining Unicode char U+00B3 (decimal 179)
+   defining Unicode char U+00B4 (decimal 180)
+   defining Unicode char U+00B5 (decimal 181)
+   defining Unicode char U+00B6 (decimal 182)
+   defining Unicode char U+00B7 (decimal 183)
+   defining Unicode char U+00B9 (decimal 185)
+   defining Unicode char U+00BA (decimal 186)
+   defining Unicode char U+00BC (decimal 188)
+   defining Unicode char U+00BD (decimal 189)
+   defining Unicode char U+00BE (decimal 190)
+   defining Unicode char U+00D7 (decimal 215)
+   defining Unicode char U+00F7 (decimal 247)
+   defining Unicode char U+0192 (decimal 402)
+   defining Unicode char U+02C7 (decimal 711)
+   defining Unicode char U+02D8 (decimal 728)
+   defining Unicode char U+02DD (decimal 733)
+   defining Unicode char U+0E3F (decimal 3647)
+   defining Unicode char U+2016 (decimal 8214)
+   defining Unicode char U+2020 (decimal 8224)
+   defining Unicode char U+2021 (decimal 8225)
+   defining Unicode char U+2022 (decimal 8226)
+   defining Unicode char U+2030 (decimal 8240)
+   defining Unicode char U+2031 (decimal 8241)
+   defining Unicode char U+203B (decimal 8251)
+   defining Unicode char U+203D (decimal 8253)
+   defining Unicode char U+2044 (decimal 8260)
+   defining Unicode char U+204E (decimal 8270)
+   defining Unicode char U+2052 (decimal 8274)
+   defining Unicode char U+20A1 (decimal 8353)
+   defining Unicode char U+20A4 (decimal 8356)
+   defining Unicode char U+20A6 (decimal 8358)
+   defining Unicode char U+20A9 (decimal 8361)
+   defining Unicode char U+20AB (decimal 8363)
+   defining Unicode char U+20AC (decimal 8364)
+   defining Unicode char U+20B1 (decimal 8369)
+   defining Unicode char U+2103 (decimal 8451)
+   defining Unicode char U+2116 (decimal 8470)
+   defining Unicode char U+2117 (decimal 8471)
+   defining Unicode char U+211E (decimal 8478)
+   defining Unicode char U+2120 (decimal 8480)
+   defining Unicode char U+2122 (decimal 8482)
+   defining Unicode char U+2126 (decimal 8486)
+   defining Unicode char U+2127 (decimal 8487)
+   defining Unicode char U+212E (decimal 8494)
+   defining Unicode char U+2190 (decimal 8592)
+   defining Unicode char U+2191 (decimal 8593)
+   defining Unicode char U+2192 (decimal 8594)
+   defining Unicode char U+2193 (decimal 8595)
+   defining Unicode char U+2329 (decimal 9001)
+   defining Unicode char U+232A (decimal 9002)
+   defining Unicode char U+2422 (decimal 9250)
+   defining Unicode char U+25E6 (decimal 9702)
+   defining Unicode char U+25EF (decimal 9711)
+   defining Unicode char U+266A (decimal 9834)
+))
+LaTeX Info: Redefining \oldstylenums on input line 266.
+Package textcomp Info: Setting cmr sub-encoding to TS1/0 on input line 281.
+Package textcomp Info: Setting cmss sub-encoding to TS1/0 on input line 282.
+Package textcomp Info: Setting cmtt sub-encoding to TS1/0 on input line 283.
+Package textcomp Info: Setting cmvtt sub-encoding to TS1/0 on input line 284.
+Package textcomp Info: Setting cmbr sub-encoding to TS1/0 on input line 285.
+Package textcomp Info: Setting cmtl sub-encoding to TS1/0 on input line 286.
+Package textcomp Info: Setting ccr sub-encoding to TS1/0 on input line 287.
+Package textcomp Info: Setting ptm sub-encoding to TS1/4 on input line 288.
+Package textcomp Info: Setting pcr sub-encoding to TS1/4 on input line 289.
+Package textcomp Info: Setting phv sub-encoding to TS1/4 on input line 290.
+Package textcomp Info: Setting ppl sub-encoding to TS1/3 on input line 291.
+Package textcomp Info: Setting pag sub-encoding to TS1/4 on input line 292.
+Package textcomp Info: Setting pbk sub-encoding to TS1/4 on input line 293.
+Package textcomp Info: Setting pnc sub-encoding to TS1/4 on input line 294.
+Package textcomp Info: Setting pzc sub-encoding to TS1/4 on input line 295.
+Package textcomp Info: Setting bch sub-encoding to TS1/4 on input line 296.
+Package textcomp Info: Setting put sub-encoding to TS1/5 on input line 297.
+Package textcomp Info: Setting uag sub-encoding to TS1/5 on input line 298.
+Package textcomp Info: Setting ugq sub-encoding to TS1/5 on input line 299.
+Package textcomp Info: Setting ul8 sub-encoding to TS1/4 on input line 300.
+Package textcomp Info: Setting ul9 sub-encoding to TS1/4 on input line 301.
+Package textcomp Info: Setting augie sub-encoding to TS1/5 on input line 302.
+Package textcomp Info: Setting dayrom sub-encoding to TS1/3 on input line 303.
+Package textcomp Info: Setting dayroms sub-encoding to TS1/3 on input line 304.
+
+Package textcomp Info: Setting pxr sub-encoding to TS1/0 on input line 305.
+Package textcomp Info: Setting pxss sub-encoding to TS1/0 on input line 306.
+Package textcomp Info: Setting pxtt sub-encoding to TS1/0 on input line 307.
+Package textcomp Info: Setting txr sub-encoding to TS1/0 on input line 308.
+Package textcomp Info: Setting txss sub-encoding to TS1/0 on input line 309.
+Package textcomp Info: Setting txtt sub-encoding to TS1/0 on input line 310.
+Package textcomp Info: Setting lmr sub-encoding to TS1/0 on input line 311.
+Package textcomp Info: Setting lmdh sub-encoding to TS1/0 on input line 312.
+Package textcomp Info: Setting lmss sub-encoding to TS1/0 on input line 313.
+Package textcomp Info: Setting lmssq sub-encoding to TS1/0 on input line 314.
+Package textcomp Info: Setting lmvtt sub-encoding to TS1/0 on input line 315.
+Package textcomp Info: Setting qhv sub-encoding to TS1/0 on input line 316.
+Package textcomp Info: Setting qag sub-encoding to TS1/0 on input line 317.
+Package textcomp Info: Setting qbk sub-encoding to TS1/0 on input line 318.
+Package textcomp Info: Setting qcr sub-encoding to TS1/0 on input line 319.
+Package textcomp Info: Setting qcs sub-encoding to TS1/0 on input line 320.
+Package textcomp Info: Setting qpl sub-encoding to TS1/0 on input line 321.
+Package textcomp Info: Setting qtm sub-encoding to TS1/0 on input line 322.
+Package textcomp Info: Setting qzc sub-encoding to TS1/0 on input line 323.
+Package textcomp Info: Setting qhvc sub-encoding to TS1/0 on input line 324.
+Package textcomp Info: Setting futs sub-encoding to TS1/4 on input line 325.
+Package textcomp Info: Setting futx sub-encoding to TS1/4 on input line 326.
+Package textcomp Info: Setting futj sub-encoding to TS1/4 on input line 327.
+Package textcomp Info: Setting hlh sub-encoding to TS1/3 on input line 328.
+Package textcomp Info: Setting hls sub-encoding to TS1/3 on input line 329.
+Package textcomp Info: Setting hlst sub-encoding to TS1/3 on input line 330.
+Package textcomp Info: Setting hlct sub-encoding to TS1/5 on input line 331.
+Package textcomp Info: Setting hlx sub-encoding to TS1/5 on input line 332.
+Package textcomp Info: Setting hlce sub-encoding to TS1/5 on input line 333.
+Package textcomp Info: Setting hlcn sub-encoding to TS1/5 on input line 334.
+Package textcomp Info: Setting hlcw sub-encoding to TS1/5 on input line 335.
+Package textcomp Info: Setting hlcf sub-encoding to TS1/5 on input line 336.
+Package textcomp Info: Setting pplx sub-encoding to TS1/3 on input line 337.
+Package textcomp Info: Setting pplj sub-encoding to TS1/3 on input line 338.
+Package textcomp Info: Setting ptmx sub-encoding to TS1/4 on input line 339.
+Package textcomp Info: Setting ptmj sub-encoding to TS1/4 on input line 340.
+)
+(/usr/local/texlive/2012/texmf-dist/tex/latex/fancybox/fancybox.sty
+Package: fancybox 2010/05/15 1.4
+
+Style option: `fancybox' v1.4 <2010/05/15> (tvz)
+\@fancybox=\box30
+\shadowsize=\dimen105
+\@Sbox=\box31
+\do at VerbBox=\toks17
+\the at fancyput=\toks18
+\this at fancyput=\toks19
+\EndVerbatimTokens=\toks20
+\Verbatim at Outfile=\write3
+\Verbatim at Infile=\read1
+) (/usr/local/texlive/2012/texmf-dist/tex/latex/titlesec/titlesec.sty
+Package: titlesec 2011/12/15 v2.10.0 Sectioning titles
+\ttl at box=\box32
+\beforetitleunit=\skip63
+\aftertitleunit=\skip64
+\ttl at plus=\dimen106
+\ttl at minus=\dimen107
+\ttl at toksa=\toks21
+\titlewidth=\dimen108
+\titlewidthlast=\dimen109
+\titlewidthfirst=\dimen110
+)
+(./tabulary.sty
+Package: tabulary 2007/10/02 v0.9 tabulary package (DPC)
+ (/usr/local/texlive/2012/texmf-dist/tex/latex/tools/array.sty
+Package: array 2008/09/09 v2.4c Tabular extension package (FMi)
+\col at sep=\dimen111
+\extrarowheight=\dimen112
+\NC at list=\toks22
+\extratabsurround=\skip65
+\backup at length=\skip66
+)
+\TY at count=\count96
+\TY at linewidth=\dimen113
+\tymin=\dimen114
+\tymax=\dimen115
+\TY at tablewidth=\dimen116
+) (/usr/local/texlive/2012/texmf-dist/tex/latex/amsmath/amsmath.sty
+Package: amsmath 2013/01/14 v2.14 AMS math features
+\@mathmargin=\skip67
+
+For additional information on amsmath, use the `?' option.
+(/usr/local/texlive/2012/texmf-dist/tex/latex/amsmath/amstext.sty
+Package: amstext 2000/06/29 v2.01
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/amsmath/amsgen.sty
+File: amsgen.sty 1999/11/30 v2.0
+\@emptytoks=\toks23
+\ex@=\dimen117
+))
+(/usr/local/texlive/2012/texmf-dist/tex/latex/amsmath/amsbsy.sty
+Package: amsbsy 1999/11/29 v1.2d
+\pmbraise@=\dimen118
+)
+(/usr/local/texlive/2012/texmf-dist/tex/latex/amsmath/amsopn.sty
+Package: amsopn 1999/12/14 v2.01 operator names
+)
+\inf at bad=\count97
+LaTeX Info: Redefining \frac on input line 210.
+\uproot@=\count98
+\leftroot@=\count99
+LaTeX Info: Redefining \overline on input line 306.
+\classnum@=\count100
+\DOTSCASE@=\count101
+LaTeX Info: Redefining \ldots on input line 378.
+LaTeX Info: Redefining \dots on input line 381.
+LaTeX Info: Redefining \cdots on input line 466.
+\Mathstrutbox@=\box33
+\strutbox@=\box34
+\big at size=\dimen119
+LaTeX Font Info:    Redeclaring font encoding OML on input line 566.
+LaTeX Font Info:    Redeclaring font encoding OMS on input line 567.
+\macc at depth=\count102
+\c at MaxMatrixCols=\count103
+\dotsspace@=\muskip10
+\c at parentequation=\count104
+\dspbrk at lvl=\count105
+\tag at help=\toks24
+\row@=\count106
+\column@=\count107
+\maxfields@=\count108
+\andhelp@=\toks25
+\eqnshift@=\dimen120
+\alignsep@=\dimen121
+\tagshift@=\dimen122
+\tagwidth@=\dimen123
+\totwidth@=\dimen124
+\lineht@=\dimen125
+\@envbody=\toks26
+\multlinegap=\skip68
+\multlinetaggap=\skip69
+\mathdisplay at stack=\toks27
+LaTeX Info: Redefining \[ on input line 2665.
+LaTeX Info: Redefining \] on input line 2666.
+)
+(/usr/local/texlive/2012/texmf-dist/tex/latex/base/makeidx.sty
+Package: makeidx 2000/03/29 v1.0m Standard LaTeX package
+)
+(/usr/local/texlive/2012/texmf-dist/tex/latex/framed/framed.sty
+Package: framed 2011/10/22 v 0.96: framed or shaded text with page breaks
+\OuterFrameSep=\skip70
+\fb at frw=\dimen126
+\fb at frh=\dimen127
+\FrameRule=\dimen128
+\FrameSep=\dimen129
+)
+(/usr/local/texlive/2012/texmf-dist/tex/latex/base/ifthen.sty
+Package: ifthen 2001/05/26 v1.1c Standard LaTeX ifthen package (DPC)
+)
+(/usr/local/texlive/2012/texmf-dist/tex/latex/graphics/color.sty
+Package: color 2005/11/14 v1.0j Standard LaTeX Color (DPC)
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/latexconfig/color.cfg
+File: color.cfg 2007/01/18 v1.5 color configuration of teTeX/TeXLive
+)
+Package color Info: Driver file: pdftex.def on input line 130.
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/pdftex-def/pdftex.def
+File: pdftex.def 2011/05/27 v0.06d Graphics/color for pdfTeX
+
+(/usr/local/texlive/2012/texmf-dist/tex/generic/oberdiek/infwarerr.sty
+Package: infwarerr 2010/04/08 v1.3 Providing info/warning/error messages (HO)
+)
+(/usr/local/texlive/2012/texmf-dist/tex/generic/oberdiek/ltxcmds.sty
+Package: ltxcmds 2011/11/09 v1.22 LaTeX kernel commands for general use (HO)
+)
+\Gread at gobject=\count109
+))
+(/usr/local/texlive/2012/texmf-dist/tex/latex/fancyvrb/fancyvrb.sty
+Package: fancyvrb 2008/02/07
+
+Style option: `fancyvrb' v2.7a, with DG/SPQR fixes, and firstline=lastline fix 
+<2008/02/07> (tvz)
+(/usr/local/texlive/2012/texmf-dist/tex/latex/graphics/keyval.sty
+Package: keyval 1999/03/16 v1.13 key=value parser (DPC)
+\KV at toks@=\toks28
+)
+\FV at CodeLineNo=\count110
+\FV at InFile=\read2
+\FV at TabBox=\box35
+\c at FancyVerbLine=\count111
+\FV at StepNumber=\count112
+\FV at OutFile=\write4
+)
+(/usr/local/texlive/2012/texmf-dist/tex/latex/threeparttable/threeparttable.sty
+Package: threeparttable 2003/06/13  v 3.0
+\@tempboxb=\box36
+) (/usr/local/texlive/2012/texmf-dist/tex/latex/mdwtools/footnote.sty
+Package: footnote 1997/01/28 1.13 Save footnotes around boxes
+\fn at notes=\box37
+\fn at width=\dimen130
+)
+(/usr/local/texlive/2012/texmf-dist/tex/latex/wrapfig/wrapfig.sty
+\wrapoverhang=\dimen131
+\WF at size=\dimen132
+\c at WF@wrappedlines=\count113
+\WF at box=\box38
+\WF at everypar=\toks29
+Package: wrapfig 2003/01/31  v 3.6
+)
+(/usr/local/texlive/2012/texmf-dist/tex/latex/parskip/parskip.sty
+Package: parskip 2001/04/09 non-zero parskip adjustments
+)
+(/usr/local/texlive/2012/texmf-dist/tex/latex/graphics/graphicx.sty
+Package: graphicx 1999/02/16 v1.0f Enhanced LaTeX Graphics (DPC,SPQR)
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/graphics/graphics.sty
+Package: graphics 2009/02/05 v1.0o Standard LaTeX Graphics (DPC,SPQR)
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/graphics/trig.sty
+Package: trig 1999/03/16 v1.09 sin cos tan (DPC)
+)
+(/usr/local/texlive/2012/texmf-dist/tex/latex/latexconfig/graphics.cfg
+File: graphics.cfg 2010/04/23 v1.9 graphics configuration of TeX Live
+)
+Package graphics Info: Driver file: pdftex.def on input line 91.
+)
+\Gin at req@height=\dimen133
+\Gin at req@width=\dimen134
+)
+(/usr/local/texlive/2012/texmf-dist/tex/plain/misc/pdfcolor.tex)
+\distancetoright=\skip71
+\py at argswidth=\skip72
+\py at noticelength=\skip73
+\lineblockindentation=\skip74
+\image at box=\box39
+\image at width=\dimen135
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/hyperref/hyperref.sty
+Package: hyperref 2012/11/06 v6.83m Hypertext links for LaTeX
+
+(/usr/local/texlive/2012/texmf-dist/tex/generic/oberdiek/hobsub-hyperref.sty
+Package: hobsub-hyperref 2012/05/28 v1.13 Bundle oberdiek, subset hyperref (HO)
+
+
+(/usr/local/texlive/2012/texmf-dist/tex/generic/oberdiek/hobsub-generic.sty
+Package: hobsub-generic 2012/05/28 v1.13 Bundle oberdiek, subset generic (HO)
+Package: hobsub 2012/05/28 v1.13 Construct package bundles (HO)
+Package hobsub Info: Skipping package `infwarerr' (already loaded).
+Package hobsub Info: Skipping package `ltxcmds' (already loaded).
+Package: ifluatex 2010/03/01 v1.3 Provides the ifluatex switch (HO)
+Package ifluatex Info: LuaTeX not detected.
+Package: ifvtex 2010/03/01 v1.5 Detect VTeX and its facilities (HO)
+Package ifvtex Info: VTeX not detected.
+Package: intcalc 2007/09/27 v1.1 Expandable calculations with integers (HO)
+Package: ifpdf 2011/01/30 v2.3 Provides the ifpdf switch (HO)
+Package ifpdf Info: pdfTeX in PDF mode is detected.
+Package: etexcmds 2011/02/16 v1.5 Avoid name clashes with e-TeX commands (HO)
+Package etexcmds Info: Could not find \expanded.
+(etexcmds)             That can mean that you are not using pdfTeX 1.50 or
+(etexcmds)             that some package has redefined \expanded.
+(etexcmds)             In the latter case, load this package earlier.
+Package: kvsetkeys 2012/04/25 v1.16 Key value parser (HO)
+Package: kvdefinekeys 2011/04/07 v1.3 Define keys (HO)
+Package: pdftexcmds 2011/11/29 v0.20 Utility functions of pdfTeX for LuaTeX (HO
+)
+Package pdftexcmds Info: LuaTeX not detected.
+Package pdftexcmds Info: \pdf at primitive is available.
+Package pdftexcmds Info: \pdf at ifprimitive is available.
+Package pdftexcmds Info: \pdfdraftmode found.
+Package: pdfescape 2011/11/25 v1.13 Implements pdfTeX's escape features (HO)
+Package: bigintcalc 2012/04/08 v1.3 Expandable calculations on big integers (HO
+)
+Package: bitset 2011/01/30 v1.1 Handle bit-vector datatype (HO)
+Package: uniquecounter 2011/01/30 v1.2 Provide unlimited unique counter (HO)
+)
+Package hobsub Info: Skipping package `hobsub' (already loaded).
+Package: letltxmacro 2010/09/02 v1.4 Let assignment for LaTeX macros (HO)
+Package: hopatch 2012/05/28 v1.2 Wrapper for package hooks (HO)
+Package: xcolor-patch 2011/01/30 xcolor patch
+Package: atveryend 2011/06/30 v1.8 Hooks at the very end of document (HO)
+Package atveryend Info: \enddocument detected (standard20110627).
+Package: atbegshi 2011/10/05 v1.16 At begin shipout hook (HO)
+Package: refcount 2011/10/16 v3.4 Data extraction from label references (HO)
+Package: hycolor 2011/01/30 v1.7 Color options for hyperref/bookmark (HO)
+)
+(/usr/local/texlive/2012/texmf-dist/tex/generic/ifxetex/ifxetex.sty
+Package: ifxetex 2010/09/12 v0.6 Provides ifxetex conditional
+)
+(/usr/local/texlive/2012/texmf-dist/tex/latex/oberdiek/auxhook.sty
+Package: auxhook 2011/03/04 v1.3 Hooks for auxiliary files (HO)
+)
+(/usr/local/texlive/2012/texmf-dist/tex/latex/oberdiek/kvoptions.sty
+Package: kvoptions 2011/06/30 v3.11 Key value format for package options (HO)
+)
+\@linkdim=\dimen136
+\Hy at linkcounter=\count114
+\Hy at pagecounter=\count115
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/hyperref/pd1enc.def
+File: pd1enc.def 2012/11/06 v6.83m Hyperref: PDFDocEncoding definition (HO)
+Now handling font encoding PD1 ...
+... no UTF-8 mapping file for font encoding PD1
+)
+\Hy at SavedSpaceFactor=\count116
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/latexconfig/hyperref.cfg
+File: hyperref.cfg 2002/06/06 v1.2 hyperref configuration of TeXLive
+)
+Package hyperref Info: Option `colorlinks' set `true' on input line 4319.
+Package hyperref Info: Option `breaklinks' set `true' on input line 4319.
+Package hyperref Info: Hyper figures OFF on input line 4443.
+Package hyperref Info: Link nesting OFF on input line 4448.
+Package hyperref Info: Hyper index ON on input line 4451.
+Package hyperref Info: Plain pages OFF on input line 4458.
+Package hyperref Info: Backreferencing OFF on input line 4463.
+Package hyperref Info: Implicit mode ON; LaTeX internals redefined.
+Package hyperref Info: Bookmarks ON on input line 4688.
+\c at Hy@tempcnt=\count117
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/url/url.sty
+\Urlmuskip=\muskip11
+Package: url 2006/04/12  ver 3.3  Verb mode for urls, etc.
+)
+LaTeX Info: Redefining \url on input line 5041.
+\XeTeXLinkMargin=\dimen137
+\Fld at menulength=\count118
+\Field at Width=\dimen138
+\Fld at charsize=\dimen139
+Package hyperref Info: Hyper figures OFF on input line 6295.
+Package hyperref Info: Link nesting OFF on input line 6300.
+Package hyperref Info: Hyper index ON on input line 6303.
+Package hyperref Info: backreferencing OFF on input line 6310.
+Package hyperref Info: Link coloring ON on input line 6313.
+Package hyperref Info: Link coloring with OCG OFF on input line 6320.
+Package hyperref Info: PDF/A mode OFF on input line 6325.
+LaTeX Info: Redefining \ref on input line 6365.
+LaTeX Info: Redefining \pageref on input line 6369.
+\Hy at abspage=\count119
+\c at Item=\count120
+\c at Hfootnote=\count121
+)
+
+Package hyperref Message: Driver (autodetected): hpdftex.
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/hyperref/hpdftex.def
+File: hpdftex.def 2012/11/06 v6.83m Hyperref driver for pdfTeX
+\Fld at listcount=\count122
+\c at bookmark@seq at number=\count123
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/oberdiek/rerunfilecheck.sty
+Package: rerunfilecheck 2011/04/15 v1.7 Rerun checks for auxiliary files (HO)
+Package uniquecounter Info: New unique counter `rerunfilecheck' on input line 2
+82.
+)
+\Hy at SectionHShift=\skip75
+)
+(/usr/local/texlive/2012/texmf-dist/tex/latex/oberdiek/hypcap.sty
+Package: hypcap 2011/02/16 v1.11 Adjusting the anchors of captions (HO)
+)
+\DUlineblockindent=\skip76
+)
+(/usr/local/texlive/2012/texmf-dist/tex/latex/multirow/multirow.sty
+\bigstrutjot=\dimen140
+)
+\@indexfile=\write5
+\openout5 = `xmds2.idx'.
+
+
+Writing index file xmds2.idx
+(./xmds2.aux)
+\openout1 = `xmds2.aux'.
+
+LaTeX Font Info:    Checking defaults for OML/cmm/m/it on input line 117.
+LaTeX Font Info:    ... okay on input line 117.
+LaTeX Font Info:    Checking defaults for T1/cmr/m/n on input line 117.
+LaTeX Font Info:    ... okay on input line 117.
+LaTeX Font Info:    Checking defaults for OT1/cmr/m/n on input line 117.
+LaTeX Font Info:    ... okay on input line 117.
+LaTeX Font Info:    Checking defaults for OMS/cmsy/m/n on input line 117.
+LaTeX Font Info:    ... okay on input line 117.
+LaTeX Font Info:    Checking defaults for OMX/cmex/m/n on input line 117.
+LaTeX Font Info:    ... okay on input line 117.
+LaTeX Font Info:    Checking defaults for U/cmr/m/n on input line 117.
+LaTeX Font Info:    ... okay on input line 117.
+LaTeX Font Info:    Checking defaults for TS1/cmr/m/n on input line 117.
+LaTeX Font Info:    Try loading font information for TS1+cmr on input line 117.
+
+ (/usr/local/texlive/2012/texmf-dist/tex/latex/base/ts1cmr.fd
+File: ts1cmr.fd 1999/05/25 v2.5h Standard LaTeX font definitions
+)
+LaTeX Font Info:    ... okay on input line 117.
+LaTeX Font Info:    Checking defaults for PD1/pdf/m/n on input line 117.
+LaTeX Font Info:    ... okay on input line 117.
+LaTeX Font Info:    Try loading font information for T1+ptm on input line 117.
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/psnfss/t1ptm.fd
+File: t1ptm.fd 2001/06/04 font definitions for T1/ptm.
+)
+(/usr/local/texlive/2012/texmf-dist/tex/context/base/supp-pdf.mkii
+[Loading MPS to PDF converter (version 2006.09.02).]
+\scratchcounter=\count124
+\scratchdimen=\dimen141
+\scratchbox=\box40
+\nofMPsegments=\count125
+\nofMParguments=\count126
+\everyMPshowfont=\toks30
+\MPscratchCnt=\count127
+\MPscratchDim=\dimen142
+\MPnumerator=\count128
+\makeMPintoPDFobject=\count129
+\everyMPtoPDFconversion=\toks31
+) (/usr/local/texlive/2012/texmf-dist/tex/latex/oberdiek/epstopdf-base.sty
+Package: epstopdf-base 2010/02/09 v2.5 Base part for package epstopdf
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/oberdiek/grfext.sty
+Package: grfext 2010/08/19 v1.1 Manage graphics extensions (HO)
+)
+Package grfext Info: Graphics extension search list:
+(grfext)             [.png,.pdf,.jpg,.mps,.jpeg,.jbig2,.jb2,.PNG,.PDF,.JPG,.JPE
+G,.JBIG2,.JB2,.eps]
+(grfext)             \AppendGraphicsExtensions on input line 452.
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg
+File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Liv
+e
+))
+\AtBeginShipoutBox=\box41
+Package hyperref Info: Link coloring ON on input line 117.
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/hyperref/nameref.sty
+Package: nameref 2012/10/27 v2.43 Cross-referencing by name of section
+
+(/usr/local/texlive/2012/texmf-dist/tex/generic/oberdiek/gettitlestring.sty
+Package: gettitlestring 2010/12/03 v1.4 Cleanup title references (HO)
+)
+\c at section@level=\count130
+)
+LaTeX Info: Redefining \ref on input line 117.
+LaTeX Info: Redefining \pageref on input line 117.
+LaTeX Info: Redefining \nameref on input line 117.
+
+(./xmds2.out) (./xmds2.out)
+\@outlinefile=\write6
+\openout6 = `xmds2.out'.
+
+
+Underfull \hbox (badness 10000) in paragraph at lines 120--120
+
+ []
+
+<xmds_logo.pdf, id=218, 183.084pt x 183.084pt>
+File: xmds_logo.pdf Graphic file (type pdf)
+ <use xmds_logo.pdf>
+Package pdftex.def Info: xmds_logo.pdf used on input line 120.
+(pdftex.def)             Requested size: 183.08354pt x 183.08354pt.
+File: xmds_logo.pdf Graphic file (type pdf)
+
+<use xmds_logo.pdf>
+Package pdftex.def Info: xmds_logo.pdf used on input line 120.
+(pdftex.def)             Requested size: 183.08354pt x 183.08354pt.
+LaTeX Font Info:    Try loading font information for T1+phv on input line 120.
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/psnfss/t1phv.fd
+File: t1phv.fd 2001/06/04 scalable font definitions for T1/phv.
+)
+LaTeX Font Info:    Font shape `T1/phv/bx/n' in size <24.88> not available
+(Font)              Font shape `T1/phv/b/n' tried instead on input line 120.
+LaTeX Font Info:    Font shape `T1/phv/m/it' in size <17.28> not available
+(Font)              Font shape `T1/phv/m/sl' tried instead on input line 120.
+LaTeX Font Info:    Font shape `T1/phv/bx/it' in size <17.28> not available
+(Font)              Font shape `T1/phv/b/it' tried instead on input line 120.
+LaTeX Font Info:    Font shape `T1/phv/b/it' in size <17.28> not available
+(Font)              Font shape `T1/phv/b/sl' tried instead on input line 120.
+LaTeX Font Info:    Font shape `T1/phv/bx/n' in size <17.28> not available
+(Font)              Font shape `T1/phv/b/n' tried instead on input line 120.
+<<ot1.cmap>><<oml.cmap>><<oms.cmap>><<omx.cmap>> [1
+
+{/usr/local/texlive/2012/texmf-var/fonts/map/pdftex/updmap/pdftex.map} <./xmds_
+logo.pdf>] [2
+
+] (./xmds2.toc
+LaTeX Font Info:    Font shape `T1/ptm/bx/n' in size <10> not available
+(Font)              Font shape `T1/ptm/b/n' tried instead on input line 2.
+LaTeX Font Info:    Try loading font information for T1+pcr on input line 81.
+
+(/usr/local/texlive/2012/texmf-dist/tex/latex/psnfss/t1pcr.fd
+File: t1pcr.fd 2001/06/04 font definitions for T1/pcr.
+)
+LaTeX Font Info:    Font shape `T1/phv/bx/n' in size <10> not available
+(Font)              Font shape `T1/phv/b/n' tried instead on input line 101.
+pdfTeX warning (ext4): destination with the same identifier (name{page.i}) has 
+been already used, duplicate ignored
+<to be read again> 
+                   \relax 
+l.101 ...iler and library tricks}{85}{section.9.3}
+                                                   [1
+
+])
+\tf at toc=\write7
+\openout7 = `xmds2.toc'.
+
+pdfTeX warning (ext4): destination with the same identifier (name{page.ii}) has
+ been already used, duplicate ignored
+<to be read again> 
+                   \relax 
+l.120 \tableofcontents
+                       [2]
+Chapter 1.
+LaTeX Font Info:    Font shape `T1/phv/bx/n' in size <14.4> not available
+(Font)              Font shape `T1/phv/b/n' tried instead on input line 125.
+LaTeX Font Info:    Font shape `T1/ptm/bx/n' in size <14.4> not available
+(Font)              Font shape `T1/ptm/b/n' tried instead on input line 125.
+LaTeX Font Info:    Font shape `T1/ptm/bx/n' in size <24.88> not available
+(Font)              Font shape `T1/ptm/b/n' tried instead on input line 125.
+LaTeX Font Info:    Font shape `T1/ptm/bx/n' in size <8> not available
+(Font)              Font shape `T1/ptm/b/n' tried instead on input line 143.
+[1
+
+
+] [2]
+Chapter 2.
+
+Package tabulary Warning: No suitable columns! on input line 182.
+
+LaTeX Font Info:    Font shape `T1/phv/bx/n' in size <12> not available
+(Font)              Font shape `T1/phv/b/n' tried instead on input line 217.
+[3
+
+]
+LaTeX Font Info:    Try loading font information for TS1+ptm on input line 263.
+
+ (/usr/local/texlive/2012/texmf-dist/tex/latex/psnfss/ts1ptm.fd
+File: ts1ptm.fd 2001/06/04 font definitions for TS1/ptm.
+) [4]
+Underfull \hbox (badness 10000) in paragraph at lines 307--310
+[]\T1/ptm/m/n/10 First cre-ate the path ~/lib/python2.5/site-packages (as-sum-i
+ng you in-stalled
+ []
+
+[5]
+Underfull \hbox (badness 10000) in paragraph at lines 388--390
+[]\T1/ptm/m/n/10 It can be in-stalled with \T1/pcr/m/n/10 sudo
+ []
+
+
+Underfull \hbox (badness 10000) in paragraph at lines 402--404
+[]
+ []
+
+
+Underfull \hbox (badness 10000) in paragraph at lines 410--412
+[]\T1/ptm/m/n/10 h5py
+ []
+
+
+Underfull \hbox (badness 10000) in paragraph at lines 422--424
+[]\T1/pcr/m/n/10 sudo
+ []
+
+
+Underfull \hbox (badness 5563) in paragraph at lines 437--440
+[]\T1/ptm/m/n/10 If you have `numpy' in-stalled, test XMDS2 by typ-ing
+ []
+
+
+Underfull \hbox (badness 10000) in paragraph at lines 452--453
+[]\T1/ptm/m/n/10 The gen-er-ated html doc-u-men-ta-tion will then be found at x
+mds-
+ []
+
+
+Underfull \hbox (badness 10000) in paragraph at lines 465--466
+[]\T1/pcr/m/n/10 xmds2 --reconfigure --include-path /apps/fftw3/include
+ []
+
+[6] [7] [8
+
+]
+Chapter 3.
+LaTeX Font Info:    Font shape `T1/pcr/m/it' in size <9> not available
+(Font)              Font shape `T1/pcr/m/sl' tried instead on input line 495.
+LaTeX Font Info:    Font shape `T1/pcr/bx/n' in size <9> not available
+(Font)              Font shape `T1/pcr/b/n' tried instead on input line 496.
+[9] [10] <lorenz.pdf, id=455, 681.01025pt x 300.322pt>
+File: lorenz.pdf Graphic file (type pdf)
+ <use lorenz.pdf>
+Package pdftex.def Info: lorenz.pdf used on input line 631.
+(pdftex.def)             Requested size: 681.00859pt x 300.32127pt.
+File: lorenz.pdf Graphic file (type pdf)
+
+<use lorenz.pdf>
+Package pdftex.def Info: lorenz.pdf used on input line 631.
+(pdftex.def)             Requested size: 452.96788pt x 199.75745pt.
+ [11 <./lorenz.pdf>] [12] [13] [14]
+Chapter 4.
+[15
+
+]
+Underfull \vbox (badness 10000) detected at line 877
+ []
+
+
+Underfull \vbox (badness 10000) detected at line 877
+ []
+
+[16] [17] [18] [19] [20] <kuboSingle.pdf, id=524, 569.32701pt x 349.00288pt>
+File: kuboSingle.pdf Graphic file (type pdf)
+
+<use kuboSingle.pdf>
+Package pdftex.def Info: kuboSingle.pdf used on input line 1092.
+(pdftex.def)             Requested size: 569.3256pt x 349.00203pt.
+File: kuboSingle.pdf Graphic file (type pdf)
+ <use kuboSingle.pdf>
+Package pdftex.def Info: kuboSingle.pdf used on input line 1092.
+(pdftex.def)             Requested size: 452.96788pt x 277.67963pt.
+
+<kubo10000.pdf, id=525, 560.49402pt x 346.36702pt>
+File: kubo10000.pdf Graphic file (type pdf)
+ <use kubo10000.pdf>
+Package pdftex.def Info: kubo10000.pdf used on input line 1100.
+(pdftex.def)             Requested size: 560.49265pt x 346.36617pt.
+File: kubo10000.pdf Graphic file (type pdf)
+
+<use kubo10000.pdf>
+Package pdftex.def Info: kubo10000.pdf used on input line 1100.
+(pdftex.def)             Requested size: 452.96788pt x 279.9268pt.
+ [21] [22 <./kuboSingle.pdf> <./kubo10000.pdf>]
+Underfull \vbox (badness 10000) detected at line 1183
+ []
+
+
+Underfull \vbox (badness 10000) detected at line 1183
+ []
+
+[23] [24] <fibreSingle.pdf, id=559, 639.99098pt x 481.84819pt>
+File: fibreSingle.pdf Graphic file (type pdf)
+
+<use fibreSingle.pdf>
+Package pdftex.def Info: fibreSingle.pdf used on input line 1242.
+(pdftex.def)             Requested size: 639.98943pt x 481.84702pt.
+File: fibreSingle.pdf Graphic file (type pdf)
+ <use fibreSingle.pdf>
+Package pdftex.def Info: fibreSingle.pdf used on input line 1242.
+(pdftex.def)             Requested size: 452.96788pt x 341.04851pt.
+
+<fibre1024.pdf, id=560, 639.99098pt x 482.46848pt>
+File: fibre1024.pdf Graphic file (type pdf)
+ <use fibre1024.pdf>
+Package pdftex.def Info: fibre1024.pdf used on input line 1250.
+(pdftex.def)             Requested size: 639.98943pt x 482.4673pt.
+File: fibre1024.pdf Graphic file (type pdf)
+
+<use fibre1024.pdf>
+Package pdftex.def Info: fibre1024.pdf used on input line 1250.
+(pdftex.def)             Requested size: 452.96788pt x 341.48755pt.
+ [25 <./fibreSingle.pdf>] [26 <./fibre1024.pdf>] [27]
+[28]
+Underfull \vbox (badness 10000) detected at line 1455
+ []
+
+
+Underfull \vbox (badness 10000) detected at line 1455
+ []
+
+[29] [30] [31]
+LaTeX Font Info:    Font shape `T1/pcr/bx/it' in size <9> not available
+(Font)              Font shape `T1/pcr/b/it' tried instead on input line 1638.
+LaTeX Font Info:    Font shape `T1/pcr/b/it' in size <9> not available
+(Font)              Font shape `T1/pcr/b/sl' tried instead on input line 1638.
+
+Overfull \vbox (0.87749pt too high) detected at line 1699
+ []
+
+[32]
+Underfull \vbox (badness 10000) detected at line 1699
+ []
+
+
+Underfull \vbox (badness 10000) detected at line 1699
+ []
+
+[33] [34] <groundstateU2.pdf, id=629, 467.32591pt x 333.245pt>
+File: groundstateU2.pdf Graphic file (type pdf)
+
+<use groundstateU2.pdf>
+Package pdftex.def Info: groundstateU2.pdf used on input line 1776.
+(pdftex.def)             Requested size: 467.32477pt x 333.24417pt.
+File: groundstateU2.pdf Graphic file (type pdf)
+ <use groundstateU2.pdf>
+Package pdftex.def Info: groundstateU2.pdf used on input line 1776.
+(pdftex.def)             Requested size: 452.96788pt x 323.01334pt.
+
+<groundstateU20.pdf, id=630, 467.32591pt x 333.245pt>
+File: groundstateU20.pdf Graphic file (type pdf)
+ <use groundstateU20.pdf>
+Package pdftex.def Info: groundstateU20.pdf used on input line 1782.
+(pdftex.def)             Requested size: 467.32477pt x 333.24417pt.
+File: groundstateU20.pdf Graphic file (type pdf)
+
+<use groundstateU20.pdf>
+Package pdftex.def Info: groundstateU20.pdf used on input line 1782.
+(pdftex.def)             Requested size: 452.96788pt x 323.01334pt.
+ [35] [36 <./groundstateU2.pdf>]
+Underfull \vbox (badness 10000) detected at line 1910
+ []
+
+
+Underfull \vbox (badness 10000) detected at line 1910
+ []
+
+[37 <./groundstateU20.pdf>]
+Underfull \vbox (badness 10000) detected at line 1910
+ []
+
+
+Underfull \vbox (badness 10000) detected at line 1910
+ []
+
+[38] [39]
+Underfull \vbox (badness 10000) detected at line 2039
+ []
+
+
+Underfull \vbox (badness 10000) detected at line 2039
+ []
+
+[40] [41] [42]
+Chapter 5.
+
+Overfull \hbox (116.47647pt too wide) in paragraph at lines 2076--2076
+[]
+ []
+
+
+Underfull \hbox (badness 10000) in paragraph at lines 2076--2076
+
+ []
+
+[43
+
+] [44]
+Underfull \vbox (badness 10000) detected at line 2294
+ []
+
+
+Underfull \vbox (badness 10000) detected at line 2294
+ []
+
+[45] [46] [47] [48]
+LaTeX Font Info:    Font shape `T1/phv/bx/n' in size <9> not available
+(Font)              Font shape `T1/phv/b/n' tried instead on input line 2454.
+ [49] [50] [51] [52] [53] [54] [55] [56] [57] [58] [59]
+[60] [61] [62] [63] [64] [65] [66] [67] [68] [69] [70] [71] [72]
+Chapter 6.
+[73
+
+] [74] [75] <FourierTransformEx1.pdf, id=1113, 337.26pt x 261.97874pt>
+File: FourierTransformEx1.pdf Graphic file (type pdf)
+
+<use FourierTransformEx1.pdf>
+Package pdftex.def Info: FourierTransformEx1.pdf used on input line 3734.
+(pdftex.def)             Requested size: 337.25917pt x 261.9781pt.
+File: FourierTransformEx1.pdf Graphic file (type pdf)
+ <use FourierTransformEx1.pdf>
+Package pdftex.def Info: FourierTransformEx1.pdf used on input line 3734.
+(pdftex.def)             Requested size: 337.25917pt x 261.9781pt.
+
+<FourierTransformEx2.pdf, id=1114, 515.9275pt x 224.84pt>
+File: FourierTransformEx2.pdf Graphic file (type pdf)
+
+<use FourierTransformEx2.pdf>
+Package pdftex.def Info: FourierTransformEx2.pdf used on input line 3743.
+(pdftex.def)             Requested size: 515.92624pt x 224.83945pt.
+File: FourierTransformEx2.pdf Graphic file (type pdf)
+ <use FourierTransformEx2.pdf>
+Package pdftex.def Info: FourierTransformEx2.pdf used on input line 3743.
+(pdftex.def)             Requested size: 452.96788pt x 197.40694pt.
+ [76 <./FourierTransformEx1.pdf>] <FourierTransformEx3.pdf, id=1183, 515.9275pt
+ x 255.95625pt>
+File: FourierTransformEx3.pdf Graphic file (type pdf)
+
+<use FourierTransformEx3.pdf>
+Package pdftex.def Info: FourierTransformEx3.pdf used on input line 3754.
+(pdftex.def)             Requested size: 515.92624pt x 255.95561pt.
+File: FourierTransformEx3.pdf Graphic file (type pdf)
+ <use FourierTransformEx3.pdf>
+Package pdftex.def Info: FourierTransformEx3.pdf used on input line 3754.
+(pdftex.def)             Requested size: 452.96788pt x 224.72664pt.
+LaTeX Font Info:    Font shape `T1/pcr/bx/n' in size <14.4> not available
+(Font)              Font shape `T1/pcr/b/n' tried instead on input line 3759.
+ [77 <./FourierTransformEx2.pdf> <./FourierTransformEx3.pdf>] [78]
+Chapter 7.
+[79
+
+] [80]
+Chapter 8.
+[81
+
+] [82
+
+]
+Chapter 9.
+[83] [84] [85] [86]
+Chapter 10.
+[87
+
+] [88
+
+]
+Chapter 11.
+[89]
+LaTeX Font Info:    Font shape `T1/pcr/bx/n' in size <10> not available
+(Font)              Font shape `T1/pcr/b/n' tried instead on input line 4144.
+
+Overfull \hbox (34.13051pt too wide) in paragraph at lines 4146--4146
+[]
+ []
+
+
+Underfull \hbox (badness 10000) in paragraph at lines 4146--4146
+
+ []
+
+
+Overfull \hbox (216.03926pt too wide) in paragraph at lines 4161--4161
+[]
+ []
+
+
+Underfull \hbox (badness 10000) in paragraph at lines 4161--4161
+
+ []
+
+
+Overfull \hbox (58.00885pt too wide) in paragraph at lines 4170--4170
+[]
+ []
+
+
+Underfull \hbox (badness 10000) in paragraph at lines 4170--4170
+
+ []
+
+[90] [91] [92
+
+]
+Chapter 12.
+[93] [94
+
+]
+Chapter 13.
+[95] [96] (./xmds2.ind)
+Package atveryend Info: Empty hook `BeforeClearDocument' on input line 4465.
+ [97]
+Package atveryend Info: Empty hook `AfterLastShipout' on input line 4465.
+ (./xmds2.aux)
+Package atveryend Info: Executing hook `AtVeryEndDocument' on input line 4465.
+Package atveryend Info: Executing hook `AtEndAfterFileList' on input line 4465.
+
+Package rerunfilecheck Info: File `xmds2.out' has not changed.
+(rerunfilecheck)             Checksum: F6F0AD2D22B608AC0B5B4144B3DB77CD;3905.
+Package atveryend Info: Empty hook `AtVeryVeryEnd' on input line 4465.
+ ) 
+Here is how much of TeX's memory you used:
+ 9678 strings out of 493481
+ 139300 string characters out of 3140966
+ 254299 words of memory out of 3000000
+ 12405 multiletter control sequences out of 15000+200000
+ 85999 words of font info for 99 fonts, out of 3000000 for 9000
+ 958 hyphenation exceptions out of 8191
+ 38i,28n,51p,7668b,584s stack positions out of 5000i,500n,10000p,200000b,50000s
+{/usr/local/texlive/2012/texmf-dist/fonts/enc/dvips/base/8r.enc}</usr/local/t
+exlive/2012/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx10.pfb></usr/local/te
+xlive/2012/texmf-dist/fonts/type1/public/amsfonts/cm/cmex10.pfb></usr/local/tex
+live/2012/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb></usr/local/texl
+ive/2012/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi5.pfb></usr/local/texliv
+e/2012/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi7.pfb></usr/local/texlive/
+2012/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb></usr/local/texlive/20
+12/texmf-dist/fonts/type1/public/amsfonts/cm/cmr5.pfb></usr/local/texlive/2012/
+texmf-dist/fonts/type1/public/amsfonts/cm/cmr7.pfb></usr/local/texlive/2012/tex
+mf-dist/fonts/type1/public/amsfonts/cm/cmsy10.pfb></usr/local/texlive/2012/texm
+f-dist/fonts/type1/public/amsfonts/cm/cmsy7.pfb></usr/local/texlive/2012/texmf-
+dist/fonts/type1/urw/courier/ucrb8a.pfb></usr/local/texlive/2012/texmf-dist/fon
+ts/type1/urw/courier/ucrbo8a.pfb></usr/local/texlive/2012/texmf-dist/fonts/type
+1/urw/courier/ucrr8a.pfb></usr/local/texlive/2012/texmf-dist/fonts/type1/urw/co
+urier/ucrro8a.pfb></usr/local/texlive/2012/texmf-dist/fonts/type1/urw/helvetic/
+uhvb8a.pfb></usr/local/texlive/2012/texmf-dist/fonts/type1/urw/helvetic/uhvbo8a
+.pfb></usr/local/texlive/2012/texmf-dist/fonts/type1/urw/times/utmb8a.pfb></usr
+/local/texlive/2012/texmf-dist/fonts/type1/urw/times/utmr8a.pfb></usr/local/tex
+live/2012/texmf-dist/fonts/type1/urw/times/utmri8a.pfb>
+Output written on xmds2.pdf (101 pages, 6678016 bytes).
+PDF statistics:
+ 1676 PDF objects out of 1728 (max. 8388607)
+ 1446 compressed objects within 15 object streams
+ 281 named destinations out of 1000 (max. 500000)
+ 500 words of extra memory for PDF output out of 10000 (max. 10000000)
+
diff --git a/documentation/latex/xmds2.out b/documentation/latex/xmds2.out
new file mode 100644
index 0000000..50db9de
--- /dev/null
+++ b/documentation/latex/xmds2.out
@@ -0,0 +1,53 @@
+\BOOKMARK [0][-]{chapter.1}{Introduction}{}% 1
+\BOOKMARK [0][-]{chapter.2}{Installation}{}% 2
+\BOOKMARK [1][-]{section.2.1}{Installers}{chapter.2}% 3
+\BOOKMARK [1][-]{section.2.2}{Linux installer instructions}{chapter.2}% 4
+\BOOKMARK [1][-]{section.2.3}{Mac OS X Installation}{chapter.2}% 5
+\BOOKMARK [1][-]{section.2.4}{Manual installation from source}{chapter.2}% 6
+\BOOKMARK [0][-]{chapter.3}{Quickstart Tutorial}{}% 7
+\BOOKMARK [0][-]{chapter.4}{Worked Examples}{}% 8
+\BOOKMARK [1][-]{section.4.1}{The nonlinear Schr\366dinger equation}{chapter.4}% 9
+\BOOKMARK [1][-]{section.4.2}{Kubo Oscillator}{chapter.4}% 10
+\BOOKMARK [1][-]{section.4.3}{Fibre Noise}{chapter.4}% 11
+\BOOKMARK [1][-]{section.4.4}{Integer Dimensions}{chapter.4}% 12
+\BOOKMARK [1][-]{section.4.5}{Wigner Function}{chapter.4}% 13
+\BOOKMARK [1][-]{section.4.6}{Finding the Ground State of a BEC \(continuous renormalisation\)}{chapter.4}% 14
+\BOOKMARK [1][-]{section.4.7}{Finding the Ground State of a BEC again}{chapter.4}% 15
+\BOOKMARK [1][-]{section.4.8}{Multi-component Schr\366dinger equation}{chapter.4}% 16
+\BOOKMARK [0][-]{chapter.5}{Reference section}{}% 17
+\BOOKMARK [1][-]{section.5.1}{Configuration, installation and runtime options}{chapter.5}% 18
+\BOOKMARK [1][-]{section.5.2}{Useful XML Syntax}{chapter.5}% 19
+\BOOKMARK [1][-]{section.5.3}{XMDS2 XML Schema}{chapter.5}% 20
+\BOOKMARK [1][-]{section.5.4}{XMDS2 script elements}{chapter.5}% 21
+\BOOKMARK [0][-]{chapter.6}{Advanced Topics}{}% 22
+\BOOKMARK [1][-]{section.6.1}{Importing data}{chapter.6}% 23
+\BOOKMARK [1][-]{section.6.2}{Convolutions and Fourier transforms}{chapter.6}% 24
+\BOOKMARK [1][-]{section.6.3}{`Loose' geometry\137matching\137mode}{chapter.6}% 25
+\BOOKMARK [1][-]{section.6.4}{Dimension aliases}{chapter.6}% 26
+\BOOKMARK [0][-]{chapter.7}{Frequently Asked Questions}{}% 27
+\BOOKMARK [1][-]{section.7.1}{XMDS scripts look complicated! How do I start?}{chapter.7}% 28
+\BOOKMARK [1][-]{section.7.2}{Where can I get help?}{chapter.7}% 29
+\BOOKMARK [1][-]{section.7.3}{How should I cite XMDS2?}{chapter.7}% 30
+\BOOKMARK [1][-]{section.7.4}{I think I found a bug! Where should I report it?}{chapter.7}% 31
+\BOOKMARK [1][-]{section.7.5}{How do I put time dependence into my vectors?}{chapter.7}% 32
+\BOOKMARK [1][-]{section.7.6}{Can I specify the range of my domain and number of grid points at run-time?}{chapter.7}% 33
+\BOOKMARK [1][-]{section.7.7}{When can I use IP operators \(and why should I\) and when must I use EX operators?}{chapter.7}% 34
+\BOOKMARK [1][-]{section.7.8}{Visual Editors}{chapter.7}% 35
+\BOOKMARK [0][-]{chapter.8}{Upgrading From XMDS 1.X}{}% 36
+\BOOKMARK [0][-]{chapter.9}{Optimisation Hints}{}% 37
+\BOOKMARK [1][-]{section.9.1}{Geometry and transform-based tricks}{chapter.9}% 38
+\BOOKMARK [1][-]{section.9.2}{Reduce code complexity}{chapter.9}% 39
+\BOOKMARK [1][-]{section.9.3}{Compiler and library tricks}{chapter.9}% 40
+\BOOKMARK [1][-]{section.9.4}{Atom-optics-specific hints}{chapter.9}% 41
+\BOOKMARK [0][-]{chapter.10}{xsil2graphics2}{}% 42
+\BOOKMARK [0][-]{chapter.11}{Developer Documentation}{}% 43
+\BOOKMARK [1][-]{section.11.1}{Test scripts}{chapter.11}% 44
+\BOOKMARK [1][-]{section.11.2}{Steps to update XMDS script validator \(XML schema\)}{chapter.11}% 45
+\BOOKMARK [1][-]{section.11.3}{Directory layout}{chapter.11}% 46
+\BOOKMARK [0][-]{chapter.12}{Licensing}{}% 47
+\BOOKMARK [0][-]{chapter.13}{News}{}% 48
+\BOOKMARK [1][-]{section.13.1}{XMDS 2.1.4 ``Well if this isn't nice, I don't know what is'' \(September 27, 2013\)}{chapter.13}% 49
+\BOOKMARK [1][-]{section.13.2}{XMDS 2.1.3 ``Happy Mollusc'' \(June 7, 2013\)}{chapter.13}% 50
+\BOOKMARK [1][-]{section.13.3}{XMDS 2.1.2 ``Happy Mollusc'' \(October 15, 2012\)}{chapter.13}% 51
+\BOOKMARK [1][-]{section.13.4}{XMDS 2.1 ``Happy Mollusc'' \(June 14, 2012\)}{chapter.13}% 52
+\BOOKMARK [1][-]{section.13.5}{XMDS 2.0 ``Shiny!'' \(September 13, 2010\)}{chapter.13}% 53
diff --git a/documentation/latex/xmds2.pdf b/documentation/latex/xmds2.pdf
new file mode 100644
index 0000000..82851f0
Binary files /dev/null and b/documentation/latex/xmds2.pdf differ
diff --git a/documentation/latex/xmds2.tex b/documentation/latex/xmds2.tex
new file mode 100644
index 0000000..2541003
--- /dev/null
+++ b/documentation/latex/xmds2.tex
@@ -0,0 +1,4465 @@
+% Generated by Sphinx.
+\def\sphinxdocclass{report}
+\documentclass[a4paper,10pt,english]{sphinxmanual}
+\usepackage[utf8]{inputenc}
+\DeclareUnicodeCharacter{00A0}{\nobreakspace}
+\usepackage{cmap}
+\usepackage[T1]{fontenc}
+\usepackage{babel}
+\usepackage{times}
+\usepackage[Bjarne]{fncychap}
+\usepackage{longtable}
+\usepackage{sphinx}
+\usepackage{multirow}
+
+
+\title{XMDS2 Documentation}
+\date{September 28, 2013}
+\release{2.1.4}
+\author{Graham Dennis, Joe Hope and Mattias Johnsson}
+\newcommand{\sphinxlogo}{\includegraphics{xmds_logo.pdf}\par}
+\renewcommand{\releasename}{Release}
+\makeindex
+
+\makeatletter
+\def\PYG at reset{\let\PYG at it=\relax \let\PYG at bf=\relax%
+    \let\PYG at ul=\relax \let\PYG at tc=\relax%
+    \let\PYG at bc=\relax \let\PYG at ff=\relax}
+\def\PYG at tok#1{\csname PYG at tok@#1\endcsname}
+\def\PYG at toks#1+{\ifx\relax#1\empty\else%
+    \PYG at tok{#1}\expandafter\PYG at toks\fi}
+\def\PYG at do#1{\PYG at bc{\PYG at tc{\PYG at ul{%
+    \PYG at it{\PYG at bf{\PYG at ff{#1}}}}}}}
+\def\PYG#1#2{\PYG at reset\PYG at toks#1+\relax+\PYG at do{#2}}
+
+\expandafter\def\csname PYG at tok@gu\endcsname{\let\PYG at bf=\textbf\def\PYG at tc##1{\textcolor[rgb]{0.50,0.00,0.50}{##1}}}
+\expandafter\def\csname PYG at tok@gt\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.00,0.27,0.87}{##1}}}
+\expandafter\def\csname PYG at tok@gs\endcsname{\let\PYG at bf=\textbf}
+\expandafter\def\csname PYG at tok@gr\endcsname{\def\PYG at tc##1{\textcolor[rgb]{1.00,0.00,0.00}{##1}}}
+\expandafter\def\csname PYG at tok@cm\endcsname{\let\PYG at it=\textit\def\PYG at tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}}
+\expandafter\def\csname PYG at tok@vg\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.73,0.38,0.84}{##1}}}
+\expandafter\def\csname PYG at tok@m\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}}
+\expandafter\def\csname PYG at tok@mh\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}}
+\expandafter\def\csname PYG at tok@cs\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}\def\PYG at bc##1{\setlength{\fboxsep}{0pt}\colorbox[rgb]{1.00,0.94,0.94}{\strut ##1}}}
+\expandafter\def\csname PYG at tok@ge\endcsname{\let\PYG at it=\textit}
+\expandafter\def\csname PYG at tok@gd\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.63,0.00,0.00}{##1}}}
+\expandafter\def\csname PYG at tok@il\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}}
+\expandafter\def\csname PYG at tok@go\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.20,0.20,0.20}{##1}}}
+\expandafter\def\csname PYG at tok@cp\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
+\expandafter\def\csname PYG at tok@gi\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.00,0.63,0.00}{##1}}}
+\expandafter\def\csname PYG at tok@gh\endcsname{\let\PYG at bf=\textbf\def\PYG at tc##1{\textcolor[rgb]{0.00,0.00,0.50}{##1}}}
+\expandafter\def\csname PYG at tok@ni\endcsname{\let\PYG at bf=\textbf\def\PYG at tc##1{\textcolor[rgb]{0.84,0.33,0.22}{##1}}}
+\expandafter\def\csname PYG at tok@nl\endcsname{\let\PYG at bf=\textbf\def\PYG at tc##1{\textcolor[rgb]{0.00,0.13,0.44}{##1}}}
+\expandafter\def\csname PYG at tok@nn\endcsname{\let\PYG at bf=\textbf\def\PYG at tc##1{\textcolor[rgb]{0.05,0.52,0.71}{##1}}}
+\expandafter\def\csname PYG at tok@no\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.38,0.68,0.84}{##1}}}
+\expandafter\def\csname PYG at tok@na\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}}
+\expandafter\def\csname PYG at tok@nb\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
+\expandafter\def\csname PYG at tok@nc\endcsname{\let\PYG at bf=\textbf\def\PYG at tc##1{\textcolor[rgb]{0.05,0.52,0.71}{##1}}}
+\expandafter\def\csname PYG at tok@nd\endcsname{\let\PYG at bf=\textbf\def\PYG at tc##1{\textcolor[rgb]{0.33,0.33,0.33}{##1}}}
+\expandafter\def\csname PYG at tok@ne\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
+\expandafter\def\csname PYG at tok@nf\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.02,0.16,0.49}{##1}}}
+\expandafter\def\csname PYG at tok@si\endcsname{\let\PYG at it=\textit\def\PYG at tc##1{\textcolor[rgb]{0.44,0.63,0.82}{##1}}}
+\expandafter\def\csname PYG at tok@s2\endcsname{\let\PYG at it=\textit\def\PYG at tc##1{\textcolor[rgb]{0.32,0.47,0.09}{##1}}}
+\expandafter\def\csname PYG at tok@vi\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.73,0.38,0.84}{##1}}}
+\expandafter\def\csname PYG at tok@nt\endcsname{\let\PYG at bf=\textbf\def\PYG at tc##1{\textcolor[rgb]{0.02,0.16,0.45}{##1}}}
+\expandafter\def\csname PYG at tok@nv\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.73,0.38,0.84}{##1}}}
+\expandafter\def\csname PYG at tok@s1\endcsname{\let\PYG at it=\textit\def\PYG at tc##1{\textcolor[rgb]{0.32,0.47,0.09}{##1}}}
+\expandafter\def\csname PYG at tok@vc\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.73,0.38,0.84}{##1}}}
+\expandafter\def\csname PYG at tok@sh\endcsname{\let\PYG at it=\textit\def\PYG at tc##1{\textcolor[rgb]{0.32,0.47,0.09}{##1}}}
+\expandafter\def\csname PYG at tok@ow\endcsname{\let\PYG at bf=\textbf\def\PYG at tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
+\expandafter\def\csname PYG at tok@sx\endcsname{\let\PYG at it=\textit\def\PYG at tc##1{\textcolor[rgb]{0.78,0.36,0.04}{##1}}}
+\expandafter\def\csname PYG at tok@bp\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
+\expandafter\def\csname PYG at tok@c1\endcsname{\let\PYG at it=\textit\def\PYG at tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}}
+\expandafter\def\csname PYG at tok@kc\endcsname{\let\PYG at bf=\textbf\def\PYG at tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
+\expandafter\def\csname PYG at tok@c\endcsname{\let\PYG at it=\textit\def\PYG at tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}}
+\expandafter\def\csname PYG at tok@mf\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}}
+\expandafter\def\csname PYG at tok@err\endcsname{\def\PYG at bc##1{\setlength{\fboxsep}{0pt}\fcolorbox[rgb]{1.00,0.00,0.00}{1,1,1}{\strut ##1}}}
+\expandafter\def\csname PYG at tok@kd\endcsname{\let\PYG at bf=\textbf\def\PYG at tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
+\expandafter\def\csname PYG at tok@ss\endcsname{\let\PYG at it=\textit\def\PYG at tc##1{\textcolor[rgb]{0.32,0.47,0.09}{##1}}}
+\expandafter\def\csname PYG at tok@sr\endcsname{\let\PYG at it=\textit\def\PYG at tc##1{\textcolor[rgb]{0.14,0.33,0.53}{##1}}}
+\expandafter\def\csname PYG at tok@mo\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}}
+\expandafter\def\csname PYG at tok@kn\endcsname{\let\PYG at bf=\textbf\def\PYG at tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
+\expandafter\def\csname PYG at tok@mi\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}}
+\expandafter\def\csname PYG at tok@gp\endcsname{\let\PYG at bf=\textbf\def\PYG at tc##1{\textcolor[rgb]{0.78,0.36,0.04}{##1}}}
+\expandafter\def\csname PYG at tok@o\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
+\expandafter\def\csname PYG at tok@kr\endcsname{\let\PYG at bf=\textbf\def\PYG at tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
+\expandafter\def\csname PYG at tok@s\endcsname{\let\PYG at it=\textit\def\PYG at tc##1{\textcolor[rgb]{0.32,0.47,0.09}{##1}}}
+\expandafter\def\csname PYG at tok@kp\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
+\expandafter\def\csname PYG at tok@w\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.73,0.73,0.73}{##1}}}
+\expandafter\def\csname PYG at tok@kt\endcsname{\def\PYG at tc##1{\textcolor[rgb]{0.56,0.13,0.00}{##1}}}
+\expandafter\def\csname PYG at tok@sc\endcsname{\let\PYG at it=\textit\def\PYG at tc##1{\textcolor[rgb]{0.32,0.47,0.09}{##1}}}
+\expandafter\def\csname PYG at tok@sb\endcsname{\let\PYG at it=\textit\def\PYG at tc##1{\textcolor[rgb]{0.32,0.47,0.09}{##1}}}
+\expandafter\def\csname PYG at tok@k\endcsname{\let\PYG at bf=\textbf\def\PYG at tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
+\expandafter\def\csname PYG at tok@se\endcsname{\let\PYG at bf=\textbf\let\PYG at it=\textit\def\PYG at tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}}
+\expandafter\def\csname PYG at tok@sd\endcsname{\let\PYG at it=\textit\def\PYG at tc##1{\textcolor[rgb]{0.32,0.47,0.09}{##1}}}
+
+\def\PYGZbs{\char`\\}
+\def\PYGZus{\char`\_}
+\def\PYGZob{\char`\{}
+\def\PYGZcb{\char`\}}
+\def\PYGZca{\char`\^}
+\def\PYGZam{\char`\&}
+\def\PYGZlt{\char`\<}
+\def\PYGZgt{\char`\>}
+\def\PYGZsh{\char`\#}
+\def\PYGZpc{\char`\%}
+\def\PYGZdl{\char`\$}
+\def\PYGZhy{\char`\-}
+\def\PYGZsq{\char`\'}
+\def\PYGZdq{\char`\"}
+\def\PYGZti{\char`\~}
+% for compatibility with earlier versions
+\def\PYGZat{@}
+\def\PYGZlb{[}
+\def\PYGZrb{]}
+\makeatother
+
+\begin{document}
+
+\maketitle
+\tableofcontents
+\phantomsection\label{documentation_toc::doc}
+
+
+
+\chapter{Introduction}
+\label{introduction:introduction}\label{introduction:documentation}\label{introduction::doc}\label{introduction:welcome-to-the-documentation-for-xmds2}
+Welcome to \textbf{XMDS2} (codenamed \emph{xpdeint}), which is an all-new version of {\hyperref[introduction:xmdshistory]{\emph{XMDS}}}.  Prepare for fast, easily-extended simulations with minimal code error.
+
+\textbf{Description:}   The purpose of XMDS2 is to simplify the process of creating simulations that solve systems of initial-value first-order partial and ordinary differential equations. Instead of going through the error-prone process of writing by hand thousands of lines of code, XMDS2 enables many problems to be described in a simple XML format. From this XML description XMDS2 writes a C++ simulation that solves the problem using fast algorithms. Anecdotally, the code generated by X [...]
+
+XMDS2 can be used to simulate almost any set of (coupled) (partial) (stochastic) differential equations in any number of dimensions.  It can input and output data in a range of data formats, produce programs that can take command-line arguments, and produce parallelised code suitable for either modern computer architectures or distributed clusters.
+
+If this is your first time with XMDS, then an ideal place to start is the {\hyperref[tutorial:quickstarttutorial]{\emph{Quickstart Tutorial}}}, where we will show you how to write a basic simulation.  {\hyperref[installation:installation]{\emph{Installation}}} instructions should get you up and running and able to start playing with the large library of examples provided. The impatient will probably have good luck browsing the examples library included with the source, and the {\hyperref [...]
+
+If you are upgrading from \textbf{XMDS version 1.x}, then after following the installation instructions ({\hyperref[installation:installation]{\emph{Installation}}}), you might want to have a quick read of the note for upgraders ({\hyperref[upgrade:upgradefromxmds1]{\emph{Upgrading From XMDS 1.X}}}).  The syntax of the XML scripts has changed, but hopefully you will find the new scripts very intuitive.
+
+Detailed advice on input/output issues, and ways to code more complicated simulations can be found in {\hyperref[advanced_topics:advancedtopics]{\emph{Advanced Topics}}}.
+
+XMDS2 should be cited as \href{http://dx.doi.org/10.1016/j.cpc.2012.08.016}{Comput. Phys. Commun. 184, 201-208 (2013)}.
+\phantomsection\label{introduction:xmdshistory}
+\textbf{History:}   \textbf{XMDS} was created in 1997 by Peter Drummond and Greg Collecutt, who conceived of the idea of using an XML-based code generator to simplify the process of integrating systems of equations with arbitrary dimension \footnote{
+G.R.Collecutt and P.D.Drummond, \emph{Xmds: eXtensible multi-dimensional simulator}, Comput. Phys. Commun. \textbf{142}, 219 (2001).
+}.  The first version was written in C, and featured a very flexible, strongly convergent stochastic algorithm: the {\hyperref[reference_elements:si]{\emph{semi-implicit algorithm}}} \footnote{
+M.J.Werner and P.D.Drummond, \emph{Robust algorithms for solving stochastic partial differential equations}, J. Comput. Phys. \textbf{132}, 312 (1997).
+}.  Released under a public licence, it began to receive attention across several research groups.  Over the next few years several people helped add new algorithms and features.
+
+In 2003, the increased scope of the package prompted a complete rewrite by Greg Collecutt (using C++), which lead to \textbf{XMDS 1.0}.  It was placed on sourceforge, and over a dozen developers contributed from 2003-2007 to help XMDS address a wider range of problems with a range of modern algorithms and support for parallel supercomputing.  The documentation and installation method was improved enabling the software to be used in a wider context, and XMDS gained many users from across  [...]
+
+In 2008 a second complete rewrite was undertaken, largely by Graham Dennis (using Cheetah templates in python), leading to the current version \textbf{XMDS2}.  This restructuring of the internal treatment of XML elements and the generated code allowed a new range of extensions to be explored.  These included possibilities such as integrating multiple fields with different dimensionality, a more general set of differential equations that can be solved efficiently, and multiple choices of  [...]
+
+
+\chapter{Installation}
+\label{installation:installation}\label{installation::doc}\label{installation:id1}
+\textbf{XMDS2} can be installed on any unix-like system including Linux, Tru64, and Mac OS X.  It requires a C++ compiler, python, and several installed packages.  Many of these packages are optional, but a good idea to obtain full functionality.
+
+
+\section{Installers}
+\label{installation:installers}
+The easiest way to get started is with an installer.  If we don't have an installer for your system, follow the {\hyperref[installation:manualinstallation]{\emph{manual installation}}} instructions.
+
+\begin{tabulary}{\linewidth}{|c|c|c|}
+\hline
+
+Linux (Ubuntu/Debian/Fedora/RedHat)
+ & 
+\href{http://svn.code.sf.net/p/xmds/code/trunk/xpdeint/admin/linux\_installer.sh}{Download Linux Installer}
+ & 
+{\hyperref[installation:linux-installation]{\emph{Learn more}}}
+\\
+
+OS X 10.6/10.7
+ & 
+\href{http://sourceforge.net/projects/xmds/files}{Download OS X Installer}
+ & 
+{\hyperref[installation:mac-installation]{\emph{Learn more}}}
+\\
+
+Other systems
+ & 
+{\hyperref[installation:manualinstallation]{\emph{Install from source}}}
+ & \\
+\hline\end{tabulary}
+
+
+If you have one of the supported operating systems listed above, but you find the installer doesn't work for you, please let us know by emailing xmds-devel \textless{}at\textgreater{} lists.sourceforge.net. If you'd like to tweak the linux installer to work on a distribution we haven't tested, we'd love you to do that and let us know!
+
+
+\section{Linux installer instructions}
+\label{installation:linux-installation}\label{installation:linux-installer-instructions}
+The linux installer has currently only been tested with Ubuntu, Debian, Fedora, and Red Hat. Download the installer here: \href{http://svn.code.sf.net/p/xmds/code/trunk/xpdeint/admin/linux\_installer.sh}{http://svn.code.sf.net/p/xmds/code/trunk/xpdeint/admin/linux\_installer.sh}
+
+Once you have downloaded it, make the installer executable and run it by typing the following into a terminal:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+chmod u+x linux\PYGZus{}installer.sh
+./linux\PYGZus{}installer.sh
+\end{Verbatim}
+
+Alternatively, if you wish to download and run the installer in a single step, you can use the following command:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+/bin/bash \PYGZhy{}c \PYGZdq{}\PYGZdl{}(wget \PYGZhy{}qO \PYGZhy{} http://svn.code.sf.net/p/xmds/code/trunk/xpdeint/admin/linux\PYGZus{}installer.sh)\PYGZdq{}
+\end{Verbatim}
+
+The linux installer installs all XMDS2 dependencies from your native package manager where possible (\code{apt-get} for Ubuntu/Debian, \code{yum} for Fedora/Red Hat) but will download and compile the source code for libraries not available through the package manager. This means you'll need to be connected to the internet when running the installer. The installer should not be run with administrative privileges; it will ask you to enter your admin password at the appropriate point.
+
+For instructions on how to install XMDS2 on systems where you lack administrative rights, see {\hyperref[installation:manualinstallation]{\emph{Manual installation from source}}}.
+
+By default, this installer will install a known stable version of XMDS, which can be updated at any time by navigating to the XMDS directory and typing `make update'. To install the latest developer version at the beginning, simply run the installer with the \code{-{-}develop} option.
+
+Once XMDS2 has been installed, you can run it from the terminal by typing \code{xmds2}. See the {\hyperref[tutorial:quickstarttutorial]{\emph{Quickstart Tutorial}}} for next steps.
+
+
+\section{Mac OS X Installation}
+\label{installation:mac-os-x-installation}\label{installation:mac-installation}
+
+\subsection{Download}
+\label{installation:download}
+Mac OS X 10.6 (Snow Leopard) or later XMDS 2 installer: \href{http://sourceforge.net/projects/xmds/files/}{http://sourceforge.net/projects/xmds/files/}
+
+
+\subsection{Using the Mac OS X Installer}
+\label{installation:using-the-mac-os-x-installer}
+A self-contained installer for Mac OS X 10.6 (Snow Leopard) and later is available from the link above. This installer is only compatible with Intel Macs.  This means that the older PowerPC architecture is \emph{not supported}.  Xcode (Apple's developer tools) is required to use this installer. Xcode is available for free from the Mac App Store for 10.7 or later, and is available on the install disk of earlier Macs as an optional install.  For users of earlier operating systems (10.6.8 o [...]
+
+Once you have downloaded the XMDS installer, installation is as simple as dragging it to your Applications folder or any other location.  Click the XMDS application to launch it, and press the ``Launch XMDS Terminal'' button to open a Terminal window customised to work with XMDS.  The first time you do this, the application will complete the installation process.  This process can take a few minutes, but is only performed once.
+
+The terminal window launched by the XMDS application has environment variables set for using this installation of XMDS.  You can run XMDS in this terminal by typing \code{xmds2}.  See the {\hyperref[tutorial:quickstarttutorial]{\emph{Quickstart Tutorial}}} for next steps.
+
+To uninstall XMDS, drag the XMDS application to the trash. XMDS places some files in the directory \code{\textasciitilde{}/Library/XMDS}. Remove this directory to completely remove XMDS from your system.
+
+This package includes binaries for \href{http://www.open-mpi.org}{OpenMPI}, \href{http://www.fftw.org}{FFTW}, \href{http://www.hdfgroup.org/HDF5}{HDF5} and \href{http://www.gnu.org/software/gsl}{GSL}. These binaries are self-contained and do not overwrite any existing installations.
+
+
+\section{Manual installation from source}
+\label{installation:manualinstallation}\label{installation:manual-installation-from-source}
+This installation guide will take you through a typical full install step by step. A large part of this procedure is obtaining and installing other libraries that XMDS2 requires, before installing XMDS2 itself.
+
+While the instructions below detail these packages individually, if you have administrative privileges (or can request packages from your administrator) and if you are using an Ubuntu, Debian, Fedora or Red Hat linux distribution, you can install all required and optional dependencies (but not XMDS2 itself) via
+
+Ubuntu / Debian:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+sudo apt\PYGZhy{}get install build\PYGZhy{}essential subversion libopenmpi\PYGZhy{}dev openmpi\PYGZhy{}bin python\PYGZhy{}dev python\PYGZhy{}setuptools python\PYGZhy{}cheetah python\PYGZhy{}numpy python\PYGZhy{}pyparsing python\PYGZhy{}lxml python\PYGZhy{}mpmath libhdf5\PYGZhy{}serial\PYGZhy{}dev libgsl0\PYGZhy{}dev python\PYGZhy{}sphinx python\PYGZhy{}h5py libatlas\PYGZhy{}base\PYGZhy{}dev
+\end{Verbatim}
+
+Fedora / Red Hat:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+sudo yum install gcc gcc\PYGZhy{}c++ make automake subversion openmpi\PYGZhy{}devel python\PYGZhy{}devel python\PYGZhy{}setuptools python\PYGZhy{}cheetah numpy gsl\PYGZhy{}devel python\PYGZhy{}sphinx libxml2\PYGZhy{}devel libxslt\PYGZhy{}devel atlas\PYGZhy{}devel hdf5\PYGZhy{}devel pyparsing pyparsing python\PYGZhy{}lxml python\PYGZhy{}mpmath h5py
+\end{Verbatim}
+
+You will still have to download and build FFTW 3.3 from source (see below) since prebuilt packages with MPI and AVX support are not currently available in the repositories.
+
+Also note that this guide adds extra notes for users wishing to install XMDS2 using the SVN repository.  This requires a few extra steps, but allows you to edit your copy, and/or update your copy very efficiently (with all the usual advantages and disadvantages of using unreleased material).
+\begin{enumerate}
+\setcounter{enumi}{-1}
+\item {} \begin{description}
+\item[{You will need a copy of XMDS2.}] \leavevmode
+The current release can be found at \href{http://sourceforge.net/projects/xmds/}{Sourceforge}, and downloaded as a single file.
+Download this file, and expand it in a directory where you want to keep the program files.
+\begin{itemize}
+\item {} 
+Developer-only instructions: You can instead check out a working copy of the source using SVN.
+In a directory where you want to check out the repository, run:
+\code{svn checkout https://svn.code.sf.net/p/xmds/code/trunk/xpdeint .}
+
+(Only do this once.  To update your copy, type \code{svn up} or \code{make update} in the same directory, and then repeat any developer-only instructions below).
+
+\end{itemize}
+
+\end{description}
+
+\item {} \begin{description}
+\item[{You will need a working C++ compiler.}] \leavevmode
+For Mac OS X, this means that the developer tools (XCode) should be installed.
+One common free compiler is \href{http://gcc.gnu.org/}{gcc}.  It can be downloaded using your favourite package manager.
+XMDS2 can also use Intel's C++ compiler if you have it.
+Intel's compiler typically generates faster code than gcc, but it isn't free.
+
+\end{description}
+
+\item {} 
+You will need a \href{http://www.python.org/}{python distribution}.
+\begin{itemize}
+\item {} 
+Mac OS X: It is pre-installed on Mac OS X 10.5 or later.
+
+\item {} 
+Linux: It should be pre-installed. If not, install using your favourite package manager.
+
+\end{itemize}
+\begin{quote}
+
+We require python 2.4 or greater. XMDS2 does not support Python 3.
+\end{quote}
+
+\item {} \begin{description}
+\item[{Install setuptools.}] \leavevmode
+If you have root (sudo) access, the easy way to install this is by executing
+ez\_setup.py from the repository. Simply type \code{sudo python ez\_setup.py}
+\begin{quote}
+
+If you want to install into your home directory without root access, this is more complex:
+\begin{enumerate}
+\item {} 
+First create the path \textasciitilde{}/lib/python2.5/site-packages (assuming you installed python version 2.5) and \textasciitilde{}/bin
+Add ``export PYTHONPATH=\textasciitilde{}/lib/python2.5/site-packages:\$PYTHONPATH'' and ``export PATH=\textasciitilde{}/bin:\$PATH'' (if necessary)
+to your .bashrc file (and run ''. \textasciitilde{}/.bashrc'')
+
+\item {} 
+If necessary install setuptools, by executing ez\_setup.py from the repository.
+\code{python ez\_setup.py -{-}prefix=\textasciitilde{}}
+
+\end{enumerate}
+\end{quote}
+
+If you use Mac OS X 10.5 or later, or installed the Enthought Python Distribution on Windows, then setuptools is already installed.
+Though if the next step fails, you may need to upgrade setuptools.  To do that, type \code{sudo easy\_install -U setuptools}
+
+\end{description}
+
+\item {} \begin{description}
+\item[{Install HDF5 and FFTW3 (and optionally MPI).}] \leavevmode\phantomsection\label{installation:hdf5-installation}\begin{enumerate}
+\item {} \begin{description}
+\item[{\textbf{HDF5} is a library for reading and writing the \href{http://www.hdfgroup.org/HDF5/}{Hierarchical Data Format}.}] \leavevmode
+This is a standardised data format which it is suggested that people use in preference to the older `binary' output (which is
+compatible with xmds-1). The advantage of HDF5 is that this data format is understood by a variety of other tools. xsil2graphics2
+provides support for loading data created in this format into Mathematica and Matlab.
+
+XMDS2 only requires the single process version of HDF5, so there is no need to install the MPI version.
+
+* Sidebar: Installing HDF5 from source follows a common pattern, which you may find yourself repeating later:
+\begin{enumerate}
+\item {} 
+After extracting the source directory, type \code{configure} and then add possible options.
+\begin{quote}
+
+(For HDF5, install with the \code{-{-}prefix=/usr/local/} option if you want XMDS2 to find the library automatically.  This is rarely needed for other packages.)
+\end{quote}
+
+\item {} 
+Once that is finished, type \code{make}.  Then wait for that to finish, which will often be longer than you think.
+
+\item {} 
+Finally, type \code{sudo make install} to install it into the appropriate directory.
+
+\end{enumerate}
+
+\end{description}
+
+\item {} \begin{description}
+\item[{\textbf{FFTW} is the library XMDS2 uses for Fourier transforms.}] \leavevmode
+This is the transform most people will use in their simulations. If you need
+support for MPI distributed simulations, you must configure FFTW to use MPI.
+
+FFTW is available for free at the \href{http://www.fftw.org/}{FFTW website}.
+To configure and compile it, follow the steps described in the HDF5 sidebar above.
+You may wish to add the \code{-{-}enable-mpi -{-}disable-fortran} options to the \code{configure} command.
+
+\end{description}
+
+\item {} \begin{description}
+\item[{\textbf{MPI} is an API for doing parallel processing.}] \leavevmode
+XMDS2 can use MPI to parallelise simulations on multi-processor/multi-core computers, or clusters of computers.
+Many supercomputing systems come with MPI libraries pre-installed.
+The \href{http://www.open-mpi.org/}{Open MPI} project has free distributions of this library available.
+
+If you intend to take advantage of XMDS2's multi-processing features, you must install MPI, and configure FFTW3 to use it.
+
+\end{description}
+
+\end{enumerate}
+
+\end{description}
+
+\item {} 
+There are a range of optional installs.  We recommend that you install them all if possible:
+\begin{enumerate}
+\item {} \begin{description}
+\item[{A Matrix library like \href{http://math-atlas.sourceforge.net/}{ATLAS}, Intel's \href{http://software.intel.com/en-us/intel-mkl/}{MKL} or the \href{http://www.gnu.org/software/gsl/}{GNU Scientific library (GSL)}}] \leavevmode
+These libraries allow efficient implementation of transform spaces other than Fourier space.
+Mac OS X comes with its own (fast) matrix library.
+
+\end{description}
+
+\item {} \begin{description}
+\item[{\textbf{numpy} is a tool that XMDS2 uses for automated testing.}] \leavevmode
+It can be installed with \code{sudo easy\_install numpy}.
+
+Mac OS X 10.5 and later come with numpy.
+
+\end{description}
+
+\item {} \begin{description}
+\item[{\textbf{lxml} is used to validate the syntax of scripts passed to XMDS2.}] \leavevmode
+If you have root access, this can be installed with the command \code{sudo easy\_install lxml}
+
+You will need to have `libxml2' and `libxslt' installed (via your choice of package manager) to install lxml.
+Sufficient versions are preinstalled on Mac OS X 10.6.
+\begin{description}
+\item[{If you don't have root access or want to install into your home directory, use:}] \leavevmode
+\code{easy\_install -{-}prefix=\textasciitilde{} lxml}
+
+\end{description}
+
+\end{description}
+
+\item {} \begin{description}
+\item[{\textbf{h5py} is needed for checking the results of XMDS2 tests that generate HDF5 output.}] \leavevmode
+h5py requires numpy version 1.0.3 or later.
+
+Upgrading \href{http://h5py.alfven.org/}{h5py} on Mac OS X is best done with the source of the package, as the easy\_install option can get confused with multiple numpy versions.
+(Mac OS X Snow Leopard comes with version 1.2.1).
+After downloading the source, execute \code{python ./setup.py build} in the source directory, and then \code{python ./setup.py install} to install it.
+
+\end{description}
+
+\end{enumerate}
+
+\item {} \begin{description}
+\item[{Install XMDS2 into your python path by running (in the xmds-2.1.4/ directory):}] \leavevmode
+\code{sudo ./setup.py develop}
+
+If you want to install it into your home directory, type \code{./setup.py develop -{-}prefix=\textasciitilde{}}
+
+This step requires access to the net, as it downloads any dependent packages.  If you are behind a firewall, you may need to set your HTTP\_PROXY environment variable in order to do this.
+\begin{itemize}
+\item {} \begin{description}
+\item[{Developer only instructions:}] \leavevmode
+The Cheetah templates (*.tmpl) must be compiled into python.
+To do this, run \code{make} in the xmds-2.1.4/ directory.
+
+\end{description}
+
+\item {} \begin{description}
+\item[{Developer-only instructions:}] \leavevmode
+If you have `numpy' installed, test XMDS2 by typing \code{./run\_tests.py} in the xmds-2.1.4/ directory.
+The package `numpy' is one of the optional packages, with installation instructions below.
+
+\end{description}
+
+\item {} \begin{description}
+\item[{Developer-only instructions:}] \leavevmode
+To build the user documentation, you first need to install sphinx, either via your package manager or:
+\code{sudo easy\_install Sphinx}
+
+Then, to build the documentation, in the xmds-2.1.4/admin/userdoc-source/ directory run: \code{make html}
+
+If this results in an error, you may need to run \code{sudo ./setup.py develop}
+
+The generated html documentation will then be found at xmds-2.1.4/documentation/index.html
+
+\end{description}
+
+\end{itemize}
+
+\end{description}
+
+\item {} 
+Configure XMDS2 by typing \code{xmds2 -{-}reconfigure}.  If XMDS2 is unable to find a library, you can tell XMDS2 where these libraries are located by adding \code{include} and \code{lib} search paths using the \code{-{-}include-path} and \code{-{-}lib-path} options.  For example, if FFTW3 is installed in \code{/apps/fftw3} with headers in \code{/apps/fftw3/include/} and the libraries in \code{/apps/fftw3/lib}, (re)configure XMDS2 by typing:
+\begin{quote}
+\begin{itemize}
+\item {} 
+\code{xmds2 -{-}reconfigure -{-}include-path /apps/fftw3/include -{-}lib-path /apps/fftw3/lib}.
+
+\end{itemize}
+
+If you need to use additional compiler or link flags for XMDS2 to use certain libraries, set the \code{CXXFLAGS} or \code{LINKFLAGS} environment variables before calling \code{xmds2 -{-}reconfigure}.  For example, to pass the compiler flag \code{-pedantic} and the link flag \code{-lm}, use:
+\begin{itemize}
+\item {} 
+\code{CXXFLAGS="-pedantic" LINKFLAGS="-lm" xmds2 -{-}reconfigure}.
+
+\end{itemize}
+\end{quote}
+
+\end{enumerate}
+
+\textbf{Congratulations!} You should now have a fully operational copy of xmds2 and xsil2graphics2.  You can test your copy using examples from the ``xmds-2.1.4/examples'' directory, and follow the worked examples in the {\hyperref[tutorial:quickstarttutorial]{\emph{Quickstart Tutorial}}} and {\hyperref[worked_examples:workedexamples]{\emph{Worked Examples}}}.
+
+
+\chapter{Quickstart Tutorial}
+\label{tutorial::doc}\label{tutorial:quickstart-tutorial}\label{tutorial:quickstarttutorial}
+In this tutorial, we will create an XMDS2 script to solve the Lorenz Attractor, an example of a dynamical system that exhibits chaos. The equations describing this problem are
+\begin{gather}
+\begin{split}\frac{dx}{dt} &= \sigma (y - x)\\
+\frac{dy}{dt} &= x (\rho - z) - y\\
+\frac{dz}{dt} &= xy - \beta z\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+where we will solve with the parameters $\sigma=10$, $\rho=28$, $\beta = \frac{8}{3}$ and the initial condition $x(0) = y(0) = z(0) = 1$.
+
+Below is a script that solves this problem (it's also saved as examples/lorenz.xmds in your XMDS2 directory). Don't worry if it doesn't make sense yet, soon we'll break it down into easily digestible parts.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{c+cp}{\PYGZlt{}?xml version=\PYGZdq{}1.0\PYGZdq{} encoding=\PYGZdq{}UTF\PYGZhy{}8\PYGZdq{}?\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}name}\PYG{n+nt}{\PYGZgt{}}lorenz\PYG{n+nt}{\PYGZlt{}/name\PYGZgt{}}
+
+  \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ While not strictly necessary, the following two tags are handy. }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}author}\PYG{n+nt}{\PYGZgt{}}Graham Dennis\PYG{n+nt}{\PYGZlt{}/author\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}description}\PYG{n+nt}{\PYGZgt{}}
+    The Lorenz Attractor, an example of chaos.
+  \PYG{n+nt}{\PYGZlt{}/description\PYGZgt{}}
+
+  \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}
+\PYG{c}{  This element defines some constants.  It can be used for other}
+\PYG{c}{  features as well, but we will go into that in more detail later.}
+\PYG{c}{  }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}features}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}globals}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n+nf}{real} \PYG{n}{sigma} \PYG{o}{=} \PYG{l+m+mf}{10.0}\PYG{p}{;}
+        \PYG{n+nf}{real} \PYG{n}{b} \PYG{o}{=} \PYG{l+m+mf}{8.0}\PYG{o}{/}\PYG{l+m+mf}{3.0}\PYG{p}{;}
+        \PYG{n+nf}{real} \PYG{n}{r} \PYG{o}{=} \PYG{l+m+mf}{28.0}\PYG{p}{;}
+        \PYG{c+cp}{]]\PYGZgt{}}
+     \PYG{n+nt}{\PYGZlt{}/globals\PYGZgt{}}
+   \PYG{n+nt}{\PYGZlt{}/features\PYGZgt{}}
+
+  \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}
+\PYG{c}{  This part defines all of the dimensions used in the problem,}
+\PYG{c}{  in this case, only the dimension of \PYGZsq{}time\PYGZsq{} is needed.}
+\PYG{c}{  }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+
+  \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ A \PYGZsq{}vector\PYGZsq{} describes the variables that we will be evolving. }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}position\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}
+      x y z
+    \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{n}{x} \PYG{o}{=} \PYG{n}{y} \PYG{o}{=} \PYG{n}{z} \PYG{o}{=} \PYG{l+m+mf}{1.0}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}sequence}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}
+\PYG{c}{    Here we define what differential equations need to be solved}
+\PYG{c}{    and what algorithm we want to use.}
+\PYG{c}{    }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}integrate} \PYG{n+na}{algorithm=}\PYG{l+s}{\PYGZdq{}ARK89\PYGZdq{}} \PYG{n+na}{interval=}\PYG{l+s}{\PYGZdq{}20.0\PYGZdq{}} \PYG{n+na}{tolerance=}\PYG{l+s}{\PYGZdq{}1e\PYGZhy{}7\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}samples}\PYG{n+nt}{\PYGZgt{}}5000\PYG{n+nt}{\PYGZlt{}/samples\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}operators}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}integration\PYGZus{}vectors}\PYG{n+nt}{\PYGZgt{}}position\PYG{n+nt}{\PYGZlt{}/integration\PYGZus{}vectors\PYGZgt{}}
+        \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{dx\PYGZus{}dt} \PYG{o}{=} \PYG{n}{sigma}\PYG{o}{*}\PYG{p}{(}\PYG{n}{y}\PYG{o}{\PYGZhy{}}\PYG{n}{x}\PYG{p}{)}\PYG{p}{;}
+        \PYG{n}{dy\PYGZus{}dt} \PYG{o}{=} \PYG{n}{r}\PYG{o}{*}\PYG{n}{x} \PYG{o}{\PYGZhy{}} \PYG{n}{y} \PYG{o}{\PYGZhy{}} \PYG{n}{x}\PYG{o}{*}\PYG{n}{z}\PYG{p}{;}
+        \PYG{n}{dz\PYGZus{}dt} \PYG{o}{=} \PYG{n}{x}\PYG{o}{*}\PYG{n}{y} \PYG{o}{\PYGZhy{}} \PYG{n}{b}\PYG{o}{*}\PYG{n}{z}\PYG{p}{;}
+        \PYG{c+cp}{]]\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}/operators\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/integrate\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/sequence\PYGZgt{}}
+
+  \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ This part defines what data will be saved in the output file }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}output} \PYG{n+na}{format=}\PYG{l+s}{\PYGZdq{}hdf5\PYGZdq{}} \PYG{n+na}{filename=}\PYG{l+s}{\PYGZdq{}lorenz.xsil\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}}xR yR zR\PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}position\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{xR} \PYG{o}{=} \PYG{n}{x}\PYG{p}{;}
+        \PYG{n}{yR} \PYG{o}{=} \PYG{n}{y}\PYG{p}{;}
+        \PYG{n}{zR} \PYG{o}{=} \PYG{n}{z}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/output\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+You can compile and run this script with \textbf{XMDS2}. To compile the script, just pass the name of the script as an argument to \textbf{XMDS2}.
+\begin{quote}
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYGZdl{} xmds2 lorenz.xmds
+xmds2 version 2.1 \PYGZdq{}Happy Mollusc\PYGZdq{} (r2680)
+Copyright 2000\PYGZhy{}2012 Graham Dennis, Joseph Hope, Mattias Johnsson
+                    and the xmds team
+Generating source code...
+... done
+Compiling simulation...
+... done. Type \PYGZsq{}./lorenz\PYGZsq{} to run.
+\end{Verbatim}
+\end{quote}
+
+Now we can execute the generated program `lorenz'.
+\begin{quote}
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYGZdl{} ./lorenz
+Sampled field (for moment group \PYGZsh{}1) at t = 0.000000e+00
+Sampled field (for moment group \PYGZsh{}1) at t = 4.000000e\PYGZhy{}03
+Current timestep: 4.000000e\PYGZhy{}03
+Sampled field (for moment group \PYGZsh{}1) at t = 8.000000e\PYGZhy{}03
+Current timestep: 4.000000e\PYGZhy{}03
+
+... many lines omitted ...
+
+Current timestep: 4.000000e\PYGZhy{}03
+Sampled field (for moment group \PYGZsh{}1) at t = 1.999600e+01
+Current timestep: 4.000000e\PYGZhy{}03
+Sampled field (for moment group \PYGZsh{}1) at t = 2.000000e+01
+Current timestep: 4.000000e\PYGZhy{}03
+Segment 1: minimum timestep: 9.997900e\PYGZhy{}06 maximum timestep: 4.000000e\PYGZhy{}03
+  Attempted 7386 steps, 0.00\PYGZpc{} steps failed.
+Generating output for lorenz
+\end{Verbatim}
+\end{quote}
+
+The program generated by \textbf{XMDS2} has now integrated your equations and produced two files.  The first is the XML file ``lorenz.xsil'', which contains the all the information used to generate the simulation (including the XMDS2 code) and the metadata description of the output.  The second file is named ``lorenz.h5'', which is a \href{http://www.hdfgroup.org/HDF5}{HDF5} file containing all of the output data.   You can analysing these files yourself, or import them into your favouri [...]
+\begin{quote}
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYGZdl{} xsil2graphics2 \PYGZhy{}e lorenz.xsil
+xsil2graphics2 from xmds2 version 2.1 \PYGZdq{}Happy Mollusc\PYGZdq{} (r2680)
+Generating output for Mathematica 6+.
+Writing import script for \PYGZsq{}lorenz.xsil\PYGZsq{} to \PYGZsq{}lorenz.nb\PYGZsq{}.
+\end{Verbatim}
+\end{quote}
+
+This has now generated the file `lorenz.nb', which is a Mathematica notebook that loads the output data of the simulation.  Loading it into Mathematica allows us to plot the points \{xR1, yR1, zR1\}:
+\begin{quote}
+
+\begin{Verbatim}[commandchars=\\\{\}]
+ll = Transpose[\PYGZob{}xR1, yR1, zR1\PYGZcb{}];
+ListPointPlot3D[ll]
+\end{Verbatim}
+\end{quote}
+
+{\hfill\includegraphics{lorenz.pdf}\hfill}
+
+...and we see the lobes of the strange attractor.  Now let us examine the code that produced this simulation.
+
+First, we have the top level description of the code.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{c+cp}{\PYGZlt{}?xml version=\PYGZdq{}1.0\PYGZdq{} encoding=\PYGZdq{}UTF\PYGZhy{}8\PYGZdq{}?\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}name}\PYG{n+nt}{\PYGZgt{}}lorenz\PYG{n+nt}{\PYGZlt{}/name\PYGZgt{}}
+
+  \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ While not strictly necessary, the following two tags are handy. }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}author}\PYG{n+nt}{\PYGZgt{}}Graham Dennis\PYG{n+nt}{\PYGZlt{}/author\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}description}\PYG{n+nt}{\PYGZgt{}}
+    The Lorenz Attractor, an example of chaos.
+  \PYG{n+nt}{\PYGZlt{}/description\PYGZgt{}}
+\end{Verbatim}
+
+One of the advantages of an XML format is that these tags are almost entirely self-explanatory.  XMDS2 files follow full XML syntax, so elements can be commented out using the \code{\textless{}!-{-}} and \code{-{-}\textgreater{}} brackets, and we have an example of that here.
+
+The first line, \code{\textless{}?xml ...\textgreater{}}, just specifies the encoding and XML version. It is optional, but its presence helps some text editors perform the correct syntax highlighting.
+
+The \code{\textless{}simulation\textgreater{}} element is mandatory, and encloses the entire simulation script.
+
+The \code{\textless{}name\textgreater{}} element is optional, but recommended. It defines the name of the executable program that will be generated, as well as the default name of the output data files (although this can be over-ridden in the \code{\textless{}output\textgreater{}} element if desired). If \code{\textless{}name\textgreater{}} is not present, it will default to the filename of the script.
+
+The next element we have used can be skipped entirely if you wish to use the default set of features and you don't want to define any global constants for your simulation.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}features}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}globals}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{n+nf}{real} \PYG{n}{sigma} \PYG{o}{=} \PYG{l+m+mf}{10.0}\PYG{p}{;}
+      \PYG{n+nf}{real} \PYG{n}{b} \PYG{o}{=} \PYG{l+m+mf}{8.0}\PYG{o}{/}\PYG{l+m+mf}{3.0}\PYG{p}{;}
+      \PYG{n+nf}{real} \PYG{n}{r} \PYG{o}{=} \PYG{l+m+mf}{28.0}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+   \PYG{n+nt}{\PYGZlt{}/globals\PYGZgt{}}
+ \PYG{n+nt}{\PYGZlt{}/features\PYGZgt{}}
+\end{Verbatim}
+
+The \code{\textless{}features\textgreater{}} element can be used to choose a large number of features that will be discussed later, but here we have only used it to define a \code{\textless{}globals\textgreater{}} element.  This element contains a block of text with \code{\textless{}!{[}CDATA{[}} at the start and \code{{]}{]}\textgreater{}} at the end.  These `CDATA' blocks  are used in several places in an XMDS script, and define a block of text that will be pasted directly into the gen [...]
+
+The next element is the essential \code{\textless{}geometry\textgreater{}} element.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+\end{Verbatim}
+
+This element is used to define all the dimensions in the problem.  We only require the time dimension, which we are labelling `t', so this is a trivial example.  We will discuss transverse dimensions in more detail in the next worked example ({\hyperref[worked_examples:nonlinearschrodingerequation]{\emph{The nonlinear Schrödinger equation}}}), where we deal with the integration of a partial differential equation rather than ordinary differential equations.
+
+Next, we have the \code{\textless{}vector\textgreater{}} element.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}position\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}
+    x y z
+  \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{c+cp}{\PYGZlt{}![CDATA[}
+    \PYG{n}{x} \PYG{o}{=} \PYG{n}{y} \PYG{o}{=} \PYG{n}{z} \PYG{o}{=} \PYG{l+m+mf}{1.0}\PYG{p}{;}
+    \PYG{c+cp}{]]\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+\end{Verbatim}
+
+We can define multiple vectors, but here we only need the variables that we wish to integrate.  We named this vector ``position'', as it defines the position in phase space.  These variables are real-valued (as opposed to, say, complex numbers), so we define \code{type="real"}.  The \code{\textless{}components\textgreater{}} element defines the names of the elements of this vector, which we have called `x', `y' and `z'.  Finally, we provide the initial values of the variables in a CDATA  [...]
+
+Now we come to the heart of the simulation, where we define the evolution of our vector.  This evolution is held in the \code{\textless{}sequence\textgreater{}} element, which contains an ordered sequence of actions upon any defined vectors.  Vectors can be altered with a \code{\textless{}filter\textgreater{}} element, or integrated in the propagation dimension with an \code{\textless{}integrate\textgreater{}} element.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}sequence}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}integrate} \PYG{n+na}{algorithm=}\PYG{l+s}{\PYGZdq{}ARK89\PYGZdq{}} \PYG{n+na}{interval=}\PYG{l+s}{\PYGZdq{}20.0\PYGZdq{}} \PYG{n+na}{tolerance=}\PYG{l+s}{\PYGZdq{}1e\PYGZhy{}7\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}samples}\PYG{n+nt}{\PYGZgt{}}5000\PYG{n+nt}{\PYGZlt{}/samples\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}operators}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}integration\PYGZus{}vectors}\PYG{n+nt}{\PYGZgt{}}position\PYG{n+nt}{\PYGZlt{}/integration\PYGZus{}vectors\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{n}{dx\PYGZus{}dt} \PYG{o}{=} \PYG{n}{sigma}\PYG{o}{*}\PYG{p}{(}\PYG{n}{y}\PYG{o}{\PYGZhy{}}\PYG{n}{x}\PYG{p}{)}\PYG{p}{;}
+      \PYG{n}{dy\PYGZus{}dt} \PYG{o}{=} \PYG{n}{r}\PYG{o}{*}\PYG{n}{x} \PYG{o}{\PYGZhy{}} \PYG{n}{y} \PYG{o}{\PYGZhy{}} \PYG{n}{x}\PYG{o}{*}\PYG{n}{z}\PYG{p}{;}
+      \PYG{n}{dz\PYGZus{}dt} \PYG{o}{=} \PYG{n}{x}\PYG{o}{*}\PYG{n}{y} \PYG{o}{\PYGZhy{}} \PYG{n}{b}\PYG{o}{*}\PYG{n}{z}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/operators\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/integrate\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/sequence\PYGZgt{}}
+\end{Verbatim}
+
+Here our sequence consists of a single \code{\textless{}integrate\textgreater{}} element.  It contains several important pieces of information.  At the heart, the \code{\textless{}operators\textgreater{}} element contains the equations of motion as described above, written in a very human-readable fashion.  It also contains an \code{\textless{}integration\_vectors\textgreater{}} element, which defines which vectors are used in this integrate block.  We have only one vector defined in thi [...]
+
+All integrate blocks must define which algorithm is to be used - in this case the 8th (embedded 9th) order adaptive Runge-Kutta method, called ``ARK89''.  The details of different algorithms will be described later (FIXME: Link!), but for now all we need to know is that this algorithm requires a tolerance, and that smaller means more accurate, so we'll make it $10^{-7}$ by setting \code{tolerance="1.0e-7"}.  Finally, any integration will proceed a certain length in the propagation dimens [...]
+
+The \code{\textless{}samples\textgreater{}} element says that the values of the output groups will be sampled 5000 times during this interval.  The nature of the output is defined in the last element in the simulation: the \code{\textless{}output\textgreater{}} element.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}output} \PYG{n+na}{format=}\PYG{l+s}{\PYGZdq{}hdf5\PYGZdq{}} \PYG{n+na}{filename=}\PYG{l+s}{\PYGZdq{}lorenz.xsil\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}}xR yR zR\PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}position\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+    \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{n}{xR} \PYG{o}{=} \PYG{n}{x}\PYG{p}{;}
+      \PYG{n}{yR} \PYG{o}{=} \PYG{n}{y}\PYG{p}{;}
+      \PYG{n}{zR} \PYG{o}{=} \PYG{n}{z}\PYG{p}{;}
+    \PYG{c+cp}{]]\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/output\PYGZgt{}}
+\end{Verbatim}
+
+The two top-level arguments in the \code{\textless{}output\textgreater{}} element are ``format'' and ``filename''.  Here we define the output filename, although it would have defaulted to this value.  We also choose the format to be HDF5, which is why the simulation resulted in the binary file ``lorenz.h5'' as well as ``lorenz.xsil''.  If we had instead said \code{format="ascii"}, then all of the output data would have been written in text form in ``lorenz.xsil''.
+
+The \code{\textless{}output\textgreater{}} element can contain any non-zero number of \code{\textless{}sampling\_group\textgreater{}} elements, which specify the entire output of the program.  They allow for subsampling, integration of some or all of the transverse dimensions, and/or conversion of some dimensions into Fourier space, but these will be described in more detail in the following examples.  We have a \code{\textless{}dependencies\textgreater{}} element that specifies which ve [...]
+
+And that's it.  This is quite a large framework to integrate three coupled ordinary differential equations, but the advantage of using XMDS2 is that vastly more complicated simulations can be performed without increasing the length or complexity of the XMDS2 script significantly.  The {\hyperref[worked_examples:workedexamples]{\emph{Worked Examples}}} section will provide more complicated examples with stochastic equations and partial differential equations.  If you are moved to solve yo [...]
+
+
+\chapter{Worked Examples}
+\label{worked_examples:worked-examples}\label{worked_examples::doc}\label{worked_examples:workedexamples}
+One of the best ways to learn XMDS2 is to see several illustrative examples.  Here are a set of example scripts and explanations of the code, which will be a good way to get started.  As an instructional aid, they are meant to be read sequentially, but the adventurous could try starting with one that looked like a simulation they wanted to run, and adapt for their own purposes.
+\begin{quote}
+
+{\hyperref[worked_examples:nonlinearschrodingerequation]{\emph{The nonlinear Schrödinger equation}}} (partial differential equation)
+
+{\hyperref[worked_examples:kubo]{\emph{Kubo Oscillator}}} (stochastic differential equations)
+
+{\hyperref[worked_examples:fibre]{\emph{Fibre Noise}}} (stochastic partial differential equation using parallel processing)
+
+{\hyperref[worked_examples:integerdimensionexample]{\emph{Integer Dimensions}}} (integer dimensions)
+
+{\hyperref[worked_examples:wignerarguments]{\emph{Wigner Function}}} (two dimensional PDE using parallel processing, passing arguments in at run time)
+
+{\hyperref[worked_examples:groundstatebec]{\emph{Finding the Ground State of a BEC (continuous renormalisation)}}} (PDE with continual renormalisation - computed vectors, filters, breakpoints)
+
+{\hyperref[worked_examples:hermitegaussgroundstatebec]{\emph{Finding the Ground State of a BEC again}}} (Hermite-Gaussian basis)
+
+{\hyperref[worked_examples:dmultistatese]{\emph{Multi-component Schrödinger equation}}} (combined integer and continuous dimensions with matrix multiplication, aliases)
+\end{quote}
+
+All of these scripts are available in the included ``examples'' folder, along with more examples that demonstrate other tricks.  Together, they provide starting points for a huge range of different simulations.
+
+
+\section{The nonlinear Schrödinger equation}
+\label{worked_examples:nonlinearschrodingerequation}\label{worked_examples:the-nonlinear-schrodinger-equation}
+This worked example will show a range of new features that can be used in an \textbf{XMDS2} script, and we will also examine our first partial differential equation.  We will take the one dimensional nonlinear Schrödinger equation, which is a common nonlinear wave equation.  The equation describing this problem is:
+\begin{gather}
+\begin{split}\frac{\partial \phi}{\partial \xi} = \frac{i}{2}\frac{\partial^2 \phi}{\partial \tau^2} - \Gamma(\tau)\phi+i|\phi|^2 \phi\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+where $\phi$ is a complex-valued field, and $\Gamma(\tau)$ is a $\tau$-dependent damping term.  Let us look at an XMDS2 script that integrates this equation, and then examine it in detail.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}name}\PYG{n+nt}{\PYGZgt{}}nlse\PYG{n+nt}{\PYGZlt{}/name\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}author}\PYG{n+nt}{\PYGZgt{}}Joe Hope\PYG{n+nt}{\PYGZlt{}/author\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}description}\PYG{n+nt}{\PYGZgt{}}
+    The nonlinear Schrodinger equation in one dimension,
+    which is a simple partial differential equation.
+    We introduce several new features in this script.
+  \PYG{n+nt}{\PYGZlt{}/description\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}features}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}benchmark} \PYG{n+nt}{/\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}bing} \PYG{n+nt}{/\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}fftw} \PYG{n+na}{plan=}\PYG{l+s}{\PYGZdq{}patient\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}openmp} \PYG{n+nt}{/\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}auto\PYGZus{}vectorise} \PYG{n+nt}{/\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}globals}\PYG{n+nt}{\PYGZgt{}}
+          \PYG{c+cp}{\PYGZlt{}![CDATA[}
+          \PYG{k}{const} \PYG{k+kt}{double} \PYG{n}{energy} \PYG{o}{=} \PYG{l+m+mi}{4}\PYG{p}{;}
+          \PYG{k}{const} \PYG{k+kt}{double} \PYG{n}{vel} \PYG{o}{=} \PYG{l+m+mf}{0.3}\PYG{p}{;}
+          \PYG{k}{const} \PYG{k+kt}{double} \PYG{n}{hwhm} \PYG{o}{=} \PYG{l+m+mf}{1.0}\PYG{p}{;}
+          \PYG{c+cp}{]]\PYGZgt{}}
+       \PYG{n+nt}{\PYGZlt{}/globals\PYGZgt{}}
+     \PYG{n+nt}{\PYGZlt{}/features\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} xi \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}tau\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}128\PYGZdq{}}  \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(\PYGZhy{}6, 6)\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+   \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}wavefunction\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}complex\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}tau\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} phi \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{k}{const} \PYG{k+kt}{double} \PYG{n}{w0} \PYG{o}{=} \PYG{n}{hwhm}\PYG{o}{*}\PYG{n}{sqrt}\PYG{p}{(}\PYG{l+m+mi}{2}\PYG{o}{/}\PYG{n}{log}\PYG{p}{(}\PYG{l+m+mi}{2}\PYG{p}{)}\PYG{p}{)}\PYG{p}{;}
+      \PYG{k}{const} \PYG{k+kt}{double} \PYG{n}{amp} \PYG{o}{=} \PYG{n}{sqrt}\PYG{p}{(}\PYG{n}{energy}\PYG{o}{/}\PYG{n}{w0}\PYG{o}{/}\PYG{n}{sqrt}\PYG{p}{(}\PYG{n}{M\PYGZus{}PI}\PYG{o}{/}\PYG{l+m+mi}{2}\PYG{p}{)}\PYG{p}{)}\PYG{p}{;}
+      \PYG{n}{phi} \PYG{o}{=} \PYG{n}{amp}\PYG{o}{*}\PYG{n}{exp}\PYG{p}{(}\PYG{o}{\PYGZhy{}}\PYG{n}{tau}\PYG{o}{*}\PYG{n}{tau}\PYG{o}{/}\PYG{n}{w0}\PYG{o}{/}\PYG{n}{w0}\PYG{p}{)}\PYG{o}{*}\PYG{n}{exp}\PYG{p}{(}\PYG{k+kc}{i}\PYG{o}{*}\PYG{n}{vel}\PYG{o}{*}\PYG{n}{tau}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}dampingVector\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} Gamma \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{n}{Gamma}\PYG{o}{=}\PYG{l+m+mf}{1.0}\PYG{o}{*}\PYG{p}{(}\PYG{l+m+mi}{1}\PYG{o}{\PYGZhy{}}\PYG{n}{exp}\PYG{p}{(}\PYG{o}{\PYGZhy{}}\PYG{n}{pow}\PYG{p}{(}\PYG{n}{tau}\PYG{o}{*}\PYG{n}{tau}\PYG{o}{/}\PYG{l+m+mf}{4.0}\PYG{o}{/}\PYG{l+m+mf}{4.0}\PYG{p}{,}\PYG{l+m+mi}{10}\PYG{p}{)}\PYG{p}{)}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}sequence}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}integrate} \PYG{n+na}{algorithm=}\PYG{l+s}{\PYGZdq{}ARK45\PYGZdq{}} \PYG{n+na}{interval=}\PYG{l+s}{\PYGZdq{}20.0\PYGZdq{}} \PYG{n+na}{tolerance=}\PYG{l+s}{\PYGZdq{}1e\PYGZhy{}7\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}samples}\PYG{n+nt}{\PYGZgt{}}10 100 10\PYG{n+nt}{\PYGZlt{}/samples\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}operators}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}integration\PYGZus{}vectors}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/integration\PYGZus{}vectors\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}operator} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}ex\PYGZdq{}} \PYG{n+na}{constant=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+          \PYG{n+nt}{\PYGZlt{}operator\PYGZus{}names}\PYG{n+nt}{\PYGZgt{}}Ltt\PYG{n+nt}{\PYGZlt{}/operator\PYGZus{}names\PYGZgt{}}
+          \PYG{c+cp}{\PYGZlt{}![CDATA[}
+            \PYG{n}{Ltt} \PYG{o}{=} \PYG{o}{\PYGZhy{}}\PYG{k+kc}{i}\PYG{o}{*}\PYG{n}{ktau}\PYG{o}{*}\PYG{n}{ktau}\PYG{o}{*}\PYG{l+m+mf}{0.5}\PYG{p}{;}
+          \PYG{c+cp}{]]\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/operator\PYGZgt{}}
+        \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{dphi\PYGZus{}dxi} \PYG{o}{=} \PYG{n}{Ltt}\PYG{p}{[}\PYG{n}{phi}\PYG{p}{]} \PYG{o}{\PYGZhy{}} \PYG{n}{phi}\PYG{o}{*}\PYG{n}{Gamma} \PYG{o}{+} \PYG{k+kc}{i}\PYG{o}{*}\PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{o}{*}\PYG{n}{phi}\PYG{p}{;}
+        \PYG{c+cp}{]]\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}dampingVector\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}/operators\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/integrate\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/sequence\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}output}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}tau\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}}density\PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{density} \PYG{o}{=} \PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+
+    \PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}tau(0)\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}}normalisation\PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{normalisation} \PYG{o}{=} \PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+
+    \PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}ktau(32)\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}}densityK\PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{densityK} \PYG{o}{=} \PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}/output\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+Let us examine the new items in the \code{\textless{}features\textgreater{}} element that we have demonstrated here.  The existence of the \code{\textless{}benchmark\textgreater{}} element causes the simulation to be timed.  The \code{\textless{}bing\textgreater{}} element causes the computer to make a sound upon the conclusion of the simulation.  The \code{\textless{}fftw\textgreater{}} element is used to pass options to the \href{http://fftw.org}{FFTW libraries for fast Fourier transfo [...]
+
+Finally, we use two tags to make the simulation run faster.  The \code{\textless{}auto\_vectorise\textgreater{}} element switches on several loop optimisations that exist in later versions of the GCC compiler.  The \code{\textless{}openmp\textgreater{}} element turns on threaded parallel processing using the OpenMP standard where possible.  These options are not activated by default as they only exist on certain compilers.  If your code compiles with them on, then they are recommended.
+
+Let us examine the \code{\textless{}geometry\textgreater{}} element.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} xi \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}tau\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}128\PYGZdq{}}  \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(\PYGZhy{}6, 6)\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+ \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+\end{Verbatim}
+
+This is the first example that includes a transverse dimension.  We have only one dimension, and we have labelled it ``tau''.  It is a continuous dimension, but only defined on a grid containing 128 points (defined with the lattice variable), and on a domain from -6 to 6.  The default is that transforms in continuous dimensions are fast Fourier transforms, which means that this dimension is effectively defined on a loop, and the ``tau=-6'' and ``tau=6'' positions are in fact the same.  O [...]
+
+Two vector elements have been defined in this simulation.  One defines the complex-valued wavefunction ``phi'' that we wish to evolve.  We define the transverse dimensions over which this vector is defined by the \code{dimensions} tag in the description.  By default, it is defined over all of the transverse dimensions in the \code{\textless{}geometry\textgreater{}} element, so even though we have omitted this tag for the second vector, it also assumes that the vector is defined over all of tau.
+
+The second vector element contains the component ``Gamma'' which is a function of the transverse variable tau, as specified in the equation of motion for the field.  This second vector could have been avoided in two ways.  First, the function could have been written explicitly in the integrate block where it is required, but calculating it once and then recalling it from memory is far more efficient.  Second, it could have been included in the ``wavefunction'' vector as another component [...]
+
+The \code{\textless{}integrate\textgreater{}} element for a partial differential equation has some new features:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}integrate} \PYG{n+na}{algorithm=}\PYG{l+s}{\PYGZdq{}ARK45\PYGZdq{}} \PYG{n+na}{interval=}\PYG{l+s}{\PYGZdq{}20.0\PYGZdq{}} \PYG{n+na}{tolerance=}\PYG{l+s}{\PYGZdq{}1e\PYGZhy{}7\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}samples}\PYG{n+nt}{\PYGZgt{}}10 100 10\PYG{n+nt}{\PYGZlt{}/samples\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}operators}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}integration\PYGZus{}vectors}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/integration\PYGZus{}vectors\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}operator} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}ex\PYGZdq{}} \PYG{n+na}{constant=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}operator\PYGZus{}names}\PYG{n+nt}{\PYGZgt{}}Ltt\PYG{n+nt}{\PYGZlt{}/operator\PYGZus{}names\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{Ltt} \PYG{o}{=} \PYG{o}{\PYGZhy{}}\PYG{k+kc}{i}\PYG{o}{*}\PYG{n}{ktau}\PYG{o}{*}\PYG{n}{ktau}\PYG{o}{*}\PYG{l+m+mf}{0.5}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/operator\PYGZgt{}}
+    \PYG{c+cp}{\PYGZlt{}![CDATA[}
+    \PYG{n}{dphi\PYGZus{}dxi} \PYG{o}{=} \PYG{n}{Ltt}\PYG{p}{[}\PYG{n}{phi}\PYG{p}{]} \PYG{o}{\PYGZhy{}} \PYG{n}{phi}\PYG{o}{*}\PYG{n}{Gamma} \PYG{o}{+} \PYG{k+kc}{i}\PYG{o}{*}\PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{o}{*}\PYG{n}{phi}\PYG{p}{;}
+    \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}dampingVector\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/operators\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/integrate\PYGZgt{}}
+\end{Verbatim}
+
+There are some trivial changes from the tutorial script, such as the fact that we are using the ARK45 algorithm rather than ARK89.  Higher order algorithms are often better, but not always.  Also, since this script has multiple output groups, we have to specify how many times each of these output groups are sampled in the \code{\textless{}samples\textgreater{}} element, so there are three numbers there.  Besides the vectors that are to be integrated, we also specify that we want to use t [...]
+
+The equation of motion as written in the CDATA block looks almost identical to our desired equation of motion, except for the term based on the second derivative, which introduces an important new concept.  Inside the \code{\textless{}operators\textgreater{}} element, we can define any number of operators.  Operators are used to define functions in the transformed space of each dimension, which in this case is Fourier space.  The derivative of a function is equivalent to multiplying by $ [...]
+
+Operators can be explicit (\code{kind="ex"}) or in the interaction picture (\code{kind="ip"}).  The interaction picture can be more efficient, but it restricts the possible syntax of the equation of motion.  Safe utilisation of interaction picture operators will be described later, but for now let us emphasise that \textbf{explicit operators should be used} unless the user is clear what they are doing.  That said, \textbf{XMDS2} will generate an error if the user tries to use interaction [...]
+
+The output of a partial differential equation offers more possibilities than an ordinary differential equation, and we examine some in this example.
+
+For vectors with transverse dimensions, we can sample functions of the vectors on the full lattice or a subset of the points.  In the \code{\textless{}sampling\_group\textgreater{}} element, we must add a string called ``basis'' that determines the space in which each transverse dimension is to be sampled, optionally followed by the number of points to be sampled in parentheses.  If the number of points is not specified, it will default to a complete sampling of all points in that dimens [...]
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}tau\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}}density\PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+  \PYG{c+cp}{\PYGZlt{}![CDATA[}
+    \PYG{n}{density} \PYG{o}{=} \PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{p}{;}
+  \PYG{c+cp}{]]\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+\end{Verbatim}
+
+The first output group samples the mod square of the vector ``phi'' over the full lattice of 128 points.
+
+If the lattice parameter is set to zero points, then the corresponding dimension is integrated.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}tau(0)\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}}normalisation\PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+  \PYG{c+cp}{\PYGZlt{}![CDATA[}
+    \PYG{n}{normalisation} \PYG{o}{=} \PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{p}{;}
+  \PYG{c+cp}{]]\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+\end{Verbatim}
+
+This second output group samples the normalisation of the wavefunction $\int d\tau |\phi(\tau)|^2$ over the domain of $\tau$.  This output requires only a single real number per sample, so in the integrate element we have chosen to sample it many more times than the vectors themselves.
+
+Finally, functions of the vectors can be sampled with their dimensions in Fourier space.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}ktau(32)\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}}densityK\PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+  \PYG{c+cp}{\PYGZlt{}![CDATA[}
+    \PYG{n}{densityK} \PYG{o}{=} \PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{p}{;}
+  \PYG{c+cp}{]]\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+\end{Verbatim}
+
+The final output group above samples the mod square of the Fourier-space wavefunction phi on a sample of 32 points.
+
+
+\section{Kubo Oscillator}
+\label{worked_examples:kubo}\label{worked_examples:kubo-oscillator}
+This example demonstrates the integration of a stochastic differential equation.  We examine the Kubo oscillator, which is a complex variable whose phase is evolving according to a Wiener noise.  In a suitable rotating frame, the equation of motion for the variable is
+\begin{gather}
+\begin{split}\frac{dz}{dt} = i z \;\eta\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+where $\eta(t)$ is the Wiener differential, and we interpret this as a Stratonovich equation.  In other common notation, this is sometimes written:
+\begin{gather}
+\begin{split}dz = i z \;\circ dW\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+Most algorithms employed by XMDS require the equations to be input in the Stratonovich form.  Ito differential equations can always be transformed into Stratonovich euqations, and in this case the difference is equivalent to the choice of rotating frame.  This equation is solved by the following XMDS2 script:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}name}\PYG{n+nt}{\PYGZgt{}}kubo\PYG{n+nt}{\PYGZlt{}/name\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}author}\PYG{n+nt}{\PYGZgt{}}Graham Dennis and Joe Hope\PYG{n+nt}{\PYGZlt{}/author\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}description}\PYG{n+nt}{\PYGZgt{}}
+    Example Kubo oscillator simulation
+  \PYG{n+nt}{\PYGZlt{}/description\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}driver} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}multi\PYGZhy{}path\PYGZdq{}} \PYG{n+na}{paths=}\PYG{l+s}{\PYGZdq{}10000\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}features}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}error\PYGZus{}check} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}benchmark} \PYG{n+nt}{/\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/features\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}noise\PYGZus{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}drivingNoise\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}\PYGZdq{}} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}wiener\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{method=}\PYG{l+s}{\PYGZdq{}dsfmt\PYGZdq{}} \PYG{n+na}{seed=}\PYG{l+s}{\PYGZdq{}314 159 276\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}eta\PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/noise\PYGZus{}vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}main\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}complex\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} z \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{z} \PYG{o}{=} \PYG{l+m+mf}{1.0}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}sequence}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}integrate} \PYG{n+na}{algorithm=}\PYG{l+s}{\PYGZdq{}SI\PYGZdq{}} \PYG{n+na}{interval=}\PYG{l+s}{\PYGZdq{}10\PYGZdq{}} \PYG{n+na}{steps=}\PYG{l+s}{\PYGZdq{}1000\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}samples}\PYG{n+nt}{\PYGZgt{}}100\PYG{n+nt}{\PYGZlt{}/samples\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}operators}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}integration\PYGZus{}vectors}\PYG{n+nt}{\PYGZgt{}}main\PYG{n+nt}{\PYGZlt{}/integration\PYGZus{}vectors\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}drivingNoise\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+        \PYG{c+cp}{\PYGZlt{}![CDATA[}
+          \PYG{n}{dz\PYGZus{}dt} \PYG{o}{=} \PYG{k+kc}{i}\PYG{o}{*}\PYG{n}{z}\PYG{o}{*}\PYG{n}{eta}\PYG{p}{;}
+        \PYG{c+cp}{]]\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}/operators\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/integrate\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/sequence\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}output}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}}zR zI\PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}main\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{zR} \PYG{o}{=} \PYG{n}{z}\PYG{p}{.}\PYG{n}{Re}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
+        \PYG{n}{zI} \PYG{o}{=} \PYG{n}{z}\PYG{p}{.}\PYG{n}{Im}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/output\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+The first new item in this script is the \code{\textless{}driver\textgreater{}} element.  This element enables us to change top level management of the simulation.  Without this element, XMDS2 will integrate the stochastic equation as described.  With this element and the option \code{name="multi-path"}, it will integrate it multiple times, using different random numbers each time.  The output will then contain the mean values and standard errors of your output variables.  The number of  [...]
+
+In the \code{\textless{}features\textgreater{}} element we have included the \code{\textless{}error\_check\textgreater{}} element.  This performs the integration first with the specified number of steps (or with the specified tolerance), and then with twice the number of steps (or equivalently reduced tolerance).  The output then includes the difference between the output variables on the coarse and the fine grids as the `error' in the output variables.  This error is particularly useful [...]
+
+We define the stochastic elements in a simulation with the \code{\textless{}noise\_vector\textgreater{}} element.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}noise\PYGZus{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}drivingNoise\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}\PYGZdq{}} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}wiener\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{method=}\PYG{l+s}{\PYGZdq{}dsfmt\PYGZdq{}} \PYG{n+na}{seed=}\PYG{l+s}{\PYGZdq{}314 159 276\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+ \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}eta\PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/noise\PYGZus{}vector\PYGZgt{}}
+\end{Verbatim}
+
+This defines a vector that is used like any other, but it will be randomly generated with particular statistics and characteristics rather than initialised.  The name, dimensions and type tags are defined just as for normal vectors.  The names of the components are also defined in the same way.  The noise is defined as a Wiener noise here (\code{kind = "wiener"}), which is a zero-mean Gaussian random noise with an average variance equal to the discretisation volume (here it is just the s [...]
+
+We may also define a noise method to choose a non-default pseudo random number generator, and a seed for the random number generator.  Using a seed can be very useful when debugging the behaviour of a simulation, and many compilers have pseudo-random number generators that are superior to the default option (posix).
+
+The integrate block is using the semi-implicit algorithm (\code{algorithm="SI"}), which is a good default choice for stochastic problems, even though it is only second order convergent for deterministic equations.  More will be said about algorithm choice later, but for now we should note that adaptive algorithms based on Runge-Kutta methods are not guaranteed to converge safely for stochastic equations.  This can be particularly deceptive as they often succeed, particularly for almost a [...]
+
+We include elements from the noise vector in the equation of motion just as we do for any other vector.  The default SI and Runge-Kutta algorithms converge to the \emph{Stratonovich} integral.  Ito stochastic equations can be converted to Stratonovich form and vice versa.
+
+Executing the generated program `kubo' gives slightly different output due to the ``multi-path'' driver.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYGZdl{} ./kubo
+Beginning full step integration ...
+Starting path 1
+Starting path 2
+
+... many lines omitted ...
+
+Starting path 9999
+Starting path 10000
+Beginning half step integration ...
+Starting path 1
+Starting path 2
+
+... many lines omitted ...
+
+Starting path 9999
+Starting path 10000
+Generating output for kubo
+Maximum step error in moment group 1 was 4.942549e\PYGZhy{}04
+Time elapsed for simulation is: 2.71 seconds
+\end{Verbatim}
+
+The maximum step error in each moment group is given in absolute terms.  This is the largest difference between the full step integration and the half step integration.  While a single path might be very stochastic:
+\begin{figure}[htbp]
+\centering
+\capstart
+
+\includegraphics{kuboSingle.pdf}
+\caption{The mean value of the real and imaginary components of the z variable for a single path of the simulation.}\end{figure}
+
+The average over multiple paths can be increasingly smooth.
+\begin{figure}[htbp]
+\centering
+\capstart
+
+\includegraphics{kubo10000.pdf}
+\caption{The mean and standard error of the z variable averaged over 10000 paths, as given by this simulation.  It agrees within the standard error with the expected result of $\exp(-t/2)$.}\end{figure}
+
+
+\section{Fibre Noise}
+\label{worked_examples:fibre}\label{worked_examples:fibre-noise}
+This simulation is a stochastic partial differential equation, in which a one-dimensional damped field is subject to a complex noise. This script can be found in \code{examples/fibre.xmds}.
+\begin{gather}
+\begin{split}\frac{\partial \psi}{\partial t} = -i \frac{\partial^2 \psi}{\partial x^2} -\gamma \psi+\beta \frac{1}{\sqrt{2}}\left(\eta_1(x)+i\eta_2(x)\right)\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+where the noise terms $\eta_j(x,t)$ are Wiener differentials and the equation is interpreted as a Stratonovich differential equation.  On a finite grid, these increments have variance $\frac{1}{\Delta x \Delta t}$.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}name}\PYG{n+nt}{\PYGZgt{}}fibre\PYG{n+nt}{\PYGZlt{}/name\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}author}\PYG{n+nt}{\PYGZgt{}}Joe Hope and Graham Dennis\PYG{n+nt}{\PYGZlt{}/author\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}description}\PYG{n+nt}{\PYGZgt{}}
+    Example fibre noise simulation
+  \PYG{n+nt}{\PYGZlt{}/description\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}64\PYGZdq{}}  \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(\PYGZhy{}5, 5)\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}driver} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}mpi\PYGZhy{}multi\PYGZhy{}path\PYGZdq{}} \PYG{n+na}{paths=}\PYG{l+s}{\PYGZdq{}8\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}features}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}auto\PYGZus{}vectorise} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}benchmark} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}error\PYGZus{}check} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}globals}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{k}{const} \PYG{n+nf}{real} \PYG{n}{ggamma} \PYG{o}{=} \PYG{l+m+mf}{1.0}\PYG{p}{;}
+      \PYG{k}{const} \PYG{n+nf}{real} \PYG{n}{beta} \PYG{o}{=} \PYG{n}{sqrt}\PYG{p}{(}\PYG{n}{M\PYGZus{}PI}\PYG{o}{*}\PYG{n}{ggamma}\PYG{o}{/}\PYG{l+m+mf}{10.0}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/globals\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/features\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}noise\PYGZus{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}drivingNoise\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}wiener\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}complex\PYGZdq{}} \PYG{n+na}{method=}\PYG{l+s}{\PYGZdq{}dsfmt\PYGZdq{}} \PYG{n+na}{seed=}\PYG{l+s}{\PYGZdq{}314 159 276\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}Eta\PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/noise\PYGZus{}vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}main\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}basis=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}complex\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}phi\PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{phi} \PYG{o}{=} \PYG{l+m+mf}{0.0}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}sequence}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}integrate} \PYG{n+na}{algorithm=}\PYG{l+s}{\PYGZdq{}SI\PYGZdq{}} \PYG{n+na}{iterations=}\PYG{l+s}{\PYGZdq{}3\PYGZdq{}} \PYG{n+na}{interval=}\PYG{l+s}{\PYGZdq{}2.5\PYGZdq{}} \PYG{n+na}{steps=}\PYG{l+s}{\PYGZdq{}200000\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}samples}\PYG{n+nt}{\PYGZgt{}}50\PYG{n+nt}{\PYGZlt{}/samples\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}operators}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}operator} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}ex\PYGZdq{}} \PYG{n+na}{constant=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+          \PYG{n+nt}{\PYGZlt{}operator\PYGZus{}names}\PYG{n+nt}{\PYGZgt{}}L\PYG{n+nt}{\PYGZlt{}/operator\PYGZus{}names\PYGZgt{}}
+          \PYG{c+cp}{\PYGZlt{}![CDATA[}
+            \PYG{n}{L} \PYG{o}{=} \PYG{o}{\PYGZhy{}}\PYG{k+kc}{i}\PYG{o}{*}\PYG{n}{kx}\PYG{o}{*}\PYG{n}{kx}\PYG{p}{;}
+          \PYG{c+cp}{]]\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/operator\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}drivingNoise\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}integration\PYGZus{}vectors}\PYG{n+nt}{\PYGZgt{}}main\PYG{n+nt}{\PYGZlt{}/integration\PYGZus{}vectors\PYGZgt{}}
+        \PYG{c+cp}{\PYGZlt{}![CDATA[}
+          \PYG{n}{dphi\PYGZus{}dt} \PYG{o}{=} \PYG{n}{L}\PYG{p}{[}\PYG{n}{phi}\PYG{p}{]} \PYG{o}{\PYGZhy{}} \PYG{n}{ggamma}\PYG{o}{*}\PYG{n}{phi} \PYG{o}{+} \PYG{n}{beta}\PYG{o}{*}\PYG{n}{Eta}\PYG{p}{;}
+        \PYG{c+cp}{]]\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}/operators\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/integrate\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/sequence\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}output}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}kx\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}}pow\PYGZus{}dens\PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}main\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{pow\PYGZus{}dens} \PYG{o}{=} \PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/output\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+Note that the noise vector used in this example is complex-valued, and has the argument \code{dimensions="x"} to define it as a field of delta-correlated noises along the x-dimension.
+
+This simulation demonstrates the ease with which XMDS2 can be used in a parallel processing environment.  Instead of using the stochastic driver ``multi-path'', we simply replace it with ``mpi-multi-path''.  This instructs XMDS2 to write a parallel version of the program based on the widespread \href{http://www.open-mpi.org/}{MPI standard}.  This protocol allows multiple processors or clusters of computers to work simultaneously on the same problem.  Free open source libraries implementi [...]
+
+Executing this program is slightly different with the MPI option.  The details can change between MPI implementations, but as an example:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYGZdl{}xmds2 fibre.xmds
+xmds2 version 2.1 \PYGZdq{}Happy Mollusc\PYGZdq{} (r2543)
+Copyright 2000\PYGZhy{}2012 Graham Dennis, Joseph Hope, Mattias Johnsson
+                    and the xmds team
+Generating source code...
+... done
+Compiling simulation...
+... done. Type \PYGZsq{}./fibre\PYGZsq{} to run.
+\end{Verbatim}
+
+Note that different compile options (and potentially a different compiler) are used by XMDS2, but this is transparent to the user.  MPI simulations will have to be run using syntax that will depend on the MPI implementation.  Here we show the version based on the popular open source \href{http://www.open-mpi.org/}{Open-MPI} implementation.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYGZdl{} mpirun \PYGZhy{}np 4 ./fibre
+Found enlightenment... (Importing wisdom)
+Planning for x \PYGZlt{}\PYGZhy{}\PYGZhy{}\PYGZhy{}\PYGZgt{} kx transform... done.
+Beginning full step integration ...
+Rank[0]: Starting path 1
+Rank[1]: Starting path 2
+Rank[2]: Starting path 3
+Rank[3]: Starting path 4
+Rank[3]: Starting path 8
+Rank[0]: Starting path 5
+Rank[1]: Starting path 6
+Rank[2]: Starting path 7
+Rank[3]: Starting path 4
+Beginning half step integration ...
+Rank[0]: Starting path 1
+Rank[2]: Starting path 3
+Rank[1]: Starting path 2
+Rank[3]: Starting path 8
+Rank[0]: Starting path 5
+Rank[2]: Starting path 7
+Rank[1]: Starting path 6
+Generating output for fibre
+Maximum step error in moment group 1 was 4.893437e\PYGZhy{}04
+Time elapsed for simulation is: 20.99 seconds
+\end{Verbatim}
+
+In this example we used four processors.  The different processors are labelled by their ``Rank'', starting at zero.  Because the processors are working independently, the output from the different processors can come in a randomised order.  In the end, however, the .xsil and data files are constructed identically to the single processor outputs.
+
+The analytic solution to the stochastic averages of this equation is given by
+\begin{gather}
+\begin{split}\langle |\psi(k,t)|^2 \rangle = \exp(-2\gamma t)|\psi(k,0)|^2 +\frac{\beta^2 L_x}{4\pi \gamma} \left(1-\exp(-2\gamma t)\right)\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+where $L_x$ is the length of the x domain.  We see that a single integration of these equations is quite chaotic:
+\begin{figure}[htbp]
+\centering
+\capstart
+
+\includegraphics{fibreSingle.pdf}
+\caption{The momentum space density of the field as a function of time for a single path realisation.}\end{figure}
+
+while an average of 1024 paths (change \code{paths="8"} to \code{paths="1024"} in the \code{\textless{}driver\textgreater{}} element) converges nicely to the analytic solution:
+\begin{figure}[htbp]
+\centering
+\capstart
+
+\includegraphics{fibre1024.pdf}
+\caption{The momentum space density of the field as a function of time for an average of 1024 paths.}\end{figure}
+
+
+\section{Integer Dimensions}
+\label{worked_examples:integer-dimensions}\label{worked_examples:integerdimensionexample}
+This example shows how to handle systems with integer-valued transverse dimensions.  We will integrate the following set of equations
+\begin{gather}
+\begin{split}\frac{dx_j}{dt} = x_j \left(x_{j-1}-x_{j+1}\right)\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+where $x_j$ are complex-valued variables defined on a ring, such that $j\in \{0,j_{max}\}$ and the $x_{j_{max}+1}$ variable is identified with the variable $x_{0}$, and the variable $x_{-1}$ is identified with the variable $x_{j_{max}}$.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}name}\PYG{n+nt}{\PYGZgt{}}integer\PYGZus{}dimensions\PYG{n+nt}{\PYGZlt{}/name\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}author}\PYG{n+nt}{\PYGZgt{}}Graham Dennis\PYG{n+nt}{\PYGZlt{}/author\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}description}\PYG{n+nt}{\PYGZgt{}}
+    XMDS2 script to test integer dimensions.
+  \PYG{n+nt}{\PYGZlt{}/description\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}features}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}benchmark} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}error\PYGZus{}check} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}bing} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}diagnostics} \PYG{n+nt}{/\PYGZgt{}} \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ This will make sure that all nonlocal accesses of dimensions are safe }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/features\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}j\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}integer\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}5\PYGZdq{}} \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(0,4)\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}main\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}complex\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} x \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{n}{x} \PYG{o}{=} \PYG{l+m+mf}{1.0e\PYGZhy{}3}\PYG{p}{;}
+      \PYG{n}{x}\PYG{p}{(}\PYG{n}{j} \PYG{o}{=}\PYG{o}{\PYGZgt{}} \PYG{l+m+mi}{0}\PYG{p}{)} \PYG{o}{=} \PYG{l+m+mf}{1.0}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}sequence}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}integrate} \PYG{n+na}{algorithm=}\PYG{l+s}{\PYGZdq{}ARK45\PYGZdq{}} \PYG{n+na}{interval=}\PYG{l+s}{\PYGZdq{}60\PYGZdq{}} \PYG{n+na}{steps=}\PYG{l+s}{\PYGZdq{}25000\PYGZdq{}} \PYG{n+na}{tolerance=}\PYG{l+s}{\PYGZdq{}1.0e\PYGZhy{}9\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}samples}\PYG{n+nt}{\PYGZgt{}}1000\PYG{n+nt}{\PYGZlt{}/samples\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}operators}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}integration\PYGZus{}vectors}\PYG{n+nt}{\PYGZgt{}}main\PYG{n+nt}{\PYGZlt{}/integration\PYGZus{}vectors\PYGZgt{}}
+        \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{k+kt}{long} \PYG{n}{j\PYGZus{}minus\PYGZus{}one} \PYG{o}{=} \PYG{p}{(}\PYG{n}{j}\PYG{o}{\PYGZhy{}}\PYG{l+m+mi}{1}\PYG{p}{)} \PYG{o}{\PYGZpc{}} \PYG{n}{\PYGZus{}lattice\PYGZus{}j}\PYG{p}{;}
+        \PYG{k}{if} \PYG{p}{(}\PYG{n}{j\PYGZus{}minus\PYGZus{}one} \PYG{o}{\PYGZlt{}} \PYG{l+m+mi}{0}\PYG{p}{)}
+          \PYG{n}{j\PYGZus{}minus\PYGZus{}one} \PYG{o}{+}\PYG{o}{=} \PYG{n}{\PYGZus{}lattice\PYGZus{}j}\PYG{p}{;}
+        \PYG{k+kt}{long} \PYG{n}{j\PYGZus{}plus\PYGZus{}one}  \PYG{o}{=} \PYG{p}{(}\PYG{n}{j}\PYG{o}{+}\PYG{l+m+mi}{1}\PYG{p}{)} \PYG{o}{\PYGZpc{}} \PYG{n}{\PYGZus{}lattice\PYGZus{}j}\PYG{p}{;}
+        \PYG{n}{dx\PYGZus{}dt}\PYG{p}{(}\PYG{n}{j} \PYG{o}{=}\PYG{o}{\PYGZgt{}} \PYG{n}{j}\PYG{p}{)} \PYG{o}{=} \PYG{n}{x}\PYG{p}{(}\PYG{n}{j} \PYG{o}{=}\PYG{o}{\PYGZgt{}} \PYG{n}{j}\PYG{p}{)}\PYG{o}{*}\PYG{p}{(}\PYG{n}{x}\PYG{p}{(}\PYG{n}{j} \PYG{o}{=}\PYG{o}{\PYGZgt{}} \PYG{n}{j\PYGZus{}minus\PYGZus{}one}\PYG{p}{)} \PYG{o}{\PYGZhy{}} \PYG{n}{x}\PYG{p}{(}\PYG{n}{j} \PYG{o}{=}\PYG{o}{\PYGZgt{}} \PYG{n}{j\PYGZus{}plus\PYGZus{}one}\PYG{p}{)}\PYG{p}{)}\PYG{p}{;}
+        \PYG{c+cp}{]]\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}/operators\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/integrate\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/sequence\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}output}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}j\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}}xR\PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}main\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{xR} \PYG{o}{=} \PYG{n}{x}\PYG{p}{.}\PYG{n}{Re}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/output\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+The first extra feature we have used in this script is the \code{\textless{}diagnostics\textgreater{}} element.  It performs run-time checking that our generated code does not accidentally attempt to access a part of our vector that does not exist.  Removing this tag will increase the speed of the simulation, but its presence helps catch coding errors.
+
+The simulation defines a vector with a single transverse dimension labelled ``j'', of type ``integer'' (``int'' and ``long'' can also be used as synonyms for ``integer'').  In the absence of an explicit type, the dimension is assumed to be real-valued.  The dimension has a ``domain'' argument as normal, defining the minimum and maximum values of the dimension's range.  The lattice element, if specified, is used as a check on the size of the domain, and will create an error if the two do  [...]
+
+Integer-valued dimensions can be called non-locally.  Real-valued dimensions are typically coupled non-locally only through local operations in the transformed space of the dimension, but can be called non-locally in certain other situations as described in {\hyperref[reference_elements:referencingnonlocal]{\emph{the reference}}}.  The syntax for calling integer dimensions non-locally can be seen in the initialisation CDATA block:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+x = 1.0e\PYGZhy{}3;
+x(j =\PYGZgt{} 0) = 1.0;
+\end{Verbatim}
+
+where the syntax \code{x(j =\textgreater{} 0)} is used to reference the variable $x_0$ directly.  We see a more elaborate example in the integrate CDATA block:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+dx\PYGZus{}dt(j =\PYGZgt{} j) = x(j =\PYGZgt{} j)*(x(j =\PYGZgt{} j\PYGZus{}minus\PYGZus{}one) \PYGZhy{} x(j =\PYGZgt{} j\PYGZus{}plus\PYGZus{}one));
+\end{Verbatim}
+
+where the vector ``x'' is called using locally defined variables.  This syntax is chosen so that multiple dimensions can be addressed non-locally with minimal possibility for confusion.
+
+
+\section{Wigner Function}
+\label{worked_examples:wigner-function}\label{worked_examples:wignerarguments}
+This example integrates the two-dimensional partial differential equation
+\begin{gather}
+\begin{split}\begin{split}
+\frac{\partial W}{\partial t} &= \Bigg[ \left(\omega + \frac{U_{int}}{\hbar}\left(x^2+y^2-1\right)\right) \left(x \frac{\partial}{\partial y}
+- y \frac{\partial}{\partial x}\right)\\
+&\phantom{=\Bigg[} - \frac{U_{int}}{16 \hbar}\left(x\left(\frac{\partial^3}{\partial x^2 \partial y}
++\frac{\partial^3}{\partial y^3}\right)-y\left(\frac{\partial^3}{\partial y^2 \partial x}+\frac{\partial^3}{\partial x^3}\right)\right)\Bigg]W(x,y,t)
+\end{split}\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+with the added restriction that the derivative is forced to zero outside a certain radius.  This extra condition helps maintain the long-term stability of the integration. The script can be found in \code{examples/wigner\_arguments\_mpi.xmds} under your XMDS2 installation directory.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}name}\PYG{n+nt}{\PYGZgt{}}wigner\PYG{n+nt}{\PYGZlt{}/name\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}author}\PYG{n+nt}{\PYGZgt{}}Graham Dennis and Joe Hope\PYG{n+nt}{\PYGZlt{}/author\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}description}\PYG{n+nt}{\PYGZgt{}}
+    Simulation of the Wigner function for an anharmonic oscillator with the initial state
+    being a coherent state.
+  \PYG{n+nt}{\PYGZlt{}/description\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}features}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}benchmark} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}globals}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n+nf}{real} \PYG{n}{Uint\PYGZus{}hbar\PYGZus{}on16}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/globals\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}arguments}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}argument} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}omega\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{default\PYGZus{}value=}\PYG{l+s}{\PYGZdq{}0.0\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}argument} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}alpha\PYGZus{}0\PYGZdq{}}     \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{default\PYGZus{}value=}\PYG{l+s}{\PYGZdq{}3.0\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}argument} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}absorb\PYGZdq{}}     \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{default\PYGZus{}value=}\PYG{l+s}{\PYGZdq{}8.0\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}argument} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}width\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{default\PYGZus{}value=}\PYG{l+s}{\PYGZdq{}0.3\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}argument} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}Uint\PYGZus{}hbar\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{default\PYGZus{}value=}\PYG{l+s}{\PYGZdq{}1.0\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{c+cm}{/* derived constants */}
+        \PYG{n}{Uint\PYGZus{}hbar\PYGZus{}on16} \PYG{o}{=} \PYG{n}{Uint\PYGZus{}hbar}\PYG{o}{/}\PYG{l+m+mf}{16.0}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/arguments\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}bing} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}fftw} \PYG{n+na}{plan=}\PYG{l+s}{\PYGZdq{}patient\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}openmp} \PYG{n+nt}{/\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/features\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}driver} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}distributed\PYGZhy{}mpi\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}128\PYGZdq{}}  \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(\PYGZhy{}6, 6)\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}y\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}128\PYGZdq{}}  \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(\PYGZhy{}6, 6)\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}main\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}basis=}\PYG{l+s}{\PYGZdq{}x y\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}complex\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} W \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{W} \PYG{o}{=} \PYG{l+m+mf}{2.0}\PYG{o}{/}\PYG{n}{M\PYGZus{}PI} \PYG{o}{*} \PYG{n}{exp}\PYG{p}{(}\PYG{o}{\PYGZhy{}}\PYG{l+m+mf}{2.0}\PYG{o}{*}\PYG{p}{(}\PYG{n}{y}\PYG{o}{*}\PYG{n}{y} \PYG{o}{+} \PYG{p}{(}\PYG{n}{x}\PYG{o}{\PYGZhy{}}\PYG{n}{alpha\PYGZus{}0}\PYG{p}{)}\PYG{o}{*}\PYG{p}{(}\PYG{n}{x}\PYG{o}{\PYGZhy{}}\PYG{n}{alpha\PYGZus{}0}\PYG{p}{)}\PYG{p}{)}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}dampConstants\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}basis=}\PYG{l+s}{\PYGZdq{}x y\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}damping\PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{k}{if} \PYG{p}{(}\PYG{n}{sqrt}\PYG{p}{(}\PYG{n}{x}\PYG{o}{*}\PYG{n}{x} \PYG{o}{+} \PYG{n}{y}\PYG{o}{*}\PYG{n}{y}\PYG{p}{)} \PYG{o}{\PYGZgt{}} \PYG{n}{\PYGZus{}max\PYGZus{}x}\PYG{o}{\PYGZhy{}}\PYG{n}{width}\PYG{p}{)}
+        \PYG{n}{damping} \PYG{o}{=} \PYG{l+m+mf}{0.0}\PYG{p}{;}
+      \PYG{k}{else}
+        \PYG{n}{damping} \PYG{o}{=} \PYG{l+m+mf}{1.0}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}sequence}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}integrate} \PYG{n+na}{algorithm=}\PYG{l+s}{\PYGZdq{}ARK89\PYGZdq{}} \PYG{n+na}{tolerance=}\PYG{l+s}{\PYGZdq{}1e\PYGZhy{}7\PYGZdq{}} \PYG{n+na}{interval=}\PYG{l+s}{\PYGZdq{}7.0e\PYGZhy{}4\PYGZdq{}} \PYG{n+na}{steps=}\PYG{l+s}{\PYGZdq{}100000\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}samples}\PYG{n+nt}{\PYGZgt{}}50\PYG{n+nt}{\PYGZlt{}/samples\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}operators}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}operator} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}ex\PYGZdq{}} \PYG{n+na}{constant=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+          \PYG{n+nt}{\PYGZlt{}operator\PYGZus{}names}\PYG{n+nt}{\PYGZgt{}}Lx Ly Lxxx Lxxy Lxyy Lyyy\PYG{n+nt}{\PYGZlt{}/operator\PYGZus{}names\PYGZgt{}}
+          \PYG{c+cp}{\PYGZlt{}![CDATA[}
+            \PYG{n}{Lx} \PYG{o}{=} \PYG{k+kc}{i}\PYG{o}{*}\PYG{n}{kx}\PYG{p}{;}
+            \PYG{n}{Ly} \PYG{o}{=} \PYG{k+kc}{i}\PYG{o}{*}\PYG{n}{ky}\PYG{p}{;}
+            \PYG{n}{Lxxx} \PYG{o}{=} \PYG{o}{\PYGZhy{}}\PYG{k+kc}{i}\PYG{o}{*}\PYG{n}{kx}\PYG{o}{*}\PYG{n}{kx}\PYG{o}{*}\PYG{n}{kx}\PYG{p}{;}
+            \PYG{n}{Lxxy} \PYG{o}{=} \PYG{o}{\PYGZhy{}}\PYG{k+kc}{i}\PYG{o}{*}\PYG{n}{kx}\PYG{o}{*}\PYG{n}{kx}\PYG{o}{*}\PYG{n}{ky}\PYG{p}{;}
+            \PYG{n}{Lxyy} \PYG{o}{=} \PYG{o}{\PYGZhy{}}\PYG{k+kc}{i}\PYG{o}{*}\PYG{n}{kx}\PYG{o}{*}\PYG{n}{ky}\PYG{o}{*}\PYG{n}{ky}\PYG{p}{;}
+            \PYG{n}{Lyyy} \PYG{o}{=} \PYG{o}{\PYGZhy{}}\PYG{k+kc}{i}\PYG{o}{*}\PYG{n}{ky}\PYG{o}{*}\PYG{n}{ky}\PYG{o}{*}\PYG{n}{ky}\PYG{p}{;}
+          \PYG{c+cp}{]]\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/operator\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}integration\PYGZus{}vectors}\PYG{n+nt}{\PYGZgt{}}main\PYG{n+nt}{\PYGZlt{}/integration\PYGZus{}vectors\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}dampConstants\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+        \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n+nf}{real} \PYG{n}{rotation} \PYG{o}{=} \PYG{n}{omega} \PYG{o}{+} \PYG{n}{Uint\PYGZus{}hbar}\PYG{o}{*}\PYG{p}{(}\PYG{o}{\PYGZhy{}}\PYG{l+m+mf}{1.0} \PYG{o}{+} \PYG{n}{x}\PYG{o}{*}\PYG{n}{x} \PYG{o}{+} \PYG{n}{y}\PYG{o}{*}\PYG{n}{y}\PYG{p}{)}\PYG{p}{;}
+
+        \PYG{n}{dW\PYGZus{}dt} \PYG{o}{=} \PYG{n}{damping} \PYG{o}{*} \PYG{p}{(} \PYG{n}{rotation} \PYG{o}{*} \PYG{p}{(}\PYG{n}{x}\PYG{o}{*}\PYG{n}{Ly}\PYG{p}{[}\PYG{n}{W}\PYG{p}{]} \PYG{o}{\PYGZhy{}} \PYG{n}{y}\PYG{o}{*}\PYG{n}{Lx}\PYG{p}{[}\PYG{n}{W}\PYG{p}{]}\PYG{p}{)}
+                    \PYG{o}{\PYGZhy{}} \PYG{n}{Uint\PYGZus{}hbar\PYGZus{}on16}\PYG{o}{*}\PYG{p}{(} \PYG{n}{x}\PYG{o}{*}\PYG{p}{(}\PYG{n}{Lxxy}\PYG{p}{[}\PYG{n}{W}\PYG{p}{]} \PYG{o}{+} \PYG{n}{Lyyy}\PYG{p}{[}\PYG{n}{W}\PYG{p}{]}\PYG{p}{)} \PYG{o}{\PYGZhy{}} \PYG{n}{y}\PYG{o}{*}\PYG{p}{(}\PYG{n}{Lxyy}\PYG{p}{[}\PYG{n}{W}\PYG{p}{]} \PYG{o}{+} \PYG{n}{Lxxx}\PYG{p}{[}\PYG{n}{W}\PYG{p}{]}\PYG{p}{)} \PYG{p}{)}
+                \PYG{p}{)}\PYG{p}{;}
+        \PYG{c+cp}{]]\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}/operators\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/integrate\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/sequence\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}output}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}x y\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}}WR WI\PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}main\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{\PYGZus{}SAMPLE\PYGZus{}COMPLEX}\PYG{p}{(}\PYG{n}{W}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/output\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+This example demonstrates two new features of XMDS2.  The first is the use of parallel processing for a deterministic problem.  The FFTW library only allows MPI processing of multidimensional vectors.  For multidimensional simulations, the generated program can be parallelised simply by adding the \code{name="distributed-mpi"} argument to the \code{\textless{}driver\textgreater{}} element.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYGZdl{} xmds2 wigner\PYGZus{}argument\PYGZus{}mpi.xmds
+xmds2 version 2.1 \PYGZdq{}Happy Mollusc\PYGZdq{} (r2680)
+Copyright 2000\PYGZhy{}2012 Graham Dennis, Joseph Hope, Mattias Johnsson
+                    and the xmds team
+Generating source code...
+... done
+Compiling simulation...
+... done. Type \PYGZsq{}./wigner\PYGZsq{} to run.
+\end{Verbatim}
+
+To use multiple processors, the final program is then called using the (implementation specific) MPI wrapper:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYGZdl{} mpirun \PYGZhy{}np 2 ./wigner
+Planning for (distributed x, y) \PYG{n+nt}{\PYGZlt{}\PYGZhy{}\PYGZhy{}\PYGZhy{}}\PYG{n+nt}{\PYGZgt{}} (distributed ky, kx) transform... done.
+Planning for (distributed x, y) \PYG{n+nt}{\PYGZlt{}\PYGZhy{}\PYGZhy{}\PYGZhy{}}\PYG{n+nt}{\PYGZgt{}} (distributed ky, kx) transform... done.
+Sampled field (for moment group \PYGZsh{}1) at t = 0.000000e+00
+Current timestep: 5.908361e\PYGZhy{}06
+Sampled field (for moment group \PYGZsh{}1) at t = 1.400000e\PYGZhy{}05
+Current timestep: 4.543131e\PYGZhy{}06
+
+...
+\end{Verbatim}
+
+The possible acceleration achievable when parallelising a given simulation depends on a great many things including available memory and cache.  As a general rule, it will improve as the simulation size gets larger, but the easiest way to find out is to test.  The optimum speed up is obviously proportional to the number of available processing cores.
+
+The second new feature in this simulation is the \code{\textless{}arguments\textgreater{}} element in the \code{\textless{}features\textgreater{}} block.  This is a way of specifying global variables with a given type that can then be input at run time.  The variables are specified in a self explanatory way
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}arguments}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}argument} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}omega\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{default\PYGZus{}value=}\PYG{l+s}{\PYGZdq{}0.0\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+    ...
+  \PYG{n+nt}{\PYGZlt{}argument} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}Uint\PYGZus{}hbar\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{default\PYGZus{}value=}\PYG{l+s}{\PYGZdq{}1.0\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/arguments\PYGZgt{}}
+\end{Verbatim}
+
+where the ``default\_value'' is used as the valuable of the variable if no arguments are given.  In the absence of the generating script, the program can document its options with the \code{-{-}help} argument:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYGZdl{} ./wigner \PYGZhy{}\PYGZhy{}help
+Usage: wigner \PYGZhy{}\PYGZhy{}omega \PYGZlt{}real\PYGZgt{} \PYGZhy{}\PYGZhy{}alpha\PYGZus{}0 \PYGZlt{}real\PYGZgt{} \PYGZhy{}\PYGZhy{}absorb \PYGZlt{}real\PYGZgt{} \PYGZhy{}\PYGZhy{}width \PYGZlt{}real\PYGZgt{} \PYGZhy{}\PYGZhy{}Uint\PYGZus{}hbar \PYGZlt{}real\PYGZgt{}
+
+Details:
+Option              Type            Default value
+\PYGZhy{}o,  \PYGZhy{}\PYGZhy{}omega        real            0.0
+\PYGZhy{}a,  \PYGZhy{}\PYGZhy{}alpha\PYGZus{}0      real            3.0
+\PYGZhy{}b,  \PYGZhy{}\PYGZhy{}absorb       real            8.0
+\PYGZhy{}w,  \PYGZhy{}\PYGZhy{}width        real            0.3
+\PYGZhy{}U,  \PYGZhy{}\PYGZhy{}Uint\PYGZus{}hbar    real            1.0
+\end{Verbatim}
+
+We can change one or more of these variables' values in the simulation by passing it at run time.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYGZdl{} mpirun \PYGZhy{}np 2 ./wigner \PYGZhy{}\PYGZhy{}omega 0.1 \PYGZhy{}\PYGZhy{}alpha\PYGZus{}0 2.5 \PYGZhy{}\PYGZhy{}Uint\PYGZus{}hbar 0
+Found enlightenment... (Importing wisdom)
+Planning for (distributed x, y) \PYGZlt{}\PYGZhy{}\PYGZhy{}\PYGZhy{}\PYGZgt{} (distributed ky, kx) transform... done.
+Planning for (distributed x, y) \PYGZlt{}\PYGZhy{}\PYGZhy{}\PYGZhy{}\PYGZgt{} (distributed ky, kx) transform... done.
+Sampled field (for moment group \PYGZsh{}1) at t = 0.000000e+00
+Current timestep: 1.916945e\PYGZhy{}04
+
+...
+\end{Verbatim}
+
+The values that were used for the variables, whether default or passed in, are stored in the output file (wigner.xsil).
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}info}\PYG{n+nt}{\PYGZgt{}}
+Script compiled with XMDS2 version 2.1 \PYGZdq{}Happy Mollusc\PYGZdq{} (r2680)
+See http://www.xmds.org for more information.
+
+Variables that can be specified on the command line:
+  Command line argument omega = 1.000000e\PYGZhy{}01
+  Command line argument alpha\PYGZus{}0 = 2.500000e+00
+  Command line argument absorb = 8.000000e+00
+  Command line argument width = 3.000000e\PYGZhy{}01
+  Command line argument Uint\PYGZus{}hbar = 0.000000e+00
+\PYG{n+nt}{\PYGZlt{}/info\PYGZgt{}}
+\end{Verbatim}
+
+Finally, note the shorthand used in the output group
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{c+cp}{\PYGZlt{}![CDATA[}
+  \PYG{n}{\PYGZus{}SAMPLE\PYGZus{}COMPLEX}\PYG{p}{(}\PYG{n}{W}\PYG{p}{)}\PYG{p}{;}
+\PYG{c+cp}{]]\PYGZgt{}}
+\end{Verbatim}
+
+which is short for
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{c+cp}{\PYGZlt{}![CDATA[}
+  \PYG{n}{WR} \PYG{o}{=} \PYG{n}{W}\PYG{p}{.}\PYG{n}{Re}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
+  \PYG{n}{WI} \PYG{o}{=} \PYG{n}{W}\PYG{p}{.}\PYG{n}{Im}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
+\PYG{c+cp}{]]\PYGZgt{}}
+\end{Verbatim}
+
+
+\section{Finding the Ground State of a BEC (continuous renormalisation)}
+\label{worked_examples:groundstatebec}\label{worked_examples:finding-the-ground-state-of-a-bec-continuous-renormalisation}
+This simulation solves another partial differential equation, but introduces several powerful new features in XMDS2.  The nominal problem is the calculation of the lowest energy eigenstate of a non-linear Schrödinger equation:
+\begin{gather}
+\begin{split}\frac{\partial \phi}{\partial t} = i \left[\frac{1}{2}\frac{\partial^2}{\partial y^2} - V(y) - U_{int}|\phi|^2\right]\phi\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+which can be found by evolving the above equation in imaginary time while keeping the normalisation constant.  This causes eigenstates to exponentially decay at the rate of their eigenvalue, so after a short time only the state with the lowest eigenvalue remains.  The evolution equation is straightforward:
+\begin{gather}
+\begin{split}\frac{\partial \phi}{\partial t} = \left[\frac{1}{2}\frac{\partial^2}{\partial y^2} - V(y) - U_{int}|\phi|^2\right]\phi\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+but we will need to use new XMDS2 features to manage the normalisation of the function $\phi(y,t)$.  The normalisation for a non-linear Schrödinger equation is given by $\int dy |\phi(y,t)|^2 = N_{particles}$, where $N_{particles}$ is the number of particles described by the wavefunction.
+
+The code for this simulation can be found in \code{examples/groundstate\_workedexamples.xmds}:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}name}\PYG{n+nt}{\PYGZgt{}}groundstate\PYG{n+nt}{\PYGZlt{}/name\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}author}\PYG{n+nt}{\PYGZgt{}}Joe Hope\PYG{n+nt}{\PYGZlt{}/author\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}description}\PYG{n+nt}{\PYGZgt{}}
+    Calculate the ground state of the non\PYGZhy{}linear Schrodinger equation in a harmonic magnetic trap.
+    This is done by evolving it in imaginary time while re\PYGZhy{}normalising each timestep.
+  \PYG{n+nt}{\PYGZlt{}/description\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}features}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}auto\PYGZus{}vectorise} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}benchmark} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}bing} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}fftw} \PYG{n+na}{plan=}\PYG{l+s}{\PYGZdq{}exhaustive\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}globals}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{k}{const} \PYG{n+nf}{real} \PYG{n}{Uint} \PYG{o}{=} \PYG{l+m+mf}{2.0}\PYG{p}{;}
+        \PYG{k}{const} \PYG{n+nf}{real} \PYG{n}{Nparticles} \PYG{o}{=} \PYG{l+m+mf}{5.0}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/globals\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/features\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}y\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}256\PYGZdq{}}  \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(\PYGZhy{}15.0, 15.0)\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}potential\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}basis=}\PYG{l+s}{\PYGZdq{}y\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} V1 \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{V1}  \PYG{o}{=} \PYG{l+m+mf}{0.5}\PYG{o}{*}\PYG{n}{y}\PYG{o}{*}\PYG{n}{y}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}wavefunction\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}basis=}\PYG{l+s}{\PYGZdq{}y\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}complex\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} phi \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{k}{if} \PYG{p}{(}\PYG{n}{fabs}\PYG{p}{(}\PYG{n}{y}\PYG{p}{)} \PYG{o}{\PYGZlt{}} \PYG{l+m+mf}{3.0}\PYG{p}{)} \PYG{p}{\PYGZob{}}
+          \PYG{n}{phi} \PYG{o}{=} \PYG{l+m+mf}{1.0}\PYG{p}{;}
+          \PYG{c+c1}{// This will be automatically normalised later}
+        \PYG{p}{\PYGZcb{}} \PYG{k}{else} \PYG{p}{\PYGZob{}}
+          \PYG{n}{phi} \PYG{o}{=} \PYG{l+m+mf}{0.0}\PYG{p}{;}
+        \PYG{p}{\PYGZcb{}}
+            \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}computed\PYGZus{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}normalisation\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} Ncalc \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}evaluation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}y\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{c+c1}{// Calculate the current normalisation of the wave function.}
+        \PYG{n}{Ncalc} \PYG{o}{=} \PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/evaluation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/computed\PYGZus{}vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}sequence}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}filter}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{c+cp}{\PYGZlt{}![CDATA[}
+          \PYG{n}{printf}\PYG{p}{(}\PYG{l+s}{\PYGZdq{}}\PYG{l+s}{Hello world from a filter segment!}\PYG{l+s+se}{\PYGZbs{}n}\PYG{l+s}{\PYGZdq{}}\PYG{p}{)}\PYG{p}{;}
+        \PYG{c+cp}{]]\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}/filter\PYGZgt{}}
+
+    \PYG{n+nt}{\PYGZlt{}filter}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}normalisation wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{phi} \PYG{o}{*}\PYG{o}{=} \PYG{n}{sqrt}\PYG{p}{(}\PYG{n}{Nparticles}\PYG{o}{/}\PYG{n}{Ncalc}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/filter\PYGZgt{}}
+
+    \PYG{n+nt}{\PYGZlt{}integrate} \PYG{n+na}{algorithm=}\PYG{l+s}{\PYGZdq{}ARK45\PYGZdq{}} \PYG{n+na}{interval=}\PYG{l+s}{\PYGZdq{}1.0\PYGZdq{}} \PYG{n+na}{steps=}\PYG{l+s}{\PYGZdq{}4000\PYGZdq{}} \PYG{n+na}{tolerance=}\PYG{l+s}{\PYGZdq{}1e\PYGZhy{}10\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}samples}\PYG{n+nt}{\PYGZgt{}}25 4000\PYG{n+nt}{\PYGZlt{}/samples\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}filters} \PYG{n+na}{where=}\PYG{l+s}{\PYGZdq{}step end\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}filter}\PYG{n+nt}{\PYGZgt{}}
+          \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}wavefunction normalisation\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+          \PYG{c+cp}{\PYGZlt{}![CDATA[}
+            \PYG{c+c1}{// Correct normalisation of the wavefunction}
+            \PYG{n}{phi} \PYG{o}{*}\PYG{o}{=} \PYG{n}{sqrt}\PYG{p}{(}\PYG{n}{Nparticles}\PYG{o}{/}\PYG{n}{Ncalc}\PYG{p}{)}\PYG{p}{;}
+          \PYG{c+cp}{]]\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/filter\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}/filters\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}operators}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}operator} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}ip\PYGZdq{}} \PYG{n+na}{constant=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+          \PYG{n+nt}{\PYGZlt{}operator\PYGZus{}names}\PYG{n+nt}{\PYGZgt{}}T\PYG{n+nt}{\PYGZlt{}/operator\PYGZus{}names\PYGZgt{}}
+          \PYG{c+cp}{\PYGZlt{}![CDATA[}
+            \PYG{n}{T} \PYG{o}{=} \PYG{o}{\PYGZhy{}}\PYG{l+m+mf}{0.5}\PYG{o}{*}\PYG{n}{ky}\PYG{o}{*}\PYG{n}{ky}\PYG{p}{;}
+          \PYG{c+cp}{]]\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/operator\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}integration\PYGZus{}vectors}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/integration\PYGZus{}vectors\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}potential\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+        \PYG{c+cp}{\PYGZlt{}![CDATA[}
+          \PYG{n}{dphi\PYGZus{}dt} \PYG{o}{=} \PYG{n}{T}\PYG{p}{[}\PYG{n}{phi}\PYG{p}{]} \PYG{o}{\PYGZhy{}} \PYG{p}{(}\PYG{n}{V1} \PYG{o}{+} \PYG{n}{Uint}\PYG{o}{*}\PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{p}{)}\PYG{o}{*}\PYG{n}{phi}\PYG{p}{;}
+        \PYG{c+cp}{]]\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}/operators\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/integrate\PYGZgt{}}
+
+    \PYG{n+nt}{\PYGZlt{}breakpoint} \PYG{n+na}{filename=}\PYG{l+s}{\PYGZdq{}groundstate\PYGZus{}break.xsil\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}ky\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}wavefunction \PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/breakpoint\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}/sequence\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}output}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}y\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}}norm\PYGZus{}dens\PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}wavefunction normalisation\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{norm\PYGZus{}dens} \PYG{o}{=} \PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+
+    \PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}}norm\PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}normalisation\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{norm} \PYG{o}{=} \PYG{n}{Ncalc}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/output\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+We have used the \code{plan="exhasutive"} option in the \code{\textless{}fftw\textgreater{}} element to ensure that the absolute fastest transform method is found.  Because the FFTW package stores the results of its tests (by default in the \textasciitilde{}/.xmds/wisdom directory), this option does not cause significant computational overhead, except perhaps on the very first run of a new program.
+
+This simulation introduces the first example of a very powerful feature in XMDS2: the \code{\textless{}computed\_vector\textgreater{}} element.  This has syntax like any other vector, including possible dependencies on other vectors, and an ability to be used in any element that can use vectors.  The difference is that, much like noise vectors, computed vectors are recalculated each time they are required.  This means that a computed vector can never be used as an integration vector, as  [...]
+
+The difference between a computed vector and a stored vector is emphasised by the replacement of the \code{\textless{}initialisation\textgreater{}} element with an \code{\textless{}evaluation\textgreater{}} element.  Apart from the name, they have virtually identical purpose and syntax.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}computed\PYGZus{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}normalisation\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} Ncalc \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}evaluation}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}dependencies} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}y\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+    \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{c+c1}{// Calculate the current normalisation of the wave function.}
+      \PYG{n}{Ncalc} \PYG{o}{=} \PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{p}{;}
+    \PYG{c+cp}{]]\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/evaluation\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/computed\PYGZus{}vector\PYGZgt{}}
+\end{Verbatim}
+
+Here, our computed vector has no transverse dimensions and depends on the components of ``wavefunction'', so the extra transverse dimensions are integrated out.  This code therefore integrates the square modulus of the field, and returns it in the variable ``Ncalc''.  This will be used below to renormalise the ``phi'' field.  Before we examine that process, we have to introduce the \code{\textless{}filter\textgreater{}} element.
+
+The \code{\textless{}filter\textgreater{}} element can be placed in the \code{\textless{}sequence\textgreater{}} element, or inside \code{\textless{}integrate\textgreater{}} elements as we will see next.  Elements placed in the \code{\textless{}sequence\textgreater{}} element are executed in the order they are found in the .xmds file.  Filter elements place the included CDATA block directly into the generated program at the designated position.  If the element does not contain any depend [...]
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}filter}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{c+cp}{\PYGZlt{}![CDATA[}
+    \PYG{n}{printf}\PYG{p}{(}\PYG{l+s}{\PYGZdq{}}\PYG{l+s}{Hello world from a filter segment!}\PYG{l+s+se}{\PYGZbs{}n}\PYG{l+s}{\PYGZdq{}}\PYG{p}{)}\PYG{p}{;}
+  \PYG{c+cp}{]]\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/filter\PYGZgt{}}
+\end{Verbatim}
+
+This filter block merely prints a string into the output when the generated program is run.  If the \code{\textless{}filter\textgreater{}} element contains dependencies, then the variables defined in those vectors (or computed vectors, or noise vectors) will be available, and the CDATA block will be placed inside loops that run over all the transverse dimensions used by the included vectors.  The second filter block in this example depends on both the ``wavefunction'' and ``normalisation [...]
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}filter}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}normalisation wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+  \PYG{c+cp}{\PYGZlt{}![CDATA[}
+    \PYG{n}{phi} \PYG{o}{*}\PYG{o}{=} \PYG{n}{sqrt}\PYG{p}{(}\PYG{n}{Nparticles}\PYG{o}{/}\PYG{n}{Ncalc}\PYG{p}{)}\PYG{p}{;}
+  \PYG{c+cp}{]]\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/filter\PYGZgt{}}
+\end{Verbatim}
+
+Since this filter depends on a vector with the transverse dimension ``y'', this filter will execute for each point in ``y''.  This code multiplies the value of the field ``phi'' by the factor required to produce a normalised function in the sense that  $\int dy |\phi(y,t)|^2 = N_{particles}$.
+
+The next usage of a \code{\textless{}filter\textgreater{}} element in this program is inside the \code{\textless{}integrate\textgreater{}} element, where all filters are placed inside a \code{\textless{}filters\textgreater{}} element.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}filters} \PYG{n+na}{where=}\PYG{l+s}{\PYGZdq{}step end\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}filter}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}wavefunction normalisation\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+    \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{c+c1}{// Correct normalisation of the wavefunction}
+      \PYG{n}{phi} \PYG{o}{*}\PYG{o}{=} \PYG{n}{sqrt}\PYG{p}{(}\PYG{n}{Nparticles}\PYG{o}{/}\PYG{n}{Ncalc}\PYG{p}{)}\PYG{p}{;}
+    \PYG{c+cp}{]]\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/filter\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/filters\PYGZgt{}}
+\end{Verbatim}
+
+Filters placed in an integration block are applied each integration step.  The ``where'' flag is used to determine whether the filter should be applied directly before or directly after each integration step.  The default value for the where flag is \code{where="step start"}, but in this case we chose ``step end'' to make sure that the final output was normalised after the last integration step.
+
+At the end of the sequence element we introduce the \code{\textless{}breakpoint\textgreater{}} element.  This serves two purposes.  The first is a simple matter of convenience.  Often when we manage our input and output from a simulation, we are interested solely in storing the exact state of our integration vectors.  A breakpoint element does exactly that, storing the components of any vectors contained within, taking all the normal options of the \code{\textless{}output\textgreater{}}  [...]
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}breakpoint} \PYG{n+na}{filename=}\PYG{l+s}{\PYGZdq{}groundstate\PYGZus{}break.xsil\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}dependencies} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}ky\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/breakpoint\PYGZgt{}}
+\end{Verbatim}
+
+If the filename argument is omitted, the output filenames are numbered sequentially.  Any given \code{\textless{}breakpoint\textgreater{}} element must only depend on vectors with identical dimensions.
+
+This program begins with a very crude guess to the ground state, but it rapidly converges to the lowest eigenstate.
+\begin{figure}[htbp]
+\centering
+\capstart
+
+\includegraphics{groundstateU2.pdf}
+\caption{The shape of the ground state rapidly approaches the lowest eigenstate.  For weak nonlinearities, it is nearly Gaussian.}\end{figure}
+\begin{figure}[htbp]
+\centering
+\capstart
+
+\includegraphics{groundstateU20.pdf}
+\caption{When the nonlinear term is larger ($U=20$), the ground state is wider and more parabolic.}\end{figure}
+
+
+\section{Finding the Ground State of a BEC again}
+\label{worked_examples:finding-the-ground-state-of-a-bec-again}\label{worked_examples:hermitegaussgroundstatebec}
+Here we repeat the same simulation as in the {\hyperref[worked_examples:groundstatebec]{\emph{Finding the Ground State of a BEC (continuous renormalisation)}}} example, using a different transform basis.  While spectral methods are very effective, and Fourier transforms are typically very efficient due to the Fast Fourier transform algorithm, it is often desirable to describe nonlocal evolution in bases other than the Fourier basis.  The previous calculation was the Schrödinger equation  [...]
+\begin{gather}
+\begin{split}\left[-\frac{\hbar}{2 m}\frac{\partial^2}{\partial x^2} + \frac{1}{2}\omega^2 x^2\right]\phi_n(x) = E_n \phi_n(x)\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+where
+\begin{gather}
+\begin{split}\phi_n(x,t) = \sqrt{\frac{1}{2^n n!}} \left(\frac{m \omega}{\hbar \pi}\right)^\frac{1}{4} e^{-\frac{m \omega x^2}{2\hbar}} H_n\left(\sqrt{\frac{m \omega}{\hbar}x}\right),\;\;\;\;\;\;E_n = \left(n+\frac{1}{2}\right) \omega\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+where $H_n(u)$ are the physicist's version of the Hermite polynomials.  Rather than describing the derivatives as diagonal terms in Fourier space, we therefore have the option of describing the entire $-\frac{\hbar}{2 m}\frac{\partial^2}{\partial x^2} + \frac{1}{2}\omega^2 x^2$ term as a diagonal term in the hermite-Gaussian basis.  Here is an XMDS2 simulation that performs the integration in this basis. The following is a simplified version of the \code{examples/hermitegauss\_groundstat [...]
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}name}\PYG{n+nt}{\PYGZgt{}}hermitegauss\PYGZus{}groundstate\PYG{n+nt}{\PYGZlt{}/name\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}author}\PYG{n+nt}{\PYGZgt{}}Graham Dennis\PYG{n+nt}{\PYGZlt{}/author\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}description}\PYG{n+nt}{\PYGZgt{}}
+    Solve for the groundstate of the Gross\PYGZhy{}Pitaevskii equation using the hermite\PYGZhy{}Gauss basis.
+  \PYG{n+nt}{\PYGZlt{}/description\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}features}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}benchmark} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}bing} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}validation} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}run\PYGZhy{}time\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}globals}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{k}{const} \PYG{n+nf}{real} \PYG{n}{omegaz} \PYG{o}{=} \PYG{l+m+mi}{2}\PYG{o}{*}\PYG{n}{M\PYGZus{}PI}\PYG{o}{*}\PYG{l+m+mi}{20}\PYG{p}{;}
+        \PYG{k}{const} \PYG{n+nf}{real} \PYG{n}{omegarho} \PYG{o}{=} \PYG{l+m+mi}{2}\PYG{o}{*}\PYG{n}{M\PYGZus{}PI}\PYG{o}{*}\PYG{l+m+mi}{200}\PYG{p}{;}
+        \PYG{k}{const} \PYG{n+nf}{real} \PYG{n}{hbar} \PYG{o}{=} \PYG{l+m+mf}{1.05457148e\PYGZhy{}34}\PYG{p}{;}
+        \PYG{k}{const} \PYG{n+nf}{real} \PYG{n}{M} \PYG{o}{=} \PYG{l+m+mf}{1.409539200000000e\PYGZhy{}25}\PYG{p}{;}
+        \PYG{k}{const} \PYG{n+nf}{real} \PYG{n}{g} \PYG{o}{=} \PYG{l+m+mf}{9.8}\PYG{p}{;}
+        \PYG{k}{const} \PYG{n+nf}{real} \PYG{n}{scatteringLength} \PYG{o}{=} \PYG{l+m+mf}{5.57e\PYGZhy{}9}\PYG{p}{;}
+        \PYG{k}{const} \PYG{n+nf}{real} \PYG{n}{transverseLength} \PYG{o}{=} \PYG{l+m+mf}{1e\PYGZhy{}5}\PYG{p}{;}
+        \PYG{k}{const} \PYG{n+nf}{real} \PYG{n}{Uint} \PYG{o}{=} \PYG{l+m+mf}{4.0}\PYG{o}{*}\PYG{n}{M\PYGZus{}PI}\PYG{o}{*}\PYG{n}{hbar}\PYG{o}{*}\PYG{n}{hbar}\PYG{o}{*}\PYG{n}{scatteringLength}\PYG{o}{/}\PYG{n}{M}\PYG{o}{/}\PYG{n}{transverseLength}\PYG{o}{/}\PYG{n}{transverseLength}\PYG{p}{;}
+        \PYG{k}{const} \PYG{n+nf}{real} \PYG{n}{Nparticles} \PYG{o}{=} \PYG{l+m+mf}{5.0e5}\PYG{p}{;}
+
+        \PYG{c+cm}{/* offset constants */}
+        \PYG{k}{const} \PYG{n+nf}{real} \PYG{n}{EnergyOffset} \PYG{o}{=} \PYG{l+m+mf}{0.3}\PYG{o}{*}\PYG{n}{pow}\PYG{p}{(}\PYG{n}{pow}\PYG{p}{(}\PYG{l+m+mf}{3.0}\PYG{o}{*}\PYG{n}{Nparticles}\PYG{o}{/}\PYG{l+m+mi}{4}\PYG{o}{*}\PYG{n}{omegarho}\PYG{o}{*}\PYG{n}{Uint}\PYG{p}{,}\PYG{l+m+mf}{2.0}\PYG{p}{)}\PYG{o}{*}\PYG{n}{M}\PYG{o}{/}\PYG{l+m+mf}{2.0}\PYG{p}{,}\PYG{l+m+mi}{1}\PYG{o}{/}\PYG{l+m+mf}{3.0}\PYG{p}{)}\PYG{p}{;} \PYG{c+c1}{// 1D}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/globals\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/features\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}100\PYGZdq{}} \PYG{n+na}{length\PYGZus{}scale=}\PYG{l+s}{\PYGZdq{}sqrt(hbar/(M*omegarho))\PYGZdq{}} \PYG{n+na}{transform=}\PYG{l+s}{\PYGZdq{}hermite\PYGZhy{}gauss\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}wavefunction\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}basis=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}complex\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} phi \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{n}{phi} \PYG{o}{=} \PYG{n}{sqrt}\PYG{p}{(}\PYG{n}{Nparticles}\PYG{p}{)} \PYG{o}{*} \PYG{n}{pow}\PYG{p}{(}\PYG{n}{M}\PYG{o}{*}\PYG{n}{omegarho}\PYG{o}{/}\PYG{p}{(}\PYG{n}{hbar}\PYG{o}{*}\PYG{n}{M\PYGZus{}PI}\PYG{p}{)}\PYG{p}{,} \PYG{l+m+mf}{0.25}\PYG{p}{)} \PYG{o}{*} \PYG{n}{exp}\PYG{p}{(}\PYG{o}{\PYGZhy{}}\PYG{l+m+mf}{0.5}\PYG{o}{*}\PYG{p}{(}\PYG{n}{M}\PYG{o}{*}\PYG{n}{omegarho}\PYG{o}{/}\PYG{n}{hbar}\PYG{p}{)}\PYG{o}{*}\PYG{n}{x}\PYG{o}{*}\PYG{n}{x}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}computed\PYGZus{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}normalisation\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} Ncalc \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}evaluation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{c+c1}{// Calculate the current normalisation of the wave function.}
+        \PYG{n}{Ncalc} \PYG{o}{=} \PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/evaluation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/computed\PYGZus{}vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}sequence}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}integrate} \PYG{n+na}{algorithm=}\PYG{l+s}{\PYGZdq{}ARK45\PYGZdq{}} \PYG{n+na}{interval=}\PYG{l+s}{\PYGZdq{}1.0e\PYGZhy{}2\PYGZdq{}} \PYG{n+na}{steps=}\PYG{l+s}{\PYGZdq{}4000\PYGZdq{}}  \PYG{n+na}{tolerance=}\PYG{l+s}{\PYGZdq{}1e\PYGZhy{}10\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}samples}\PYG{n+nt}{\PYGZgt{}}100 100\PYG{n+nt}{\PYGZlt{}/samples\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}filters}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}filter}\PYG{n+nt}{\PYGZgt{}}
+          \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}wavefunction normalisation\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+          \PYG{c+cp}{\PYGZlt{}![CDATA[}
+            \PYG{c+c1}{// Correct normalisation of the wavefunction}
+            \PYG{n}{phi} \PYG{o}{*}\PYG{o}{=} \PYG{n}{sqrt}\PYG{p}{(}\PYG{n}{Nparticles}\PYG{o}{/}\PYG{n}{Ncalc}\PYG{p}{)}\PYG{p}{;}
+          \PYG{c+cp}{]]\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/filter\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}/filters\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}operators}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}operator} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}ip\PYGZdq{}} \PYG{n+na}{constant=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+          \PYG{n+nt}{\PYGZlt{}operator\PYGZus{}names}\PYG{n+nt}{\PYGZgt{}}L\PYG{n+nt}{\PYGZlt{}/operator\PYGZus{}names\PYGZgt{}}
+          \PYG{c+cp}{\PYGZlt{}![CDATA[}
+            \PYG{n}{L} \PYG{o}{=} \PYG{n}{EnergyOffset}\PYG{o}{/}\PYG{n}{hbar} \PYG{o}{\PYGZhy{}} \PYG{p}{(}\PYG{n}{nx} \PYG{o}{+} \PYG{l+m+mf}{0.5}\PYG{p}{)}\PYG{o}{*}\PYG{n}{omegarho}\PYG{p}{;}
+          \PYG{c+cp}{]]\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/operator\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}integration\PYGZus{}vectors}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/integration\PYGZus{}vectors\PYGZgt{}}
+        \PYG{c+cp}{\PYGZlt{}![CDATA[}
+          \PYG{n}{dphi\PYGZus{}dt} \PYG{o}{=} \PYG{n}{L}\PYG{p}{[}\PYG{n}{phi}\PYG{p}{]} \PYG{o}{\PYGZhy{}} \PYG{n}{Uint}\PYG{o}{/}\PYG{n}{hbar}\PYG{o}{*}\PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{o}{*}\PYG{n}{phi}\PYG{p}{;}
+        \PYG{c+cp}{]]\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}/operators\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/integrate\PYGZgt{}}
+
+    \PYG{n+nt}{\PYGZlt{}filter}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}normalisation wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{phi} \PYG{o}{*}\PYG{o}{=} \PYG{n}{sqrt}\PYG{p}{(}\PYG{n}{Nparticles}\PYG{o}{/}\PYG{n}{Ncalc}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/filter\PYGZgt{}}
+
+    \PYG{n+nt}{\PYGZlt{}breakpoint} \PYG{n+na}{filename=}\PYG{l+s}{\PYGZdq{}hermitegauss\PYGZus{}groundstate\PYGZus{}break.xsil\PYGZdq{}} \PYG{n+na}{format=}\PYG{l+s}{\PYGZdq{}ascii\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}nx\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/breakpoint\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/sequence\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}output}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}}dens\PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{dens} \PYG{o}{=} \PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}kx\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}}dens\PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{dens} \PYG{o}{=} \PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/output\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+The major difference in this simulation code, aside from the switch back from dimensionless units, is the new transverse dimension type in the \code{\textless{}geometry\textgreater{}} element.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}100\PYGZdq{}} \PYG{n+na}{length\PYGZus{}scale=}\PYG{l+s}{\PYGZdq{}sqrt(hbar/(M*omegarho))\PYGZdq{}} \PYG{n+na}{transform=}\PYG{l+s}{\PYGZdq{}hermite\PYGZhy{}gauss\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+\end{Verbatim}
+
+We have explicitly defined the ``transform'' option, which by defaults expects the Fourier transform.  The \code{transform="hermite-gauss"} option requires the `mpmath' package installed, just as Fourier transforms require the FFTW package to be installed.  The ``lattice'' option details the number of hermite-Gaussian eigenstates to include, and automatically starts from the zeroth order polynomial and increases.  The number of hermite-Gaussian modes fully determines the irregular spatia [...]
+
+The \code{length\_scale="sqrt(hbar/(M*omegarho))"} option requires a real number, but since this script defines it in terms of variables, XMDS2 is unable to verify that the resulting function is real-valued at the time of generating the code.  XMDS2 will therefore fail to compile this program without the feature:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}validation} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}run\PYGZhy{}time\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+\end{Verbatim}
+
+which disables many of these checks at the time of writing the C-code.
+
+
+\section{Multi-component Schrödinger equation}
+\label{worked_examples:dmultistatese}\label{worked_examples:multi-component-schrodinger-equation}
+This example demonstrates a simple method for doing matrix calculations in XMDS2.  We are solving the multi-component PDE
+\begin{gather}
+\begin{split}\frac{\partial \phi_j(x,y)}{\partial t} = \frac{i}{2}\left(\frac{\partial^2}{\partial x^2}+\frac{\partial^2}{\partial y^2}\right)\phi_j(x,y) - i U(x,y) \sum_k V_{j k}\phi_k(x,y)\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+where the last term is more commonly written as a matrix multiplication.  Writing this term out explicitly is feasible for a small number of components, but when the number of components becomes large, or perhaps $V_{j k}$ should be precomputed for efficiency reasons, it is useful to be able to perform this sum over the integer dimensions automatically.  This example show how this can be done naturally using a computed vector.  The XMDS2 script is as follows:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}name}\PYG{n+nt}{\PYGZgt{}}2DMSse\PYG{n+nt}{\PYGZlt{}/name\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}author}\PYG{n+nt}{\PYGZgt{}}Joe Hope\PYG{n+nt}{\PYGZlt{}/author\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}description}\PYG{n+nt}{\PYGZgt{}}
+    Schroedinger equation for multiple internal states in two spatial dimensions.
+  \PYG{n+nt}{\PYGZlt{}/description\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}features}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}benchmark} \PYG{n+nt}{/\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}bing} \PYG{n+nt}{/\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}fftw} \PYG{n+na}{plan=}\PYG{l+s}{\PYGZdq{}patient\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}openmp} \PYG{n+nt}{/\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}auto\PYGZus{}vectorise} \PYG{n+nt}{/\PYGZgt{}}
+     \PYG{n+nt}{\PYGZlt{}/features\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+          \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}32\PYGZdq{}}  \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(\PYGZhy{}6, 6)\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+          \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}y\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}32\PYGZdq{}}  \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(\PYGZhy{}6, 6)\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+          \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}j\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}integer\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}} \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(0,1)\PYGZdq{}} \PYG{n+na}{aliases=}\PYG{l+s}{\PYGZdq{}k\PYGZdq{}}\PYG{n+nt}{/\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+   \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}wavefunction\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}complex\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}x y j\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} phi \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{n}{phi} \PYG{o}{=} \PYG{n}{j}\PYG{o}{*}\PYG{n}{sqrt}\PYG{p}{(}\PYG{l+m+mi}{2}\PYG{o}{/}\PYG{n}{sqrt}\PYG{p}{(}\PYG{n}{M\PYGZus{}PI}\PYG{o}{/}\PYG{l+m+mi}{2}\PYG{p}{)}\PYG{p}{)}\PYG{o}{*}\PYG{n}{exp}\PYG{p}{(}\PYG{o}{\PYGZhy{}}\PYG{p}{(}\PYG{n}{x}\PYG{o}{*}\PYG{n}{x}\PYG{o}{+}\PYG{n}{y}\PYG{o}{*}\PYG{n}{y}\PYG{p}{)}\PYG{o}{/}\PYG{l+m+mi}{4}\PYG{p}{)}\PYG{o}{*}\PYG{n}{exp}\PYG{p}{(}\PYG{k+kc}{i}\PYG{o}{*}\PYG{l+m+mf}{0.1}\PYG{o}{*}\PYG{n}{x}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}spatialInteraction\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}x y\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} U \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{n}{U}\PYG{o}{=}\PYG{n}{exp}\PYG{p}{(}\PYG{o}{\PYGZhy{}}\PYG{p}{(}\PYG{n}{x}\PYG{o}{*}\PYG{n}{x}\PYG{o}{+}\PYG{n}{y}\PYG{o}{*}\PYG{n}{y}\PYG{p}{)}\PYG{o}{/}\PYG{l+m+mi}{4}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}internalInteraction\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}j k\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} V \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{n}{V}\PYG{o}{=}\PYG{l+m+mi}{3}\PYG{o}{*}\PYG{p}{(}\PYG{n}{j}\PYG{o}{*}\PYG{p}{(}\PYG{l+m+mi}{1}\PYG{o}{\PYGZhy{}}\PYG{n}{k}\PYG{p}{)}\PYG{o}{+}\PYG{p}{(}\PYG{l+m+mi}{1}\PYG{o}{\PYGZhy{}}\PYG{n}{j}\PYG{p}{)}\PYG{o}{*}\PYG{n}{k}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}computed\PYGZus{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}coupling\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}x y j\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}complex\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}
+      VPhi
+    \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}evaluation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}x y j k\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}internalInteraction wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{c+c1}{// Calculate the current normalisation of the wave function.}
+        \PYG{n}{VPhi} \PYG{o}{=} \PYG{n}{V}\PYG{o}{*}\PYG{n}{phi}\PYG{p}{(}\PYG{n}{j} \PYG{o}{=}\PYG{o}{\PYGZgt{}} \PYG{n}{k}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/evaluation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/computed\PYGZus{}vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}sequence}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}integrate} \PYG{n+na}{algorithm=}\PYG{l+s}{\PYGZdq{}ARK45\PYGZdq{}} \PYG{n+na}{interval=}\PYG{l+s}{\PYGZdq{}2.0\PYGZdq{}} \PYG{n+na}{tolerance=}\PYG{l+s}{\PYGZdq{}1e\PYGZhy{}7\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}samples}\PYG{n+nt}{\PYGZgt{}}20 100\PYG{n+nt}{\PYGZlt{}/samples\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}operators}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}integration\PYGZus{}vectors}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/integration\PYGZus{}vectors\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}operator} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}ex\PYGZdq{}} \PYG{n+na}{constant=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+          \PYG{n+nt}{\PYGZlt{}operator\PYGZus{}names}\PYG{n+nt}{\PYGZgt{}}Ltt\PYG{n+nt}{\PYGZlt{}/operator\PYGZus{}names\PYGZgt{}}
+          \PYG{c+cp}{\PYGZlt{}![CDATA[}
+            \PYG{n}{Ltt} \PYG{o}{=} \PYG{o}{\PYGZhy{}}\PYG{k+kc}{i}\PYG{o}{*}\PYG{p}{(}\PYG{n}{kx}\PYG{o}{*}\PYG{n}{kx}\PYG{o}{+}\PYG{n}{ky}\PYG{o}{*}\PYG{n}{ky}\PYG{p}{)}\PYG{o}{*}\PYG{l+m+mf}{0.5}\PYG{p}{;}
+          \PYG{c+cp}{]]\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/operator\PYGZgt{}}
+        \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{dphi\PYGZus{}dt} \PYG{o}{=} \PYG{n}{Ltt}\PYG{p}{[}\PYG{n}{phi}\PYG{p}{]} \PYG{o}{\PYGZhy{}}\PYG{k+kc}{i}\PYG{o}{*}\PYG{n}{U}\PYG{o}{*}\PYG{n}{VPhi}\PYG{p}{;}
+        \PYG{c+cp}{]]\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}spatialInteraction coupling\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}/operators\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/integrate\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/sequence\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}output}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}x y j\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}}density\PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{density} \PYG{o}{=} \PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}x(0) y(0) j\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}}normalisation\PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{normalisation} \PYG{o}{=} \PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/output\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+The only truly new feature in this script is the ``aliases'' option on a dimension.  The integer-valued dimension in this script indexes the components of the PDE (in this case only two).  The  $V_{j k}$ term is required to be a square array of dimension of this number of components.  If we wrote the k-index of $V_{j k}$ using a separate \code{\textless{}dimension\textgreater{}} element, then we would not be enforcing the requirement that the matrix be square.  Instead, we note that we w [...]
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}j\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}integer\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}} \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(0,1)\PYGZdq{}} \PYG{n+na}{aliases=}\PYG{l+s}{\PYGZdq{}k\PYGZdq{}}\PYG{n+nt}{/\PYGZgt{}}
+\end{Verbatim}
+
+This means that we can use the index ``k'', which will have exactly the same properties as the ``j'' index.  This is used to define the ``V'' function in the ``internalInteraction'' vector.  Now, just as we use a computed vector to perform an integration over our fields, we use a computed vector to calculate the sum.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}computed\PYGZus{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}coupling\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}x y j\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}complex\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}
+    VPhi
+  \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}evaluation}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}dependencies} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}x y j k\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}internalInteraction wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+    \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{c+c1}{// Calculate the current normalisation of the wave function.}
+      \PYG{n}{VPhi} \PYG{o}{=} \PYG{n}{V}\PYG{o}{*}\PYG{n}{phi}\PYG{p}{(}\PYG{n}{j} \PYG{o}{=}\PYG{o}{\PYGZgt{}} \PYG{n}{k}\PYG{p}{)}\PYG{p}{;}
+    \PYG{c+cp}{]]\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/evaluation\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/computed\PYGZus{}vector\PYGZgt{}}
+\end{Verbatim}
+
+Since the output dimensions of the computed vector do not include a ``k'' index, this index is integrated.  The volume element for this summation is the spacing between neighbouring values of ``j'', and since this spacing is one, this integration is just a sum over k, as required.
+
+By this point, we have introduced most of the important features in XMDS2.  More details on other transform options and rarely used features can be found in the {\hyperref[advanced_topics:advancedtopics]{\emph{Advanced Topics}}} section.
+
+
+\chapter{Reference section}
+\label{reference_index:reference-section}\label{reference_index::doc}
+Contents:
+
+
+\section{Configuration, installation and runtime options}
+\label{reference_installation_and_configuration:referenceconfigurationinstallationruntime}\label{reference_installation_and_configuration::doc}\label{reference_installation_and_configuration:configuration-installation-and-runtime-options}\begin{description}
+\item[{Running the `xmds2' program with the option `--help', gives several options that can change its behaviour at runtime.  These include:}] \leavevmode\begin{itemize}
+\item {} 
+`-o' or `--output', which overrides the name of the output file to be generated
+
+\item {} 
+`-n' or `--no-compile', which generates the C code for the simulation, but does not try to compile it
+
+\item {} 
+`-v' or `--verbose', which gives verbose output about compilation flags.
+
+\item {} 
+`-g' or `--debug', which compiles the simulation in debug mode (compilation errors refer to lines in the source, not the .xmds file). This option implies `-v'. This option is mostly useful when debugging XMDS code generation.
+
+\item {} 
+`--waf-verbose', which makes \code{waf} be very verbose when configuring XMDS or compiling simulations.  This option is intended for developer use only to aid in diagnosing problems with \code{waf}.
+
+\end{itemize}
+
+\end{description}
+
+It also has commands to configure XMDS2 and recheck the installation.  If your program requires extra paths to compile, you can configure XMDS2 to include those paths by default.  Simply use the command
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nv}{\PYGZdl{} }xmds2 \PYGZhy{}\PYGZhy{}configure \PYGZhy{}\PYGZhy{}include\PYGZhy{}path /path/to/include \PYGZhy{}\PYGZhy{}lib\PYGZhy{}path /path/to/lib
+\end{Verbatim}
+
+Alternatively, you can set the \code{CXXFLAGS} or \code{LINKFLAGS} environment variables before calling \code{xmds2 -{-}reconfigure}.  For example, to pass the compiler flag \code{-pedantic} and the link flag \code{-lm} using the bash shell, use:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nv}{\PYGZdl{} }\PYG{n+nb}{export }\PYG{n+nv}{CXXFLAGS}\PYG{o}{=}\PYG{l+s+s2}{\PYGZdq{}\PYGZhy{}pedantic\PYGZdq{}}
+\PYG{n+nv}{\PYGZdl{} }\PYG{n+nb}{export }\PYG{n+nv}{LINKFLAGS}\PYG{o}{=}\PYG{l+s+s2}{\PYGZdq{}\PYGZhy{}lm\PYGZdq{}}
+\PYG{n+nv}{\PYGZdl{} }xmds2 \PYGZhy{}\PYGZhy{}reconfigure\PYG{l+s+sb}{{}`}\PYG{l+s+sb}{{}`}
+\end{Verbatim}
+
+This method can also be used to change the default compilers for standard and parallel processing, using the CXX and MPICXX flags respectively.
+
+Running XMDS2 with the `--configure' option also searches for packages that have been installed since you last installed or configured XMDS2.  If you wish to run `xmds2 --configure' with the same extra options as last time, simply use the command:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nv}{\PYGZdl{} }xmds2 \PYGZhy{}\PYGZhy{}reconfigure
+\end{Verbatim}
+
+A detailed log of the checks is saved in the file `\textasciitilde{}/.xmds/waf\_configure/config.log'.  This can be used to identify issues with packages that XMDS2 is not recognised, but you think that you have successfully installed on your system.
+
+
+\section{Useful XML Syntax}
+\label{reference_usefulXMLSyntax::doc}\label{reference_usefulXMLSyntax:referenceusefulxmlsyntax}\label{reference_usefulXMLSyntax:useful-xml-syntax}
+Standard XML placeholders can be used to simplify some scripts.  For example, the following (abbreviated) code ensures that the limits of a domain are symmetric.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{c+cp}{\PYGZlt{}?xml version=\PYGZdq{}1.0\PYGZdq{} encoding=\PYGZdq{}UTF\PYGZhy{}8\PYGZdq{}?\PYGZgt{}}
+\PYG{c+cp}{\PYGZlt{}!DOCTYPE simulation [}
+\PYG{c+cp}{\PYGZlt{}!ENTITY Npts    \PYGZdq{}64\PYGZdq{}\PYGZgt{}}
+\PYG{c+cp}{\PYGZlt{}!ENTITY L      \PYGZdq{}3.0e\PYGZhy{}5\PYGZdq{}\PYGZgt{}}
+]\PYGZgt{}
+  \PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+
+    . . .
+
+    \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+          \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}\PYGZam{}Npts;\PYGZdq{}}  \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(\PYGZhy{}\PYGZam{}L;, \PYGZam{}L;)\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+     \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+\end{Verbatim}
+
+
+\section{XMDS2 XML Schema}
+\label{reference_schema:xmds2-xml-schema}\label{reference_schema::doc}\label{reference_schema:referenceschema}
+There are many, many XML tags that can make up an XMDS2 script. Most of them are optional, or have default values if not specified. It is, however, useful to know which elements are possible, and their position and relationship to other elements in the script. Shown below is the full XML tree for XMDS2, which shows all possible elements and their position in the tree. An ellipsis (...) outside an element indicates the element above can be repeated indefinitely, and an ellipsis inside an  [...]
+
+The syntax \textless{}element /\textgreater{} can be used for lowest-level elements that have attributes but no content, and are shorthand for \textless{}element\textgreater{} \textless{}/element\textgreater{}. This shorthand notation can also be used for elements which can only contain the content ``yes'' or ``no''; in this case the presence of \textless{}element /\textgreater{} is equivalent to \textless{}element\textgreater{} yes \textless{}/element\textgreater{}, and the absence of s [...]
+
+The possible attributes and attribute values for each element are not shown; see the individual entries in the Reference section for details.
+{\hyperref[reference_elements:simulationelement]{\emph{}}}{\hyperref[reference_elements:nameelement]{\emph{}}}{\hyperref[reference_elements:nameelement]{\emph{}}}{\hyperref[reference_elements:authorelement]{\emph{}}}{\hyperref[reference_elements:authorelement]{\emph{}}}{\hyperref[reference_elements:descriptionelement]{\emph{}}}{\hyperref[reference_elements:descriptionelement]{\emph{}}}{\hyperref[reference_elements:featureselement]{\emph{}}}{\hyperref[reference_elements:argumentselement]{ [...]
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{c+cp}{\PYGZlt{}?xml version=\PYGZdq{}1.0\PYGZdq{} encoding=\PYGZdq{}UTF\PYGZhy{}8\PYGZdq{}?\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}name}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/name\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}author}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}author}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}description}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/description\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}features}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}arguments}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}argument} \PYG{n+nt}{/\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}argument} \PYG{n+nt}{/\PYGZgt{}}
+      ...
+    \PYG{n+nt}{\PYGZlt{}/arguments\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}auto\PYGZus{}vectorise} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}benchmark} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}bing} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}cflags}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/cflags\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}chunked\PYGZus{}output} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}diagnostics} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}error\PYGZus{}check} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}halt\PYGZus{}non\PYGZus{}finite} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}fftw} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}globals}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/globals\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}openmp} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}precision}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/precision\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}validation} \PYG{n+nt}{/\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/features\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}driver} \PYG{n+nt}{/\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+nt}{/\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+nt}{/\PYGZgt{}}
+      ...
+    \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}vector}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}filename}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA [}
+\PYG{c+cp}{      ]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}vector}\PYG{n+nt}{\PYGZgt{}} ... \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}vector}\PYG{n+nt}{\PYGZgt{}} ... \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+  ...
+
+  \PYG{n+nt}{\PYGZlt{}computed\PYGZus{}vector}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}evaluation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA [}
+\PYG{c+cp}{      ]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/evaluation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/computed\PYGZus{}vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}computed\PYGZus{}vector}\PYG{n+nt}{\PYGZgt{}} ... \PYG{n+nt}{\PYGZlt{}/computed\PYGZus{}vector\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}computed\PYGZus{}vector}\PYG{n+nt}{\PYGZgt{}} ... \PYG{n+nt}{\PYGZlt{}/computed\PYGZus{}vector\PYGZgt{}}
+  ...
+
+  \PYG{n+nt}{\PYGZlt{}noise\PYGZus{}vector}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/noise\PYGZus{}vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}noise\PYGZus{}vector}\PYG{n+nt}{\PYGZgt{}} ... \PYG{n+nt}{\PYGZlt{}/noise\PYGZus{}vector\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}noise\PYGZus{}vector}\PYG{n+nt}{\PYGZgt{}} ... \PYG{n+nt}{\PYGZlt{}/noise\PYGZus{}vector\PYGZgt{}}
+  ...
+
+  \PYG{n+nt}{\PYGZlt{}sequence}\PYG{n+nt}{\PYGZgt{}}
+
+    \PYG{n+nt}{\PYGZlt{}filter}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA [}
+\PYG{c+cp}{      ]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/filter\PYGZgt{}}
+
+    \PYG{n+nt}{\PYGZlt{}integrate}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}samples}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/samples\PYGZgt{}}
+
+      \PYG{n+nt}{\PYGZlt{}computed\PYGZus{}vector}\PYG{n+nt}{\PYGZgt{}} ... \PYG{n+nt}{\PYGZlt{}/computed\PYGZus{}vector\PYGZgt{}}
+
+      \PYG{n+nt}{\PYGZlt{}filters}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}filter}\PYG{n+nt}{\PYGZgt{}} ... \PYG{n+nt}{\PYGZlt{}/filter\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}filter}\PYG{n+nt}{\PYGZgt{}} ... \PYG{n+nt}{\PYGZlt{}/filter\PYGZgt{}}
+        ...
+      \PYG{n+nt}{\PYGZlt{}/filters\PYGZgt{}}
+
+      \PYG{n+nt}{\PYGZlt{}operators}\PYG{n+nt}{\PYGZgt{}}
+
+        \PYG{n+nt}{\PYGZlt{}operator}\PYG{n+nt}{\PYGZgt{}}
+          \PYG{n+nt}{\PYGZlt{}boundary\PYGZus{}condition}\PYG{n+nt}{\PYGZgt{}}
+            \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+            \PYG{c+cp}{\PYGZlt{}![CDATA [}
+\PYG{c+cp}{            ]]\PYGZgt{}}
+          \PYG{n+nt}{\PYGZlt{}/boundary\PYGZus{}condition\PYGZgt{}}
+          \PYG{n+nt}{\PYGZlt{}operator\PYGZus{}names}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/operator\PYGZus{}names\PYGZgt{}}
+          \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+          \PYG{c+cp}{\PYGZlt{}![CDATA [}
+\PYG{c+cp}{          ]]\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/operator\PYGZgt{}}
+
+        \PYG{n+nt}{\PYGZlt{}operator}\PYG{n+nt}{\PYGZgt{}} ... \PYG{n+nt}{\PYGZlt{}/operator\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}operator}\PYG{n+nt}{\PYGZgt{}} ... \PYG{n+nt}{\PYGZlt{}/operator\PYGZgt{}}
+        ...
+
+        \PYG{n+nt}{\PYGZlt{}integration\PYGZus{}vectors}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/integration\PYGZus{}vectors\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+        \PYG{c+cp}{\PYGZlt{}![CDATA [}
+\PYG{c+cp}{        ]]\PYGZgt{}}
+
+      \PYG{n+nt}{\PYGZlt{}/operators\PYGZgt{}}
+
+    \PYG{n+nt}{\PYGZlt{}/integrate\PYGZgt{}}
+
+    \PYG{n+nt}{\PYGZlt{}breakpoint}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/breakpoint\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}/sequence\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}output}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}operator}\PYG{n+nt}{\PYGZgt{}} ... \PYG{n+nt}{\PYGZlt{}/operator\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA [}
+\PYG{c+cp}{      ]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+
+    \PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group}\PYG{n+nt}{\PYGZgt{}} ... \PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group}\PYG{n+nt}{\PYGZgt{}} ... \PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+    ...
+
+  \PYG{n+nt}{\PYGZlt{}/output\PYGZgt{}}
+
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\section{XMDS2 script elements}
+\label{reference_elements:xmds2-script-elements}\label{reference_elements::doc}\label{reference_elements:referenceelements}
+This section outlines all the elements and options available in an XMDS2 script.  This is very much a \textbf{work in progress}, beginning with placeholders in most cases, as we have prioritised the tutorials for new users.  One of the most productive ways that non-developer veterans can contribute to the project is to help develop this documentation.
+
+
+\subsection{Simulation element}
+\label{reference_elements:simulation-element}\label{reference_elements:simulationelement}
+The \code{\textless{}simulation\textgreater{}} element is the single top level element in an XMDS2 simulation, and contains all the other elements.  All XMDS scripts must contain exactly one simulation element, and it must have the \code{xmds-version="2"} attribute defined.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ Rest of simulation goes here }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsection{Name element}
+\label{reference_elements:name-element}\label{reference_elements:nameelement}
+The name of your simulation. This element is optional, but recommended. If it is set, it will be the name of the executable file generated from this script. It will also be the name of the output file (with an appropriate extension) if the \code{filename} attribute is not given a value in the \code{\textless{}output\textgreater{}} element.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}name}\PYG{n+nt}{\PYGZgt{}} funky\PYGZus{}solver \PYG{n+nt}{\PYGZlt{}/name\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsection{Author element}
+\label{reference_elements:author-element}\label{reference_elements:authorelement}
+The author(s) of this script. This element is optional, but can be useful if you need to find the person who has written an incomprehensible script and thinks comments are for the weak.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}author}\PYG{n+nt}{\PYGZgt{}} Ima Mollusc \PYG{n+nt}{\PYGZlt{}/author\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsection{Description element}
+\label{reference_elements:descriptionelement}\label{reference_elements:description-element}
+A description of what the simulation does. Optional, but recommended, in case you (or someone else) has to revist the script at some distant point in the future.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}description}\PYG{n+nt}{\PYGZgt{}}
+  Calculate the 3D ground state of a Rubidium BEC in a harmonic magnetic trap assuming
+  cylindrical symmetry about the z axis and reflection symmetry about z=0.
+  This permits us to use the cylindrical Bessel functions to expand the solution transverse
+  to z and a cosine series to expand the solution along z.
+\PYG{n+nt}{\PYGZlt{}/description\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsection{Features Elements}
+\label{reference_elements:features-elements}\label{reference_elements:featureselement}
+Features elements are where simulation-wide options are specified. The \code{\textless{}features\textgreater{}} element wraps one or more elements describing features. There are many possible feature elements. Currently, a full list of the features supported is:
+\begin{itemize}
+\item {} 
+{\hyperref[reference_elements:argumentselement]{\emph{arguments}}}
+
+\item {} 
+{\hyperref[reference_elements:autovectorise]{\emph{auto\_vectorise}}}
+
+\item {} 
+{\hyperref[reference_elements:benchmark]{\emph{benchmark}}}
+
+\item {} 
+{\hyperref[reference_elements:bing]{\emph{bing}}}
+
+\item {} 
+{\hyperref[reference_elements:cflags]{\emph{cflags}}}
+
+\item {} 
+{\hyperref[reference_elements:chunkedoutput]{\emph{chunked\_output}}}
+
+\item {} 
+{\hyperref[reference_elements:diagnostics]{\emph{diagnostics}}}
+
+\item {} 
+{\hyperref[reference_elements:errorcheck]{\emph{error\_check}}}
+
+\item {} 
+{\hyperref[reference_elements:haltnonfinite]{\emph{halt\_non\_finite}}}
+
+\item {} 
+{\hyperref[reference_elements:fftw]{\emph{fftw}}}
+
+\item {} 
+{\hyperref[reference_elements:globals]{\emph{globals}}}
+
+\item {} 
+{\hyperref[reference_elements:openmp]{\emph{OpenMP}}}
+
+\item {} 
+{\hyperref[reference_elements:precision]{\emph{precision}}}
+
+\item {} 
+{\hyperref[reference_elements:validation]{\emph{validation}}}
+
+\end{itemize}
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}features}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}bing} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}precision}\PYG{n+nt}{\PYGZgt{}} double \PYG{n+nt}{\PYGZlt{}/precision\PYGZgt{}}
+    ...
+  \PYG{n+nt}{\PYGZlt{}/features\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{Arguments Element}
+\label{reference_elements:argumentselement}\label{reference_elements:arguments-element}
+The \code{\textless{}arguments\textgreater{}} element is optional, and allows defining variables that can be passed to the simulation at run time. These variables are then globally accessible throughout the simulation script. Each of the variables must be defined in an \code{\textless{}argument\textgreater{}} element (see below). The variables can then be passed to the simulation executable as options on the command line. For example, one could define the variables \code{size}, \code{num [...]
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}name}\PYG{n+nt}{\PYGZgt{}} arguments\PYGZus{}test \PYG{n+nt}{\PYGZlt{}/name\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}features}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}arguments}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}argument} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}size\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{default\PYGZus{}value=}\PYG{l+s}{\PYGZdq{}20.0\PYGZdq{}}\PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}argument} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}number\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}integer\PYGZdq{}} \PYG{n+na}{default\PYGZus{}value=}\PYG{l+s}{\PYGZdq{}7\PYGZdq{}}\PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}argument} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}pulse\PYGZus{}shape\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}string\PYGZdq{}} \PYG{n+na}{default\PYGZus{}value=}\PYG{l+s}{\PYGZdq{}gaussian\PYGZdq{}}\PYG{n+nt}{/\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/arguments\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/features\PYGZgt{}}
+\end{Verbatim}
+
+When \code{XMDS2} is run on this script the executable \code{arguments\_test} is created. The values of \code{size}, \code{number}, and \code{pulse\_shape} can then be set to whatever is desired at runtime via
+
+\begin{Verbatim}[commandchars=\\\{\}]
+./arguments\PYGZus{}test \PYGZhy{}\PYGZhy{}size=1.3 \PYGZhy{}\PYGZhy{}number=2 \PYGZhy{}\PYGZhy{}pulse\PYGZus{}shape=lorentzian
+\end{Verbatim}
+
+It is also possible to include an optional \code{CDATA} block inside the \code{\textless{}arguments\textgreater{}} block. This code will run after the arguments have been initialised with the values passed from the command line. This code block could be used, for example, to sanity check the parameters passed in, or for assigning values to global variables based on those parameters.  Any references to variables defined in an \code{\textless{}argument\textgreater{}} element should be made [...]
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}features}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}globals}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{n+nf}{real} \PYG{n}{atom\PYGZus{}kick}\PYG{p}{;}
+    \PYG{c+cp}{]]\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}globals}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}arguments}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}argument} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}bragg\PYGZus{}order\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}integer\PYGZdq{}} \PYG{n+na}{default\PYGZus{}value=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{/\PYGZgt{}}
+    \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{n}{atom\PYGZus{}kick} \PYG{o}{=} \PYG{n}{bragg\PYGZus{}order} \PYG{o}{*} \PYG{l+m+mi}{2}\PYG{o}{*}\PYG{n}{M\PYGZus{}PI} \PYG{o}{/} \PYG{l+m+mf}{780e\PYGZhy{}9}\PYG{p}{;}
+    \PYG{c+cp}{]]\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/arguments\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/features\PYGZgt{}}
+\end{Verbatim}
+
+
+\paragraph{Argument element}
+\label{reference_elements:argument-element}\label{reference_elements:argumentelement}
+Each \code{\textless{}argument\textgreater{}} element describes one variable that can be passed to the simulation at runtime via the command line. There are three mandatory attributes: \code{name}, \code{type}, and \code{default\_value}. \code{name} is the name by which you can refer to that variable later in the script, as well as the name of the command line parameter. \code{type} defines the data type of the variable, and \code{default\_value} is the value to which the variable is set [...]
+
+
+\subsubsection{Auto\_vectorise element}
+\label{reference_elements:autovectorise}\label{reference_elements:auto-vectorise-element}
+The \code{\textless{}auto\_vectorise /\textgreater{}} feature attempts to activate automatic vectorisation for large loops, if it is available in the compiler.  This should make some simulations go faster.
+
+
+\subsubsection{Benchmark}
+\label{reference_elements:benchmark}\label{reference_elements:id1}
+The \code{\textless{}benchmark /\textgreater{}} feature includes a timing routine in the generated code, so that it is possible to see how long the simulations take to run.
+
+
+\subsubsection{Bing}
+\label{reference_elements:bing}\label{reference_elements:id2}
+The \code{\textless{}bing /\textgreater{}} feature causes the simulation to make an invigorating sound when the simulation finishes executing.
+
+
+\subsubsection{C Flags}
+\label{reference_elements:c-flags}\label{reference_elements:cflags}
+The \code{\textless{}cflags\textgreater{}} feature allows extra flags to be passed to the compiler.  This can be useful for optimisation, and also using specific external libraries.  The extra options to be passed are defined with a `CDATA' block.  The compile options can be made visible by running XMDS2 either with the ``-v'' (verbose) option, or the ``-g'' (debug) option.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}cflags}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{o}{\PYGZhy{}}\PYG{n}{O4}
+    \PYG{c+cp}{]]\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/cflags\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{Chunked Output}
+\label{reference_elements:chunked-output}\label{reference_elements:chunkedoutput}
+By default, XMDS2 keeps the contents of all output moment groups in memory until the end of the simulation when they are written to the output file.  This can be a problem if your simulation creates a very large amount of output.  \code{\textless{}chunked\_output /\textgreater{}} causes the simulation to save the output data in chunks as the simulation progresses.  For some simulations this can significantly reduce the amount of memory required.  The amount of data in a chunk can be spec [...]
+
+Limitations (XMDS will give you an error if you violate any of these):
+\begin{itemize}
+\item {} 
+This feature cannot be used with the ASCII output file format due to limitations in the file format.
+
+\item {} 
+This feature cannot be used with the \code{multi-path} drivers because all sampling data is required to compute the mean and standard error statistics.
+
+\item {} 
+Neither is this feature compatible with the \code{error\_check} feature as that relies on all sampling data being available to compute the error.
+
+\end{itemize}
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}features}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}chunked\PYGZus{}output} \PYG{n+na}{size=}\PYG{l+s}{\PYGZdq{}5MB\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/features\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{Diagnostics}
+\label{reference_elements:id3}\label{reference_elements:diagnostics}
+The \code{\textless{}diagnostics /\textgreater{}} feature causes a simulation to output more information as it executes.  This should be useful when a simulation is dying / giving bad results to help diagnose the cause.  Currently, it largely outputs step error information.
+
+
+\subsubsection{Error Check}
+\label{reference_elements:errorcheck}\label{reference_elements:error-check}
+It's often important to know whether you've got errors.  This feature runs each integration twice: once with the specified error tolerance or defined lattice spacing in the propagation dimension, and then again with half the lattice spacing, or an equivalently lower error tolerance.  Each component of the output then shows the difference between these two integrations as an estimate of the error.  This feature is particularly useful when integrating stochastic equations, as it treats the [...]
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}features}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}error\PYGZus{}check} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/features\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{Halt\_Non\_Finite}
+\label{reference_elements:halt-non-finite}\label{reference_elements:haltnonfinite}
+The \code{\textless{}halt\_non\_finite /\textgreater{}} feature is used to stop computations from continuing to run after the vectors stop having numerical values.  This can occur when a number is too large to represent numerically, or when an illegal operation occurs.  Processing variables with non-numerical values is usually much slower than normal processing, and the results are meaningless.  Of course, there is a small cost to introducing a run-time check, so this feature is optional.
+
+
+\subsubsection{fftw element}
+\label{reference_elements:fftw}\label{reference_elements:fftw-element}
+The \code{\textless{}fftw \textbackslash{}\textgreater{}} feature can be used to pass options to the \href{http://fftw.org}{Fast Fourier Transform library} used by XMDS.  This library tests algorithms on each architecture to determine the fastest method of solving each problem.  Typically this costs very little overhead, as the results of all previous tests are stored in the directory ``\textasciitilde{}/.xmds/wisdom''.  The level of detail for the search can be specified using the \code [...]
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}fftw} \PYG{n+na}{plan=}\PYG{l+s}{\PYGZdq{}patient\PYGZdq{}} \PYG{n+na}{threads=}\PYG{l+s}{\PYGZdq{}3\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{Globals}
+\label{reference_elements:id4}\label{reference_elements:globals}
+The globals feature places the contents of a `CDATA' block near the top of the generated program.  Amongst other things, this is useful for defining variables that are then accessible throughout the entire program.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}globals}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{c+cp}{\PYGZlt{}![CDATA[}
+    \PYG{k}{const} \PYG{n+nf}{real} \PYG{n}{omegaz} \PYG{o}{=} \PYG{l+m+mi}{2}\PYG{o}{*}\PYG{n}{M\PYGZus{}PI}\PYG{o}{*}\PYG{l+m+mi}{20}\PYG{p}{;}
+    \PYG{k+kt}{long} \PYG{n}{Nparticles} \PYG{o}{=} \PYG{l+m+mi}{50000}\PYG{p}{;}
+
+    \PYG{c+cm}{/* offset constants */}
+    \PYG{n+nf}{real} \PYG{n}{frequency} \PYG{o}{=} \PYG{n}{omegaz}\PYG{o}{/}\PYG{l+m+mi}{2}\PYG{o}{/}\PYG{n}{M\PYGZus{}PI}\PYG{p}{;}
+  \PYG{c+cp}{]]\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/globals\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{OpenMP}
+\label{reference_elements:openmp}\label{reference_elements:id5}
+The \code{\textless{}openmp /\textgreater{}} feature instructs compatible compilers to parallelise key loops using the \href{http://www.openmp.org}{OpenMP API} standard.  By default the simulation will use all available CPUs.  The number of threads used can be restricted by specifying the number of threads in the script with \code{\textless{}openmp threads="2"/\textgreater{}}, or by setting the \code{OMP\_NUM\_THREADS} environment variable at run-time like so:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+OMP\PYGZus{}NUM\PYGZus{}THREADS=2 ./simulation\PYGZus{}name
+\end{Verbatim}
+
+
+\subsubsection{Precision}
+\label{reference_elements:id6}\label{reference_elements:precision}
+This specifies the precision of the XMDS2 \code{real} and \code{complex} datatypes, as well as the precision used when computing transforms. Currently two values are accepted: \code{single} and \code{double}. If this feature isn't specified, XMDS2 defaults to using double precision for its variables and internal calculations.
+
+Single precision has approximately 7.2 decimal digits of accuracy, with a minimum value of 1.4×10$^{\text{-45}}$ and a maximum of 3.8×10$^{\text{34}}$. Double precision has approximately 16 decimal digits of accuracy, a minimum value of 4.9×10$^{\text{-324}}$ and a maximum value of 1.8×10$^{\text{308}}$.
+
+Using single precision can be attractive, as it can be more than twice as fast, depending on whether a simulation is CPU bound, memory bandwidth bound, MPI bound or bottlenecked elsewhere, although in some situations you may see no speed-up at all. Caution should be exercised, however. Keep in mind how many timesteps your simulation requires, and take note of the tolerance you have set per step, to see if the result will lie within your acceptable total error - seven digit precision isn' [...]
+
+Also note that when using an adaptive step integrator, setting a tolerance close to limits of the precision can lead to very slow performance.
+
+A further limitation is that not all the combinations of random number generators and probability distributions that are supported in double precision are supported in single precision. For example, the \code{solirte} generator does not support single precision gaussian distributions. \code{dsfmt}, however, is one of the fastest generators, and does support single precision.
+
+WARNING: Single precision mode has not been tested anywhere near as thoroughly as the default double precision mode, and there is a higher chance you will run into bugs.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}features}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}precision}\PYG{n+nt}{\PYGZgt{}} single \PYG{n+nt}{\PYGZlt{}/precision\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/features\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{Validation}
+\label{reference_elements:id7}\label{reference_elements:validation}
+XMDS2 makes a large number of checks in the code generation process to verify that the values for all parameters are safe choices.  Sometimes we wish to allow these parameters to be specified by variables.  This opens up many possibilities, but requires that any safety checks for parameters be performed during the execution of the program itself.  The \code{\textless{}validation\textgreater{}} feature activates that option, with allowable attributes being ``run-time'', ``compile-time'' a [...]
+
+As an example, one may wish to define the number of grid points and the range of the grid at run-time rather than explicitly define them in the XMDS2 script. To accomplish this, one could do the following:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+ \PYG{n+nt}{\PYGZlt{}name}\PYG{n+nt}{\PYGZgt{}} validation\PYGZus{}test \PYG{n+nt}{\PYGZlt{}/name\PYGZgt{}}
+ \PYG{n+nt}{\PYGZlt{}features}\PYG{n+nt}{\PYGZgt{}}
+   \PYG{n+nt}{\PYGZlt{}validation} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}run\PYGZhy{}time\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+   \PYG{n+nt}{\PYGZlt{}arguments}\PYG{n+nt}{\PYGZgt{}}
+     \PYG{n+nt}{\PYGZlt{}argument} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}xmin\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{default\PYGZus{}value=}\PYG{l+s}{\PYGZdq{}\PYGZhy{}1.0\PYGZdq{}}\PYG{n+nt}{/\PYGZgt{}}
+     \PYG{n+nt}{\PYGZlt{}argument} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}xmax\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{default\PYGZus{}value=}\PYG{l+s}{\PYGZdq{}1.0\PYGZdq{}}\PYG{n+nt}{/\PYGZgt{}}
+     \PYG{n+nt}{\PYGZlt{}argument} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}numGridPoints\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}integer\PYGZdq{}} \PYG{n+na}{default\PYGZus{}value=}\PYG{l+s}{\PYGZdq{}128\PYGZdq{}}\PYG{n+nt}{/\PYGZgt{}}
+   \PYG{n+nt}{\PYGZlt{}/arguments\PYGZgt{}}
+ \PYG{n+nt}{\PYGZlt{}/features\PYGZgt{}}
+
+ \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+   \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+   \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+     \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}numGridPoints\PYGZdq{}}  \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(xmin, xmax)\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+   \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+\end{Verbatim}
+
+and then run the resulting executable with:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+./validation\PYGZus{}test \PYGZhy{}\PYGZhy{}xmin=\PYGZhy{}2.0 \PYGZhy{}\PYGZhy{}xmax=2.0 \PYGZhy{}\PYGZhy{}numGridPoints=64
+\end{Verbatim}
+
+This approach means that when XMDS2 is parsing the script it is unable to tell, for example, if the number of sampling points requested is less than or equal to the lattice size. Consequently it will create an executable with ``numGridPoints'' as an internal variable, and make the check at run-time, when it knows the value of ``numGridPoints'' rather than at compile time, when it doesn't.
+
+
+\subsection{Driver Element}
+\label{reference_elements:driver-element}\label{reference_elements:driverelement}
+The driver element controls the overall management of the simulation, including how many paths of a stochastic simulation are to be averaged, and whether or not it is to be run using distributed memory parallelisation.  If it is not included, then the simulation is performed once without using MPI parallelisation.  If it is included, it must have a \code{name} attribute.
+
+The \code{name} attribute can have values of ``none'' (which is equivalent to the default option of not specifying a driver), ``distributed-mpi'', ``multi-path'' or ``mpi-multi-path''.
+
+Choosing the \code{name="distributed-mpi"} option allows a single integration over multiple processors.  The resulting executable can then be run according to your particular implementation of MPI.  The FFTW library only allows MPI processing of multidimensional vectors, as otherwise shared memory parallel processing requires too much inter-process communication to be efficient.  Maximally efficient parallelisation occurs where evolution is entirely local in one transverse dimension (see [...]
+
+The \code{name="multi-path"} option is used for stochastic simulations, which are typically run multiple times and averaged.  It requires a \code{paths} attribute with the number of iterations of the integration to be averaged.  The output will report the averages of the desired samples, and the standard error in those averages.
+The \code{name="mpi-multi-path"} option integrates separate paths on different processors, which is typically a highly efficient process.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}driver} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}distributed\PYGZhy{}mpi\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+        \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ or }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}driver} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}multi\PYGZhy{}path\PYGZdq{}} \PYG{n+na}{paths=}\PYG{l+s}{\PYGZdq{}10\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+        \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ or }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}driver} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}mpi\PYGZhy{}multi\PYGZhy{}path\PYGZdq{}} \PYG{n+na}{paths=}\PYG{l+s}{\PYGZdq{}1000\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsection{Geometry Element}
+\label{reference_elements:geometry-element}\label{reference_elements:geometryelement}\phantomsection\label{reference_elements:propagationdimensionelement}
+The \code{\textless{}geometry\textgreater{}} element describes the dimensions used in your simulation, and is required.  The only required element inside is the \code{\textless{}propagation\_dimension\textgreater{}} element, which defines the name of the dimension along which your simulation will integrate.  Nothing else about this dimension is specified, as requirements for the lattice along the integration dimension is specified by the \code{\textless{}integrate\textgreater{}} blocks t [...]
+\phantomsection\label{reference_elements:transversedimensionselement}\phantomsection\label{reference_elements:dimensionelement}
+If there are other dimensions in your problem, they are called ``transverse dimensions'', and are described in the \code{\textless{}transverse\_dimensions\textgreater{}} element.  Each dimension is then described in its own \code{\textless{}dimension\textgreater{}} element.  A transverse dimension must have a unique name defined by a \code{name} attribute.  If it is not specified, the type of dimension will default to ``real'', otherwise it can be specified with the \code{type} attribute [...]
+
+Each transverse dimension must specify how many points or modes it requires, and the range over which it is defined.  This is done by the \code{lattice} and \code{domain} attributes respectively.  The \code{lattice} attribute is an integer, and is optional for integer dimensions, where it can be defined implicitly by the domain.  The \code{domain} attribute is specified as a pair of numbers (e.g. \code{domain="(-17,3)"}) defining the minimum and maximum of the grid.
+
+Any dimension can have a number of aliases.  These act exactly like copies of that dimension, but must be included explicitly in the definition of subsequent vectors (i.e. they are not included in the default list of dimensions for a new vector).  The list of aliases for a dimension are included in an \code{aliases} attribute.  They are useful for non-local reference of variables.  See \code{groundstate\_gaussian.xmds} and \code{2DMultistateSE.xmds} as examples.
+
+Integrals over a dimension can be multiplied by a common prefactor, which is specified using the \code{volume\_prefactor} attribute.  For example, this allows the automatic inclusion of a factor of two due to a reflection symmetry by adding the attribute \code{volume\_prefactor="2"}.  In very specific cases, you may wish to refer to volume elements explicitly.  This will lead to grid-dependent behaviour, which is sometimes required in certain stochastic field simulations, for example.  I [...]
+
+If you are using the \code{distributed-mpi} driver to parallelise the simulation, place the dimension you wish to split over multiple processors first.  The most efficient parallelisation would involve distributing a dimension with only local evolution, as the different memory blocks would not need to communicate.  Nonlocal evolution that is local in Fourier space is the second preference, as the Fourier transform can also be successfully parallelised with minimum communication.
+\phantomsection\label{reference_elements:transforms}
+Each transverse dimension can be associated with a transform.  This allows the simulation to manipulate vectors defined on that dimension in the transform space.  The default is Fourier space (with the associated transform being the discrete Fourier transform, or ``dft''), but others can be specified with the \code{transform} attribute.  The other options are ``none'', ``dst'', ``dct'', ``bessel'', ``spherical-bessel'' and ``hermite-gauss''.  Using the right transform can dramatically im [...]
+
+An advanced feature discussed further in {\hyperref[advanced_topics:dimensionaliases]{\emph{Dimension aliases}}} are dimension aliases, which are specified by the \code{aliases} attribute.  This feature is useful for example, when calculating correlation functions.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+            \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ A real}\PYG{c}{\PYGZhy{}}\PYG{c}{valued dimension from }\PYG{c}{\PYGZhy{}}\PYG{c}{1.5 to 1.5 }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+            \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}128\PYGZdq{}} \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(\PYGZhy{}1.5, 1.5)\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+
+            \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ An integer}\PYG{c}{\PYGZhy{}}\PYG{c}{valued dimension with the 6 values }\PYG{c}{\PYGZhy{}}\PYG{c}{2, }\PYG{c}{\PYGZhy{}}\PYG{c}{1, 0, 1, 2, 3 }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+            \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}j\PYGZdq{}}               \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(\PYGZhy{}2,3)\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}integer\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+
+            \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ A real}\PYG{c}{\PYGZhy{}}\PYG{c}{valued dimension using the bessel transform for a radial coordinate }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+            \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}r\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}64\PYGZdq{}} \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(0, 5)\PYGZdq{}}  \PYG{n+na}{transform=}\PYG{l+s}{\PYGZdq{}bessel\PYGZdq{}} \PYG{n+na}{volume\PYGZus{}prefactor=}\PYG{l+s}{\PYGZdq{}2.0*M\PYGZus{}PI\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{The ``dft'' transform}
+\label{reference_elements:dft-transform}\label{reference_elements:the-dft-transform}
+The ``dft'' transform is performed using the the normal discrete Fourier transform, which means that it enforces periodic boundary conditions on vectors defined on that dimension.  Another implication is that it can only be used with complex-valued vectors.  The discrete Fourier transform is almost exactly the same as a standard Fourier transform.  The standard Fourier transform is
+\begin{gather}
+\begin{split}\mathcal{F}\left[f(x)\right](k) = \frac{1}{\sqrt{2\pi}}\int_{x_\text{min}}^{x_\text{max}} f(x) e^{-i k x} dx\end{split}\notag
+\end{gather}
+The discrete Fourier transform has no information about the domain of the lattice, so the XMDS2 transform is equivalent to
+\begin{gather}
+\begin{split}\tilde{\mathcal{F}}\left[f(x)\right](k) &= \frac{1}{\sqrt{2\pi}}\int_{x_\text{min}}^{x_\text{max}} f(x) e^{-i k (x+ x_\text{min})} dx \\
+&= e^{-i x_\text{min} k} \mathcal{F}\left[f(x)\right](k)\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+The standard usage in an XMDS simulation involves moving to Fourier space, applying a transformation, and then moving back.  For this purpose, the two transformations are entirely equivalent as the extra phase factor cancels.  However, when fields are explicitly defined in Fourier space, care must be taken to include this phase factor explicitly.  See section {\hyperref[advanced_topics:convolutions]{\emph{Convolutions and Fourier transforms}}} in the Advanced Topics section.
+
+When a dimension uses the ``dft'' transform, then the Fourier space variable is defined as the name of the dimension prefixed with a ``k''.  For example, the dimensions ``x'', ``y'', ``z'' and ``tau'' will be referenced in Fourier space as ``kx'',''ky'', ``kz'' and ``ktau''.
+
+Fourier transforms allow easy calculation of derivatives, as the n$^{\text{th}}$ derivative of a field is proportional to the n$^{\text{th}}$ moment of the field in Fourier space:
+\begin{gather}
+\begin{split}\mathcal{F}\left[\frac{\partial^n f(x)}{\partial x^n}\right](k_x) = \left(i \;k_x\right)^n \mathcal{F}\left[f(x)\right](k_x)\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+This identity can be used to write the differential operator $\mathcal{L} = \frac{\partial}{\partial x}$ as an \code{IP} or \code{EX} operator as \code{L = i*kx;} (see {\hyperref[reference_elements:operatorselement]{\emph{Operators and operator elements}}} for more details).
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+            \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ transform=\PYGZdq{}dft\PYGZdq{} is the default, omitting it wouldn\PYGZsq{}t change anything }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+            \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}128\PYGZdq{}} \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(\PYGZhy{}1.5, 1.5)\PYGZdq{}} \PYG{n+na}{transform=}\PYG{l+s}{\PYGZdq{}dft\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{The ``dct'' transform}
+\label{reference_elements:the-dct-transform}
+The ``dct'' (discrete cosine transform) is a Fourier-based transform that implies different boundary conditions for associated vectors.  XMDS uses the type-II DCT, often called ``the DCT'', and its inverse, which is also called the type-III DCT.  This transform assumes that any vector using this dimension is both periodic, and also even around a specific point within each period.  The grid is therefore only defined across a half period in order to sample each unique point once, and can t [...]
+
+As the DCT transform can be defined on real data rather only complex data, it can also be superior to DFT-based spectral methods for simulations of real-valued fields where boundary conditions are artificial.
+
+XMDS labels the cosine transform space variables the same as for {\hyperref[reference_elements:dft-transform]{\emph{Fourier transforms}}} and all the even derivatives can be calculated the same way.  Odd moments of the cosine-space variables are in fact \emph{not} related to the corresponding odd derivatives by an inverse cosine transform.
+
+Discrete cosine transforms allow easy calculation of even-order derivatives, as the 2n$^{\text{th}}$ derivative of a field is proportional to the 2n$^{\text{th}}$ moment of the field in DCT-space:
+\begin{gather}
+\begin{split}\mathcal{F}_\text{DCT}\left[\frac{\partial^{2n} f(x)}{\partial x^{2n}}\right](k_x) = (-k_x^2)^{n}\; \mathcal{F}_\text{DCT}\left[f(x)\right](k_x)\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+This identity can be used to write the differential operator $\mathcal{L} = \frac{\partial^2}{\partial x^2}$ as an \code{IP} or \code{EX} operator as \code{L = -kx*kx;} (see {\hyperref[reference_elements:operatorselement]{\emph{Operators and operator elements}}} for more details).
+
+For problems where you are defining the simulation domain over only half of the physical domain to take advantage of reflection symmetry, consider using \code{volume\_prefactor="2.0"} so that all volume integrals are over the entire physical domain, not just the simulation domain. i.e. integrals would be over -1 to 1 instead of 0 to 1 if the domain was specified as \code{domain="(0,1)"}.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+            \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}128\PYGZdq{}} \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(\PYGZhy{}1.5, 1.5)\PYGZdq{}} \PYG{n+na}{transform=}\PYG{l+s}{\PYGZdq{}dct\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+                \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ Or to cause volume integrals to be multiplied by 2 }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+            \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}y\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}128\PYGZdq{}} \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(0, 1)\PYGZdq{}} \PYG{n+na}{transform=}\PYG{l+s}{\PYGZdq{}dct\PYGZdq{}} \PYG{n+na}{volume\PYGZus{}prefactor=}\PYG{l+s}{\PYGZdq{}2.0\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{The ``dst'' transform}
+\label{reference_elements:the-dst-transform}
+The ``dst'' (discrete sine transform) is a counterpart to the DCT transform.  XMDS uses the type-II DST and its inverse, which is also called the type-III DST.  This transform assumes that fields are periodic in this dimension, but also that they are also odd around a specific point within each period.  The grid is therefore only defined across a half period in order to sample each unique point once, and can therefore be of any shape where all the even derivatives are zero at each boundary.
+
+The DST transform can be defined on real-valued vectors.  As odd-valued functions are zero at the boundaries, this is a natural transform to use when implementing zero Dirichlet boundary conditions.
+
+XMDS labels the sine transform space variables the same as for {\hyperref[reference_elements:dft-transform]{\emph{Fourier transforms}}} and all the even derivatives can be calculated the same way.  Odd moments of the sine-space variables are in fact \emph{not} related to the corresponding odd derivatives by an inverse sine transform.
+
+Discrete sine transforms allow easy calculation of even-order derivatives, as the 2n$^{\text{th}}$ derivative of a field is proportional to the 2n$^{\text{th}}$ moment of the field in DST-space:
+\begin{gather}
+\begin{split}\mathcal{F}_\text{DST}\left[\frac{\partial^{2n} f(x)}{\partial x^{2n}}\right](k_x) = (-k_x^2)^{n}\; \mathcal{F}_\text{DST}\left[f(x)\right](k_x)\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+This identity can be used to write the differential operator $\mathcal{L} = \frac{\partial^2}{\partial x^2}$ as an \code{IP} or \code{EX} operator as \code{L = -kx*kx;} (see {\hyperref[reference_elements:operatorselement]{\emph{Operators and operator elements}}} for more details).
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+            \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}128\PYGZdq{}} \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(0, 1.5)\PYGZdq{}} \PYG{n+na}{transform=}\PYG{l+s}{\PYGZdq{}dst\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{The ``bessel'' transform}
+\label{reference_elements:the-bessel-transform}\label{reference_elements:besseltransform}
+Just as the Fourier basis is useful for finding derivatives in Euclidean geometry, the basis of Bessel functions is useful for finding certain common operators in cylindrical co-ordinates.  In particular, we use the Bessel functions of the first kind, $J_m(u)$.  The relevant transform is the Hankel transform:
+\begin{gather}
+\begin{split}F_m(k) = \mathcal{H}_m \left[f\right](k) = \int_0^\infty r f(r) J_m(k r) dr\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+which has the inverse transform:
+\begin{gather}
+\begin{split}f(r) = \mathcal{H}^{-1}_m \left[F_m\right](r) = \int_0^\infty k F_m(k) J_m(k r) dk\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+This transform pair has the useful property that the Laplacian in cylindrical co-ordinates is diagonal in this basis:
+\begin{gather}
+\begin{split}\nabla^2 \left(f(r) e^{i m \theta}\right) &= \left(\frac{\partial^2 f}{\partial r^2} +\frac{1}{r}\frac{\partial f}{\partial r} -\frac{m^2}{r^2} f \right) e^{i m \theta} = \left\{\mathcal{H}^{-1}_m \left[(-k^2) F_m(k)\right](r) \right\} e^{i m \theta}\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+XMDS labels the variables in the transformed space with a prefix of `k', just as for {\hyperref[reference_elements:dft-transform]{\emph{Fourier transforms}}}.  The order $m$ of the transform is defined by the \code{order} attribute in the \code{\textless{}dimension\textgreater{}} element, which must be assigned as a non-negative integer.  If the order is not specified, it defaults to zero which corresponds to the solution being independent of the angular coordinate $\theta$.
+
+It can often be useful to have a different sampling in normal space and Hankel space.  Reducing the number of modes in either space dramatically speeds simulations.  To set the number of lattice points in Hankel space to be different to the number of lattice points for the field in its original space, use the attribute \code{spectral\_lattice}.  The Bessel space lattice is chosen such that the boundary condition at the edge of the domain is zero.  This ensures that all of the Bessel mode [...]
+
+Hankel transforms allow easy calculation of the Laplacian of fields with cylindrical symmetry.  Applying the operator \code{L = -kr*kr} in Hankel space is therefore equivalent to applying the operator
+\begin{gather}
+\begin{split}\mathcal{L} = \left(\frac{\partial^2}{\partial r^2} +\frac{1}{r}\frac{\partial}{\partial r} -\frac{m^2}{r^2} \right)\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+in coordinate space.
+
+In non-Euclidean co-ordinates, integrals have non-unit volume elements.  For example, in cylindrical co-ordinates with a radial co-ordinate `r', integrals over this dimension have a volume element $r dr$.  When performing integrals along a dimension specified by the ``bessel'' transform, the factor of the radius is included implicitly.  If you are using a geometry with some symmetry, it is common to have prefactors in your integration.  For example, for a two-dimensional volume in cylind [...]
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+            \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}r\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}128\PYGZdq{}} \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(0, 3)\PYGZdq{}} \PYG{n+na}{transform=}\PYG{l+s}{\PYGZdq{}bessel\PYGZdq{}} \PYG{n+na}{volume\PYGZus{}prefactor=}\PYG{l+s}{\PYGZdq{}2*M\PYGZus{}PI\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{The ``spherical-bessel'' transform}
+\label{reference_elements:the-spherical-bessel-transform}
+When working in spherical coordinates, it is often useful to use the spherical Bessel functions $j_l(x)=\sqrt{\frac{\pi}{2x}}J_{l+\frac{1}{2}}(x)$ as a basis.  These are eigenfunctions of the radial component of Laplace's equation in spherical coordinates:
+\begin{gather}
+\begin{split}\nabla^2 \left[j_l(k r)\; Y^m_l(\theta, \phi)\right] &= \left[\frac{\partial^2 }{\partial r^2} +\frac{2}{r}\frac{\partial }{\partial r} -\frac{l(l+1)}{r^2}\right] j_l(k r) \; Y^m_l(\theta, \phi) = -k^2 j_l(k r)\; Y^m_l(\theta, \phi)\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+Just as the Bessel basis above, the transformed dimensions are prefixed with a `k', and it is possible (and usually wise) to use the \code{spectral\_lattice} attribute to specify a different lattice size in the transformed space.  Also, the spacing of these lattices are again chosen in a non-uniform manner to Gaussian quadrature methods for spectrally accurate transforms.  Finally, the \code{order} attribute can be used to specify the order $l$ of the spherical Bessel functions used.
+
+If we denote the transformation to and from this basis by $\mathcal{SH}$, then we can write the useful property:
+\begin{gather}
+\begin{split}\frac{\partial^2 f}{\partial r^2} +\frac{2}{r}\frac{\partial f}{\partial r} -\frac{l (l+1)}{r^2} = \mathcal{SH}^{-1}_l \left[(-k^2) F_l(k)\right](r)\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+Spherical Bessel transforms allow easy calculation of the Laplacian of fields with spherical symmetry. Applying the operator \code{L = -kr*kr} in Spherical Bessel space is therefore equivalent to applying the operator
+\begin{gather}
+\begin{split}\mathcal{L} = \left( \frac{\partial^2}{\partial r^2} +\frac{2}{r}\frac{\partial}{\partial r} -\frac{l (l+1)}{r^2} \right)\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+in coordinate space.
+
+In non-Euclidean co-ordinates, integrals have non-unit volume elements.  For example, in spherical co-ordinates with a radial co-ordinate `r', integrals over this dimension have a volume element $r^2 dr$.  When performing integrals along a dimension specified by the ``spherical-bessel'' transform, the factor of the square of the radius is included implicitly.  If you are using a geometry with some symmetry, it is common to have prefactors in your integration.  For example, for a three-di [...]
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+            \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}r\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}128\PYGZdq{}} \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(0, 3)\PYGZdq{}} \PYG{n+na}{transform=}\PYG{l+s}{\PYGZdq{}spherical\PYGZhy{}bessel\PYGZdq{}} \PYG{n+na}{volume\PYGZus{}prefactor=}\PYG{l+s}{\PYGZdq{}4*M\PYGZus{}PI\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{The ``hermite-gauss'' transform}
+\label{reference_elements:the-hermite-gauss-transform}
+The ``hermite-gauss'' transform allows transformations to and from the basis of Hermite functions $\psi_n(x)$:
+\begin{gather}
+\begin{split}\psi_n(x) = \left(2^n n! \sigma \sqrt{\pi}\right)^{-1/2} e^{-x^2/2\sigma^2} H_n(\sigma x)\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+where the functions $H_n(x)$ are the Hermite polynomials:
+\begin{gather}
+\begin{split}H_n(x) &= (-1)^n e^{x^2} \frac{d^n}{dx^n} \left(e^{-x^2}\right)\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+which are eigenfunctions of the Schroedinger equation for a harmonic oscillator:
+\begin{gather}
+\begin{split}- \frac{\hbar^2}{2 m} \frac{\partial^2 \psi_n}{\partial x^2} + \frac{1}{2} m \omega^2 x^2 \psi_n(x) = \hbar \omega\left(n+\frac{1}{2}\right) \psi_n(x),\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+with $\sigma = \sqrt{\frac{\hbar}{m \omega}}$.
+
+This transform is different to the others in that it requires a \code{length\_scale} attribute rather than a \code{domain} attribute, as the range of the lattice will depend on the number of basis functions used. The \code{length\_scale} attribute defines the scale of the domain as the standard deviation $\sigma$ of the lowest order Hermite function $\psi_0(x)$:
+\begin{gather}
+\begin{split}\psi_0(x) = (\sigma^2 \pi)^{-1/4} e^{-x^2/2 \sigma^2}\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+When a dimension uses the ``hermite-gauss'' transform, then the variable indexing the basis functions is defined as the name of the dimension prefixed with an ``n''.  For example, when referencing the basis function indices for the dimensions ``x'', ``y'', ``z'' and ``tau'', use the variable ``nx'', ``ny'', ``nz'' and ``ntau''.
+
+Applying the operator \code{L = nx + 0.5} in Hermite space is therefore equivalent to applying the operator
+\begin{gather}
+\begin{split}\mathcal{L} = \left(- \frac{\sigma^2}{2}\frac{\partial^2}{\partial x^2} + \frac{1}{2 \sigma^2} x^2 \right)\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+in coordinate space.
+
+The Hermite-Gauss transform permits one to work in energy-space for the harmonic oscillator.  The normal Fourier transform of ``hermite-gauss'' dimensions can also be referenced using the dimension name prefixed with a ``k''.  See the examples \code{hermitegauss\_transform.xmds} and \code{hermitegauss\_groundstate.xmds} for examples.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+            \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}r\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}128\PYGZdq{}} \PYG{n+na}{length\PYGZus{}scale=}\PYG{l+s}{\PYGZdq{}1.0\PYGZdq{}} \PYG{n+na}{transform=}\PYG{l+s}{\PYGZdq{}hermite\PYGZhy{}gauss\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsection{Vector Element}
+\label{reference_elements:vector-element}\label{reference_elements:vectorelement}
+Vectors are arrays of data, defined over any subset of the transverse dimensions defined in your {\hyperref[reference_elements:geometryelement]{\emph{Geometry Element}}}.  These dimensions are listed in the attribute \code{dimensions}, which can be an empty string if you wish the vector to not be defined on any dimensions.  If you do not include a \code{dimensions} attribute then the vector defaults to being a function of all transverse dimensions, not including any aliases.  Vectors are [...]
+
+Each \code{\textless{}vector\textgreater{}} element has a unique name, defined by a \code{name} attribute.  It is either complex-valued (the default) or real-valued, which can be specified using the \code{type="real"} attribute.
+\phantomsection\label{reference_elements:componentselement}
+A vector contains a list of variables, each defined by name in the \code{\textless{}components\textgreater{}} element.  The name of each component is the name used to reference it later in the simulation.
+
+Vectors are initialised at the beginning of a simulation, either from code or from an input file.  The basis choice for this initialisation defaults to the normal space as defined in the \code{\textless{}geometry\textgreater{}} element, but any transverse dimension can be initialised in their transform basis by specifying them in an \code{initial\_basis} attribute.  The \code{initial\_basis} attribute lists dimensions either by their name as defined by the \code{\textless{}geometry\textg [...]
+\phantomsection\label{reference_elements:initialisationelement}
+When initialising the vector within the XMDS script, the appropriate code is placed in a `CDATA' block inside an \code{\textless{}initialisation\textgreater{}} element.  This code is in standard C-syntax, and should reference the components of the vector by name.  XMDS defines a few useful {\hyperref[reference_elements:xmdscsyntax]{\emph{shorthand macros}}} for this C-code.  If you wish to initialise all the components of the vector as zeros, then it suffices simply to add the attribute  [...]
+\phantomsection\label{reference_elements:referencingnonlocal}
+While the default XMDS behaviour is to reference all variables locally, any vector can be referenced non-locally.  The notation for referencing the value of a vector `phi' with a dimension `j' at a value of `j=jk' is \code{phi(j =\textgreater{} jk)}.  Multiple non-local dimensions are addressed by adding the references in a list, e.g. \code{phi(j =\textgreater{} jk, x =\textgreater{} y)}.  See \code{2DMultistateSE.xmds} for an example.
+
+Dimensions can only be accessed non-locally if one of the following conditions is true:
+\begin{itemize}
+\item {} 
+The dimension is an \code{integer} dimension,
+
+\item {} 
+The dimension is accessed with an {\hyperref[advanced_topics:dimensionaliases]{\emph{alias}}} of that dimension. For example, \code{phi(x =\textgreater{} y)} if the dimension \code{x} has \code{y} as an alias, or vice-versa.
+
+\item {} 
+The dimension is a Fourier transform dimension (\code{dft}), used in the spectral basis (i.e. \code{kx} for an \code{x} dimension) and it is accessed with the negative of that dimension.  For example \code{phi(kx =\textgreater{} -kx)}.
+
+\item {} 
+The dimension is uniformly spaced (i.e. corresponds to the spatial basis of a dimension with a transform of \code{dft}, \code{dct}, \code{dst} or \code{none}), the dimension is symmetric about zero and it is accessed with the negative of the dimension name.  For example \code{phi(x =\textgreater{} -x)} for a dimension with domain of \code{(-1.2, 1.2)}.
+
+\item {} 
+The dimension is uniformly spaced (i.e. corresponds to the spatial basis of a dimension with a transform of \code{dft}, \code{dct}, \code{dst} or \code{none}), and it is accessed with the lower limit of that dimension.  For example, \code{phi(x =\textgreater{} -1.2)} for a dimension with a domain of \code{(-1.2, 1.2)}.  Note that the dimension must be accessed with the exact characters used in the definition of the domain.  For the previous example \code{phi(x =\textgreater{} -1.20)} doe [...]
+
+\item {} 
+\textbf{Advanced behaviour}: The value of a variable at an arbitrary point can be accessed via the integer index for that dimension. For example \code{phi(x\_index =\textgreater{} 3)} accesses the value of \code{phi} at the grid point with index 3.  As \code{x\_index} is zero-based, this will be the \emph{fourth} grid point.  It is highly recommended that the {\hyperref[reference_elements:diagnostics]{\emph{diagnostics}}} feature be used when writing simulations using this feature.  Once [...]
+
+\end{itemize}
+
+Note that a dimension cannot be accessed non-locally in \code{distributed-mpi} simulations if the simulation is distributed across that dimension.
+\phantomsection\label{reference_elements:filenameelement}
+If you wish to initialise from a file, then you can choose to initialise from an hdf5 file using \code{kind="hdf5"} in the \code{\textless{}initialisation\textgreater{}} element, and then supply the name of the input file with the \code{filename} element.  This is a standard data format which can be generated from XMDS, or from another program.  An example for generating a file in another program for input into XMDS is detailed in the Advanced topic: {\hyperref[advanced_topics:importing] [...]
+
+When initialising from a file, the default is to require the lattice of the transverse dimensions to exactly match the lattice defined by XMDS.  There is an option to import data defined on a subset or superset of the lattice points.  Obviously, the dimensionality of the imported field still has to be correct.  This option is activated by defining the attribute \code{geometry\_matching\_mode="loose"}.  The default option is defined as \code{geometry\_matching\_mode="strict"}.  A requirem [...]
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+            \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}128\PYGZdq{}} \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(\PYGZhy{}1, 1)\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+
+    \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ A one}\PYG{c}{\PYGZhy{}}\PYG{c}{dimensional vector with dimension \PYGZsq{}x\PYGZsq{} }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}wavefunction\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}basis=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}complex\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} phi \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+            \PYG{c+cp}{\PYGZlt{}![CDATA[}
+                \PYG{c+c1}{// \PYGZsq{}cis(x)\PYGZsq{} is cos(x) + i * sin(x)}
+                \PYG{n}{phi} \PYG{o}{=} \PYG{n}{exp}\PYG{p}{(}\PYG{o}{\PYGZhy{}}\PYG{l+m+mf}{0.5} \PYG{o}{*} \PYG{n}{x} \PYG{o}{*} \PYG{n}{x}\PYG{p}{)} \PYG{o}{*} \PYG{n}{cis}\PYG{p}{(}\PYG{l+m+mi}{40} \PYG{o}{*} \PYG{n}{x}\PYG{p}{)}\PYG{p}{;}
+            \PYG{c+cp}{]]\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+
+    \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ A zero}\PYG{c}{\PYGZhy{}}\PYG{c}{dimensional real vector with components u and v }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}zero\PYGZus{}dim\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}
+            u v
+        \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}initialisation} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}hdf5\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+            \PYG{n+nt}{\PYGZlt{}filename}\PYG{n+nt}{\PYGZgt{}}data.h5\PYG{n+nt}{\PYGZlt{}/filename\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{The dependencies element}
+\label{reference_elements:the-dependencies-element}\label{reference_elements:dependencies}
+Often a vector, computed vector, filter, integration operator or output group will reference the values in one or more other vectors, computed vectors or noise vectors.  These dependencies are defined via a \code{\textless{}dependencies\textgreater{}} element, which lists the names of the vectors.  The components of those vectors will then be available for use in the `CDATA' block, and can be referenced by their name.
+
+For a vector, the basis of the dependent vectors, and therefore the basis of the dimensions available in the `CDATA' block, are defined by the \code{initial\_basis} of the vector.  For a \code{\textless{}computed\_vector\textgreater{}}, \code{\textless{}filter\textgreater{}} \code{\textless{}integration\_vector\textgreater{}}, or moment group vector, the basis of the dependencies can be specified by a \code{basis} attribute in the \code{\textless{}dependencies\textgreater{}} element.  Fo [...]
+
+Any transverse dimensions that appear in the \code{\textless{}dependencies\textgreater{}} element that do not appear in the \code{dimensions} attribute of the vector are integrated out.  For integer dimensions, this is simply an implicit sum over the dimension.  For real-valued dimensions, this is an implicit integral over the range of that dimension.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+            \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}128\PYGZdq{}} \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(\PYGZhy{}1, 1)\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+            \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}y\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}10\PYGZdq{}} \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(\PYGZhy{}3, 2)\PYGZdq{}} \PYG{n+na}{transform=}\PYG{l+s}{\PYGZdq{}dct\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+
+    \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ A one}\PYG{c}{\PYGZhy{}}\PYG{c}{dimensional vector with dimension \PYGZsq{}x\PYGZsq{} }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}wavefunction\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}basis=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}complex\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} phi \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+            \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}
+\PYG{c}{                The initialisation of the vector \PYGZsq{}wavefunction\PYGZsq{} depends on information}
+\PYG{c}{                in the \PYGZsq{}two\PYGZus{}dim\PYGZsq{} vector.  The vector two\PYGZus{}dim is DCT}\PYG{c}{\PYGZhy{}}\PYG{c}{transformed into the}
+\PYG{c}{                (x, ky) basis, and the ky dimension is implicitly integrated over in the}
+\PYG{c}{                following initialisation code}
+\PYG{c}{              }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+            \PYG{n+nt}{\PYGZlt{}dependencies} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}x ky\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}two\PYGZus{}dim\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+            \PYG{c+cp}{\PYGZlt{}![CDATA[}
+                \PYG{c+c1}{// \PYGZsq{}cis(x)\PYGZsq{} is cos(x) + i * sin(x)}
+                \PYG{n}{phi} \PYG{o}{=} \PYG{n}{exp}\PYG{p}{(}\PYG{o}{\PYGZhy{}}\PYG{l+m+mf}{0.5} \PYG{o}{*} \PYG{n}{x} \PYG{o}{*} \PYG{n}{x} \PYG{o}{+} \PYG{n}{v}\PYG{p}{)} \PYG{o}{*} \PYG{n}{cis}\PYG{p}{(}\PYG{n}{u} \PYG{o}{*} \PYG{n}{x}\PYG{p}{)}\PYG{p}{;}
+            \PYG{c+cp}{]]\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+
+    \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ A two}\PYG{c}{\PYGZhy{}}\PYG{c}{dimensional real vector with components u and v }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}two\PYGZus{}dim\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}
+            u v
+        \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}initialisation} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}hdf5\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+            \PYG{n+nt}{\PYGZlt{}filename}\PYG{n+nt}{\PYGZgt{}}data.h5\PYG{n+nt}{\PYGZlt{}/filename\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsection{Computed Vector Element}
+\label{reference_elements:computedvectorelement}\label{reference_elements:computed-vector-element}\phantomsection\label{reference_elements:evaluationelement}
+Computed vectors are arrays of data much like normal \code{\textless{}vector\textgreater{}} elements, but they are always calculated as they are referenced, so they cannot be initialised from file.  It is defined with a \code{\textless{}computed\_vector\textgreater{}} element, which has a \code{name} attribute, optional \code{dimensions} and \code{type} attributes, and a \code{\textless{}components\textgreater{}} element, just like a \code{\textless{}vector\textgreater{}} element.  Inste [...]
+
+As it is not being stored, a \code{\textless{}computed\_vector\textgreater{}} does not have or require an \code{initial\_basis} attribute, as it will be transformed into an appropriate basis for the element that references it.  The basis for its evaluation will be determined entirely by the \code{basis} attribute of the \code{\textless{}dependencies\textgreater{}} element.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+            \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}128\PYGZdq{}} \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(\PYGZhy{}1, 1)\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+
+    \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ A one}\PYG{c}{\PYGZhy{}}\PYG{c}{dimensional vector with dimension \PYGZsq{}x\PYGZsq{} }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}wavefunction\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}complex\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} phi \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+            \PYG{c+cp}{\PYGZlt{}![CDATA[}
+                \PYG{c+c1}{// \PYGZsq{}cis(x)\PYGZsq{} is cos(x) + i * sin(x)}
+                \PYG{n}{phi} \PYG{o}{=} \PYG{n}{exp}\PYG{p}{(}\PYG{o}{\PYGZhy{}}\PYG{l+m+mf}{0.5} \PYG{o}{*} \PYG{n}{x} \PYG{o}{*} \PYG{n}{x}\PYG{p}{)} \PYG{o}{*} \PYG{n}{cis}\PYG{p}{(}\PYG{l+m+mi}{40} \PYG{o}{*} \PYG{n}{x}\PYG{p}{)}\PYG{p}{;}
+            \PYG{c+cp}{]]\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+
+    \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ A zero}\PYG{c}{\PYGZhy{}}\PYG{c}{dimensional real computed vector with components Ncalc }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}computed\PYGZus{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}zero\PYGZus{}dim\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}
+            Ncalc
+        \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}evaluation}\PYG{n+nt}{\PYGZgt{}}
+            \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+            \PYG{c+cp}{\PYGZlt{}![CDATA[}
+                \PYG{c+c1}{// Implicitly integrating over the dimension \PYGZsq{}x\PYGZsq{}}
+                \PYG{n}{Ncalc} \PYG{o}{=} \PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{p}{;}
+            \PYG{c+cp}{]]\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/evaluation\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/computed\PYGZus{}vector\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsection{Noise Vector Element}
+\label{reference_elements:noise-vector-element}\label{reference_elements:noisevectorelement}
+Noise vectors are used like computed vectors, but when they are evaluated they generate arrays of random numbers of various kinds.  They do not depend on other vectors, and are not initialised by code.  They are defined by a \code{\textless{}noise\_vector\textgreater{}} element, which has a \code{name} attribute, and optional \code{dimensions}, \code{initial\_basis} and \code{type} attributes, which work identically as for normal vectors.
+
+The choice of pseudo-random number generator (RNG) can be specified with the \code{method} attribute, which has options ``posix'' (the default), ``mkl'', ``solirte'' and ``dsfmt''.  It is only possible to use any particular method if that library is available.  Although ``posix'' is the default, it is also the slowest, and produces the lowest quality random numbers (although this is typically not a problem).  ``mkl'' refers to the Intel Math Kernel Library, and is only available if insta [...]
+
+The random number generators can be provided with a seed using the \code{seed} attribute, which should typically consist of a list of three integers.  All RNGs require positive integers as seeds.  It is possible to use the {\hyperref[reference_elements:validation]{\emph{\textless{}validation kind=''run-time''/\textgreater{}}}} feature to use passed variables as seeds.  It is advantageous to use fixed seeds rather than timer-based seeds, as the {\hyperref[reference_elements:errorcheck]{\e [...]
+
+The different types of noise vectors are defined by a mandatory \code{kind} attribute, which must take the value of `gauss', `gaussian', `wiener', `poissonian','jump' or `uniform'.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+            \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}128\PYGZdq{}} \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(\PYGZhy{}1, 1)\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+
+    \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}
+\PYG{c}{        A one}\PYG{c}{\PYGZhy{}}\PYG{c}{dimensional complex wiener noise vector.}
+\PYG{c}{        This noise is appropriate for using in the complex}
+\PYG{c}{        random}\PYG{c}{\PYGZhy{}}\PYG{c}{walk equation of motion:}
+\PYG{c}{            dz\PYGZus{}dt = eta;}
+\PYG{c}{    }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}noise\PYGZus{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}noise\PYGZdq{}} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}wiener\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}
+            eta
+        \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{Uniform noise}
+\label{reference_elements:uniformnoise}\label{reference_elements:uniform-noise}
+Uniform noises defined over any transverse dimensions are simply uniformly distributed random numbers between zero and one.  This noise is an example of a ``static'' noise, i.e. one suitable for initial conditions of a field.  If it were included in the equations of motion for a field, then the effect of the noise would depend on the lattice spacing of the propagation dimension.  XMDS therefore does not allow this noise type to be used in integration elements.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}noise\PYGZus{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}drivingNoise\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}uniform\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}complex\PYGZdq{}} \PYG{n+na}{method=}\PYG{l+s}{\PYGZdq{}dsfmt\PYGZdq{}} \PYG{n+na}{seed=}\PYG{l+s}{\PYGZdq{}314 159 276\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}Eta\PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/noise\PYGZus{}vector\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{Gaussian noise}
+\label{reference_elements:gaussiannoise}\label{reference_elements:gaussian-noise}
+Noise generated with the ``gaussian'' method is gaussian distributed with zero mean.  For a real-valued noise vector, the variance at each point is the inverse of the volume element of the transverse dimensions in the vector.  This volume element for a single transverse dimension is that used to perform integrals over that dimension.  For example, it would include a factor of $r^2$ for a dimension ``r'' defined with a \code{spherical-bessel} transform.  It can be non-uniform for dimensio [...]
+
+This lattice-dependent variance is typical in most applications of partial differential equations with stochastic initial conditions, as the physical quantity is the variance of the field over some finite volume, which does not change if the variance at each lattice site varies as described above.
+
+For complex-valued noise vector, the real and imaginary parts of the noise are independent, and each have half the variance of a real-valued noise.  This means that the modulus squared of a complex-valued noise vector has the same variance as a real-valued noise vector at each point.
+
+Gaussian noise vectors are an example of a ``static'' noise, i.e. one suitable for initial conditions of a field.  If they were included in the equations of motion for a field, then the effect of the noise would depend on the lattice spacing of the propagation dimension.  XMDS therefore does not allow this noise type to be used in integration elements.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}noise\PYGZus{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}initialNoise\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}gauss\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{method=}\PYG{l+s}{\PYGZdq{}posix\PYGZdq{}} \PYG{n+na}{seed=}\PYG{l+s}{\PYGZdq{}314 159 276\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}fuzz\PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/noise\PYGZus{}vector\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{Wiener noise}
+\label{reference_elements:wienernoise}\label{reference_elements:wiener-noise}
+Noise generated with the ``wiener'' method is gaussian distributed with zero mean and the same variance as the static ``gaussian'' noise defined above, multiplied by a factor of the lattice step in the propagation dimension.  This means that these noise vectors can be used to define Wiener noises for standard stochastic ordinary or partial differential equations.  Most integrators in XMDS effectively interpret these noises as Stratonovich increments.
+
+As a dynamic noise, a Wiener process is not well-defined except in an \code{integrate} element.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}noise\PYGZus{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}diffusion\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}wiener\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{method=}\PYG{l+s}{\PYGZdq{}solirte\PYGZdq{}} \PYG{n+na}{seed=}\PYG{l+s}{\PYGZdq{}314 159 276\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}dW\PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/noise\PYGZus{}vector\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{Poissonian noise}
+\label{reference_elements:poissioniannoise}\label{reference_elements:poissonian-noise}
+A noise vector using the ``poissonian'' method generates a random variable from a Poissonian distribution.  While the the Poisson distribution is integer-valued, the variable will be cast as a real number.  The rate of the Poissonian distribution is defined by the \code{mean} or \code{mean-density} attributes.  These are are synonyms, and must be defined as positive real numbers.  For Poissonian noises defined over real-valued transverse dimensions, the rate is given by the product of th [...]
+
+Poissonian noise vectors are an example of a ``static'' noise, i.e. one suitable for initial conditions of a field.  If they were included in the equations of motion for a field, then the effect of the noise would depend on the lattice spacing of the propagation dimension.  XMDS therefore does not allow this noise type to be used in integration elements.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}noise\PYGZus{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}initialDistribution\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}poissonian\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{mean\PYGZhy{}density=}\PYG{l+s}{\PYGZdq{}2.7\PYGZdq{}} \PYG{n+na}{method=}\PYG{l+s}{\PYGZdq{}solirte\PYGZdq{}} \PYG{n+na}{seed=}\PYG{l+s}{\PYGZdq{}314 159 276\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}Pdist\PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/noise\PYGZus{}vector\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{Jump noise}
+\label{reference_elements:jumpnoise}\label{reference_elements:jump-noise}
+A noise vector using the ``jump'' method is the dynamic version of the poissonian noise method, and must have the \code{mean-rate} attribute specified as a positive real number.  The variable at each point is chosen from a Poissonian distribution with a mean equal to the product of three variables: the \code{mean-rate} attribute; the volume of the element as defined by its transverse dimensions (including their \code{volume\_prefactor} attributes); and the step size in the propagation di [...]
+
+It is common to wish to vary the mean rate of a jump process, which means that the \code{mean-rate} attribute must be a variable or a piece of code.  These cannot be verified to be a positive real number at compile time, so they must be used with the {\hyperref[reference_elements:validation]{\emph{\textless{}validation\textgreater{}}}} feature with either the \code{kind="none"} or \code{kind="run-time"} attributes.
+
+As a dynamic noise, a jump process is not well-defined except in an \code{integrate} element.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}noise\PYGZus{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}initialDistribution\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}\PYGZdq{}} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}jump\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{mean\PYGZhy{}rate=}\PYG{l+s}{\PYGZdq{}2.7\PYGZdq{}} \PYG{n+na}{method=}\PYG{l+s}{\PYGZdq{}solirte\PYGZdq{}} \PYG{n+na}{seed=}\PYG{l+s}{\PYGZdq{}314 159 276\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}dN\PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/noise\PYGZus{}vector\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsection{Sequence Element}
+\label{reference_elements:sequence-element}\label{reference_elements:sequenceelement}
+All processing of vectors happens in sequence elements.  Each simulation must have exactly one main sequence element, but it can then contain any number of nested sequence elements.  A sequence element can contain any number of \code{\textless{}sequence\textgreater{}}, {\hyperref[reference_elements:filterelement]{\emph{\textless{}filter\textgreater{}}}}, {\hyperref[reference_elements:integrateelement]{\emph{\textless{}integrate\textgreater{}}}} and/or {\hyperref[reference_elements:breakp [...]
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}sequence} \PYG{n+na}{cycles=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}sequence}\PYG{n+nt}{\PYGZgt{}}  ... \PYG{n+nt}{\PYGZlt{}/sequence\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}filter}\PYG{n+nt}{\PYGZgt{}} ... \PYG{n+nt}{\PYGZlt{}/filter\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}integrate}\PYG{n+nt}{\PYGZgt{}} ...\PYG{n+nt}{\PYGZlt{}/integrate\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/sequence\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsection{Filter element}
+\label{reference_elements:filterelement}\label{reference_elements:filter-element}
+A \code{\textless{}filter\textgreater{}} element can be placed inside a \code{\textless{}sequence\textgreater{}} element or an {\hyperref[reference_elements:integrateelement]{\emph{\textless{}integrate\textgreater{}}}} element.  It contains a `CDATA' block and an optional {\hyperref[reference_elements:dependencies]{\emph{\textless{}dependencies\textgreater{}}}} element, which may give access to variables in other \code{\textless{}vector\textgreater{}}, \code{\textless{}computed\_vector\t [...]
+
+Sometimes it is desirable to apply a filter conditionally.  The most efficient way of doing this is to call the function from the piece of code that contains the conditional statement (likely another \code{\textless{}filter\textgreater{}} element) rather than embed the conditional function in the filter itself, as the latter method can involve the conditional statement being evaluated multiple times over the transverse dimensions.  For this reason, it is possible to give a filter a \code [...]
+
+One of the common uses of a filter element is to apply discontinuous changes to the vectors and variables of the simulation.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}sequence}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}filter}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{printf}\PYG{p}{(}\PYG{l+s}{\PYGZdq{}}\PYG{l+s}{Hello world from the first filter segment!  This filter rather wastefully calls the second one.}\PYG{l+s+se}{\PYGZbs{}n}\PYG{l+s}{\PYGZdq{}}\PYG{p}{)}\PYG{p}{;}
+        \PYG{n}{fname}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/filter\PYGZgt{}}
+
+    \PYG{n+nt}{\PYGZlt{}filter} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}fname\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+       \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}normalisation wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+       \PYG{c+cp}{\PYGZlt{}![CDATA[}
+         \PYG{n}{phi} \PYG{o}{*}\PYG{o}{=} \PYG{n}{sqrt}\PYG{p}{(}\PYG{n}{Nparticles}\PYG{o}{/}\PYG{n}{Ncalc}\PYG{p}{)}\PYG{p}{;}
+       \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/filter\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/sequence\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsection{Integrate element}
+\label{reference_elements:integrate-element}\label{reference_elements:integrateelement}
+The \code{\textless{}integrate\textgreater{}} element is at the heart of most XMDS simulations.  It is used to integrate a set of (potentially stochastic) first-order differential equations for one or more of the vectors defined using the \code{\textless{}vector\textgreater{}} element along the propagation dimension.  At the beginning of the simulation, the value of the propagation dimension is set to zero, and the vectors are initialised as defined in the {\hyperref[reference_elements:v [...]
+
+The length of the integration is defined by the \code{interval} attribute, which must be a positive real number.  An \code{\textless{}integrate\textgreater{}} element must have an \code{algorithm} attribute defined, which defines the integration method.  Current methods include {\hyperref[reference_elements:si]{\emph{SI}}}, {\hyperref[reference_elements:si]{\emph{SIC}}}, {\hyperref[reference_elements:rk4]{\emph{RK4}}}, {\hyperref[reference_elements:rk4]{\emph{RK9}}}, {\hyperref[reference [...]
+\phantomsection\label{reference_elements:sampleselement}
+The optional \code{\textless{}samples\textgreater{}} element is used to track the evolution of one or more vectors or variables during an integration.  This element must contain a non-negative integer for each {\hyperref[reference_elements:samplinggroupelement]{\emph{\textless{}sampling\_group\textgreater{}}}} element defined in the simulation's {\hyperref[reference_elements:outputelement]{\emph{\textless{}output\textgreater{}}}} element.  The list of integers then defines the number of  [...]
+
+The vectors to be integrated and the form of the differential equations are defined in the {\hyperref[reference_elements:operatorselement]{\emph{\textless{}operators\textgreater{}}}} element (or elements).  Filters to be applied each step can be defined with optional {\hyperref[reference_elements:filterselement]{\emph{\textless{}filters\textgreater{}}}} elements.
+
+Computed vectors can be defined with the \code{\textless{}computed\_vector\textgreater{}} element.  These act exactly like a globally defined {\hyperref[reference_elements:computedvectorelement]{\emph{Computed Vector Element}}}, but are only available within the single \code{\textless{}integrate\textgreater{}} element.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}integrate} \PYG{n+na}{algorithm=}\PYG{l+s}{\PYGZdq{}ARK89\PYGZdq{}} \PYG{n+na}{interval=}\PYG{l+s}{\PYGZdq{}1e\PYGZhy{}4\PYGZdq{}} \PYG{n+na}{steps=}\PYG{l+s}{\PYGZdq{}10000\PYGZdq{}} \PYG{n+na}{tolerance=}\PYG{l+s}{\PYGZdq{}1e\PYGZhy{}8\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}samples}\PYG{n+nt}{\PYGZgt{}}20\PYG{n+nt}{\PYGZlt{}/samples\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}filters}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}filter}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}wavefunction normalisation\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{phi} \PYG{o}{*}\PYG{o}{=} \PYG{n}{sqrt}\PYG{p}{(}\PYG{n}{Nparticles}\PYG{o}{/}\PYG{n}{Ncalc}\PYG{p}{)}\PYG{p}{;}   \PYG{c+c1}{// Correct normalisation of the wavefunction}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/filter\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/filters\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}operators}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}operator} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}ip\PYGZdq{}} \PYG{n+na}{constant=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}operator\PYGZus{}names}\PYG{n+nt}{\PYGZgt{}}T\PYG{n+nt}{\PYGZlt{}/operator\PYGZus{}names\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{T} \PYG{o}{=} \PYG{o}{\PYGZhy{}}\PYG{l+m+mf}{0.5}\PYG{o}{*}\PYG{n}{hbar}\PYG{o}{/}\PYG{n}{M}\PYG{o}{*}\PYG{n}{ky}\PYG{o}{*}\PYG{n}{ky}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/operator\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}potential\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+    \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{n}{dphi\PYGZus{}dt} \PYG{o}{=} \PYG{n}{T}\PYG{p}{[}\PYG{n}{phi}\PYG{p}{]} \PYG{o}{\PYGZhy{}} \PYG{p}{(}\PYG{n}{V1} \PYG{o}{+} \PYG{n}{Uint}\PYG{o}{/}\PYG{n}{hbar}\PYG{o}{*}\PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{phi}\PYG{p}{)}\PYG{p}{)}\PYG{o}{*}\PYG{n}{phi}\PYG{p}{;}
+    \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}integration\PYGZus{}vectors}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/integration\PYGZus{}vectors\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/operators\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/integrate\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{Operators and operator elements}
+\label{reference_elements:operatorselement}\label{reference_elements:operators-and-operator-elements}
+An {\hyperref[reference_elements:integrateelement]{\emph{\textless{}integrate\textgreater{}}}} element must contain one or more \code{\textless{}operators\textgreater{}} elements, which define both which vectors are to be integrated, and their derivative in the propagation dimension.  When all vectors to be integrated have the same dimensionality, they can all be defined within a single \code{\textless{}operators\textgreater{}} element, and when vectors with different dimension are to be [...]
+\phantomsection\label{reference_elements:integrationvectorselement}
+Within each \code{\textless{}operators\textgreater{}} element, the vectors that are to be integrated are listed by name in the \code{\textless{}integration\_vectors\textgreater{}} element, and the differential equations are written in a `CDATA' block.   The derivative of each component of the integration vectors must be defined along the propagation dimension.  For example, if the integration vectors have components `phi' and `beta', and the propagation dimension is labelled `tau', then  [...]
+
+When noise vectors are referenced, equations with Wiener noises should be written as though the equations are in differential form, as described in the worked examples {\hyperref[worked_examples:kubo]{\emph{Kubo Oscillator}}} and {\hyperref[worked_examples:fibre]{\emph{Fibre Noise}}}.  Jump-based Poisson noises will also be written in an equivalent form, as modelled by the example \code{photodetector.xmds}.
+
+By default, the name of each component references the local value of the vector, but {\hyperref[reference_elements:referencingnonlocal]{\emph{nonlocal variables}}} can be accessed using the standard syntax.  However, typically the most common (and most efficient) method of referencing nonlocal variables is to reference variables that are local in the {\hyperref[reference_elements:transforms]{\emph{transformed space}}} for a given transverse dimension.  This is done using \code{\textless{ [...]
+\phantomsection\label{reference_elements:operatorelement}
+There are three kinds of \code{\textless{}operator\textgreater{}} elements.  The first is denoted with a \code{kind="functions"} attribute, and contains a `CDATA' block that will be executed in the order that it is defined.  This is useful when you wish to calculate functions that do not depend on the transverse dimensions.  Defining these along with the main equations of motion causes them to be recalculated separately for each point.  The second kind of \code{\textless{}operator\textgr [...]
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}operator} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}functions\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{c+cp}{\PYGZlt{}![CDATA[}
+  \PYG{n}{f} \PYG{o}{=} \PYG{n}{cos}\PYG{p}{(}\PYG{n}{t}\PYG{p}{)}\PYG{p}{;}
+  \PYG{c+cp}{]]\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/operator\PYGZgt{}}
+\end{Verbatim}
+\phantomsection\label{reference_elements:operatornameselement}
+The second kind of operator element defines a list of operators in an \code{\textless{}operator\_names\textgreater{}} element.  The basis of these operators defaults to the transform space unless a different basis is specified using the \code{basis} attribute.  These operators must then be defined in a `CDATA' block, using any {\hyperref[reference_elements:dependencies]{\emph{dependencies}}} as normal.  If the operators constant across the integration, then the attribute \code{constant=" [...]
+
+Operators of this second kind have the \code{kind="IP"} or \code{kind="EX"} attribute, standing for `interaction picture' and `explicit' operators respectively.  Explicit operators can be used in all situations, and simply construct and calculate a new vector of the form in the square brackets.  IP operators use less memory and can improve speed by allowing larger timesteps, but have two important restrictions.  \textbf{Use of IP operators without understanding these restrictions can lea [...]
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}operator} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}ex\PYGZdq{}} \PYG{n+na}{constant=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}operator\PYGZus{}names}\PYG{n+nt}{\PYGZgt{}}T\PYG{n+nt}{\PYGZlt{}/operator\PYGZus{}names\PYGZgt{}}
+  \PYG{c+cp}{\PYGZlt{}![CDATA[}
+    \PYG{n}{T} \PYG{o}{=} \PYG{o}{\PYGZhy{}}\PYG{l+m+mf}{0.5}\PYG{o}{*}\PYG{n}{hbar}\PYG{o}{/}\PYG{n}{M}\PYG{o}{*}\PYG{n}{ky}\PYG{o}{*}\PYG{n}{ky}\PYG{p}{;}
+  \PYG{c+cp}{]]\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/operator\PYGZgt{}}
+\end{Verbatim}
+
+The third kind of operator element is used to define an integration along a transverse dimension.  This kind of evolution is called ``cross-propagation'', and is described briefly in the examples `tla.xmds', `tla\_sic.xmds' and `sine\_cross.xmds'.  This class of equations have a subset of vectors that have an initial condition on one side of a transverse dimension, and a differential equation defined in that dimension, and as such, this kind of operator element has much of the structure  [...]
+
+An operator element with the \code{kind="cross\_propagation"} attribute must specify the transverse dimension along which the integration would proceed with the \code{propagation\_dimension} attribute.  It must also specify its own {\hyperref[reference_elements:integrationvectorselement]{\emph{\textless{}integration\_vectors\textgreater{}}}} element, its own \code{\textless{}operators\textgreater{}} elements (of the second kind), and may define an optional {\hyperref[reference_elements:d [...]
+\phantomsection\label{reference_elements:boundaryconditionelement}
+The boundary conditions are specified by a \code{\textless{}boundary\_conditions\textgreater{}} element, which requires the \code{kind="left"} or \code{kind="right"} attribute to specify on which side of the grid that the boundary conditions are specified.  The boundary conditions for the \code{\textless{}integration\_vectors\textgreater{}} are then specified in a `CDATA' block, which may refer to vectors in an optional {\hyperref[reference_elements:dependencies]{\emph{\textless{}depende [...]
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}operator} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}cross\PYGZus{}propagation\PYGZdq{}} \PYG{n+na}{algorithm=}\PYG{l+s}{\PYGZdq{}RK4\PYGZdq{}} \PYG{n+na}{propagation\PYGZus{}dimension=}\PYG{l+s}{\PYGZdq{}t\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}integration\PYGZus{}vectors}\PYG{n+nt}{\PYGZgt{}}cross\PYG{n+nt}{\PYGZlt{}/integration\PYGZus{}vectors\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}constants\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}boundary\PYGZus{}condition} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}left\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{n}{v} \PYG{o}{=} \PYG{l+m+mf}{1.0}\PYG{p}{;}
+      \PYG{n}{w} \PYG{o}{=} \PYG{l+m+mf}{1.0}\PYG{p}{;}
+    \PYG{c+cp}{]]\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/boundary\PYGZus{}condition\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}operator} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}ip\PYGZdq{}} \PYG{n+na}{constant=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}operator\PYGZus{}names}\PYG{n+nt}{\PYGZgt{}}L\PYG{n+nt}{\PYGZlt{}/operator\PYGZus{}names\PYGZgt{}}
+    \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{n}{L} \PYG{o}{=} \PYG{k+kc}{i}\PYG{p}{;}
+    \PYG{c+cp}{]]\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/operator\PYGZgt{}}
+
+  \PYG{c+cp}{\PYGZlt{}![CDATA[}
+    \PYG{n}{dv\PYGZus{}dt} \PYG{o}{=} \PYG{k+kc}{i}\PYG{o}{*}\PYG{n}{v}\PYG{p}{;}
+    \PYG{n}{dw\PYGZus{}dt} \PYG{o}{=} \PYG{n}{L}\PYG{p}{[}\PYG{n}{w}\PYG{p}{]}\PYG{p}{;}
+  \PYG{c+cp}{]]\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/operator\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsubsection{Algorithms}
+\label{reference_elements:algorithms}\label{reference_elements:id8}
+The stability, efficiency and even convergence of a numerical integration can depend on the method.  Due to the varying properties of different sets of equations, it is impossible to define the best method for all equations, so XMDS provides an option to use different algorithms.  These include fixed step algorithms, which divide the integration region into equal steps, and adaptive stepsize algorithms, which attempt to estimate the error in the simulation in order to choose an appropria [...]
+
+For the purposes of the descriptions below, we will assume that we are considering the following set of coupled differential equations for the vector of variables $\mathbf{x}(t)$:
+\begin{gather}
+\begin{split}\frac{d x_j}{dt} = f_j(\mathbf{x}(t),t)\end{split}\notag
+\end{gather}
+
+\paragraph{SI and SIC algorithms}
+\label{reference_elements:si}\label{reference_elements:si-and-sic-algorithms}
+The SI algorithm is a semi-implicit fixed-step algorithm that finds the increment of the vector by solving
+\begin{gather}
+\begin{split}x_j(t+\Delta t) = x_j(t) + f_j\left(\mathbf{x}(t+\frac{\Delta t}{2}),t+\frac{\Delta t}{2}\right) \;\Delta t\end{split}\notag
+\end{gather}
+using a simple iteration to find the values of the vector at the midpoint of the step self-consistently.  The number of iterations can be set using the \code{iterations} attribute, and it defaults to \code{iterations="3"}.  The choice of \code{iterations="1"} is therefore fully equivalent to the Euler algorithm, where
+\begin{gather}
+\begin{split}x_j(t+\Delta t) = x_j(t) + f_j\left(\mathbf{x}(t),t\right) \;\Delta t.\end{split}\notag
+\end{gather}
+The Euler algorithm is the only safe algorithm for direct integration of {\hyperref[reference_elements:jumpnoise]{\emph{jump-based Poisson processes}}}.  Efficient numerical solution of those types of equations is best done via a process of triggered filters, which will be described in the {\hyperref[advanced_topics:advancedtopics]{\emph{Advanced Topics}}} section.  Integrating using the Euler algorithm computes the Ito integral, as opposed to the Stratonovich integral, which all the oth [...]
+
+When SI integration is used in conjunction with SI cross-propagation, a slight variant of the SI algorithm can be employed where the integration in both directions is contained within the iteration process.  This is activated by using \code{algorithm="SIC"} rather than \code{algorithm="SI"}.
+
+The SI algorithm is correct to second order in the step-size for deterministic equations, and first order in the step-size for Stratonovich stochastic equations with Wiener noises.  This makes it the highest order stochastic algorithm in XMDS, although there are many sets of equations that integrate more efficiently with lower order algorithms.  When called with the \code{iterations="1"} option (the Euler algorithm), it is correct to first order in the step-size for deterministic equatio [...]
+
+
+\paragraph{Runge-Kutta algorithms}
+\label{reference_elements:rk4}\label{reference_elements:runge-kutta-algorithms}
+Runge-Kutta algorithms are the workhorse of numerical integration, and XMDS employs two fixed step versions: \code{algorithm="RK4"}, which is correct to fourth-order in the step size, and \code{algorithm="RK9"}, which is correct to ninth order in the step size.  It must be strongly noted that a higher order of convergence does not automatically mean a superior algorithm.  RK9 requires several times the memory of the RK4 algorithm, and each step requires significantly more computation.
+
+All Runge-Kutta algorithms are convergent for Stratonovich stochastic equations at the order of the square root of the step-size.  This `half-order' convergence may seem very weak, but for some classes of stochastic equation this improves up to one half of the deterministic order of convergence.  Also, the convergence of some stochastic equations is limited by the `deterministic part', which can be improved dramatically by using a higher order Runge-Kutta method.
+
+
+\paragraph{Adaptive Runge-Kutta algorithms}
+\label{reference_elements:adaptive-runge-kutta-algorithms}\label{reference_elements:ark45}
+Fixed step integrators can encounter two issues.  First, as the equations or parameters of a simulation are changed, the minimum number of steps required to integrate it may change.  This means that the convergence must be re-tested multiple times for each set of parameters, as overestimating the number of steps required to perform an integration to a specified error tolerance can be very inefficient. Second, even if the minimum acceptable number of steps required is known for a given si [...]
+algorithms get around this problem by testing the convergence during the integration, and adjusting the step-size until it reaches some target tolerance.
+
+XMDS employs two adaptive step-size algorithms based on `embedded Runge-Kutta' methods.  These are Runge-Kutta methods that can output multiple variables that have different convergence.  The difference between the higher-order and the lower-order solutions gives an estimate of the error in each step, which can then be used to estimate an appropriate size for the next step.  We use \code{algorthim="ARK45"}, which contains fourth and fifth order solutions, and \code{algorthim=ARK89}, whic [...]
+
+All adaptive stepsize algorithms require a \code{tolerance} attribute, which must be a positive real number that defines the allowable error per step.  It is also possible to specify a \code{max\_iterations} attribute, which is a positive integer that stops the integrator from trying too many times to find an acceptable stepsize.  The integrator will abort with an error if the number of attempts for a single step exceeds the maximum specified with this attribute.
+
+As all Runge-Kutta solutions have equal order of convergence for stochastic equations, \emph{if the step-size is limited by the stochastic term then the step-size estimation is entirely unreliable}.  Adaptive Runge-Kutta algorithms are therefore not appropriate for stochastic equations.
+
+
+\subsubsection{Filters element}
+\label{reference_elements:filterselement}\label{reference_elements:filters-element}
+{\hyperref[reference_elements:filterelement]{\emph{Filter elements}}} are used inside {\hyperref[reference_elements:sequenceelement]{\emph{sequence elements}}} to execute arbitrary code, or make discontinuous changes in the vectors.  Sometimes it is desirable to perform a filter element at the beginning or end of each step in an integration.  This can be done by placing \code{\textless{}filter\textgreater{}} elements in a \code{\textless{}filters\textgreater{}} element within the \code{\ [...]
+is then executed in the order found in the \code{\textless{}filters\textgreater{}} element.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}integrate} \PYG{n+na}{algorithm=}\PYG{l+s}{\PYGZdq{}ARK45\PYGZdq{}} \PYG{n+na}{interval=}\PYG{l+s}{\PYGZdq{}100000.0\PYGZdq{}} \PYG{n+na}{steps=}\PYG{l+s}{\PYGZdq{}10000000\PYGZdq{}} \PYG{n+na}{tolerance=}\PYG{l+s}{\PYGZdq{}1e\PYGZhy{}8\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}samples}\PYG{n+nt}{\PYGZgt{}}5000 100\PYG{n+nt}{\PYGZlt{}/samples\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}filters} \PYG{n+na}{where=}\PYG{l+s}{\PYGZdq{}step end\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}filter}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}vector1 vector2\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+        \PYG{c+cp}{\PYGZlt{}![CDATA[}
+            \PYG{n}{x} \PYG{o}{=} \PYG{l+m+mi}{1}\PYG{p}{;}
+            \PYG{n}{y} \PYG{o}{*}\PYG{o}{=} \PYG{n}{ynorm}\PYG{p}{;}
+            \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/filter\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/filters\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}operators}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}integration\PYGZus{}vectors}\PYG{n+nt}{\PYGZgt{}}vector1\PYG{n+nt}{\PYGZlt{}/integration\PYGZus{}vectors\PYGZgt{}}
+    \PYG{c+cp}{\PYGZlt{}![CDATA[}
+    \PYG{n}{dx\PYGZus{}dt} \PYG{o}{=} \PYG{n}{alpha}\PYG{p}{;}
+    \PYG{n}{dy\PYGZus{}dt} \PYG{o}{=} \PYG{n}{beta}\PYG{o}{*}\PYG{n}{y}\PYG{p}{;}
+    \PYG{c+cp}{]]\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/operators\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/integrate\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsection{Breakpoint element}
+\label{reference_elements:breakpoint-element}\label{reference_elements:breakpointelement}
+The \code{\textless{}breakpoint\textgreater{}} element is used to output the full state of one or more vectors.  Unlike sampled output, it executes immediately rather than at the end of a program, and can therefore be used to examine the current state of an ongoing simulation.  The vectors to be output are defined via a {\hyperref[reference_elements:dependencies]{\emph{\textless{}dependencies\textgreater{}}}} element, and the basis is chosen by the \code{basis} attribute supplied to that [...]
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}breakpoint} \PYG{n+na}{filename=}\PYG{l+s}{\PYGZdq{}groundstate\PYGZus{}break.xsil\PYGZdq{}} \PYG{n+na}{format=}\PYG{l+s}{\PYGZdq{}hdf5\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}dependencies} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}ky\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/breakpoint\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsection{Output element}
+\label{reference_elements:outputelement}\label{reference_elements:output-element}
+The \code{\textless{}output\textgreater{}} element describes the output of the program.  It is often inefficient to output the complete state of all vectors at all times during a large simulation, so the purpose of this function is to define subsets of the information required for output.  Each different format of information is described in a different \code{\textless{}sampling\_group\textgreater{}} element inside the output element.  The \code{\textless{}output\textgreater{}} element m [...]
+
+The \code{\textless{}samples\textgreater{}} inside \code{\textless{}integrate\textgreater{}} elements defines a string of integers, with exactly one for each \code{\textless{}sampling\_group\textgreater{}} element.  During that integration, the variables described in each \code{\textless{}sampling\_group\textgreater{}} element will be sampled and stored that number of times.
+
+
+\subsubsection{Sampling Group Element}
+\label{reference_elements:samplinggroupelement}\label{reference_elements:sampling-group-element}
+A \code{\textless{}sampling\_group\textgreater{}} element defines a set of variables that we wish to output, typically they are functions of some subset of vectors.  The names of the desired variables are listed in a \code{\textless{}moments\textgreater{}} element, just like the \code{\textless{}components\textgreater{}} element of a vector.  They are defined with a `{\hyperref[reference_elements:xmdscsyntax]{\emph{CDATA}}}` block, accessing any components of vectors and computed vectors [...]
+
+The basis of the output is specified by the \code{basis} attribute.  This overrides any basis specification in the \code{\textless{}dependencies\textgreater{}} element.  Because we often wish to calculate these vectors on a finer grid than we wish to output, it is possible to specify that the output on a subset of the points defined for any transverse dimension.  This is done by adding a number in parentheses after that dimension in the basis string, e.g. \code{basis="x y(32) kz(64)"}.   [...]
+
+The \code{initial\_sample} attribute, which must be ``yes'' or ``no'', determines whether the moment group will be sampled before any integration occurs.
+
+Example syntax:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}output} \PYG{n+na}{format=}\PYG{l+s}{\PYGZdq{}hdf5\PYGZdq{}} \PYG{n+na}{filename=}\PYG{l+s}{\PYGZdq{}SimOutput.xsil\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}x y\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}computed\PYGZus{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}filter3\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}complex\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}sparemomentagain\PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}evaluation}\PYG{n+nt}{\PYGZgt{}}
+        \PYG{n+nt}{\PYGZlt{}dependencies} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}kx ky\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}integrated\PYGZus{}u main\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+        \PYG{c+cp}{\PYGZlt{}![CDATA[}
+          \PYG{n}{sparemomentagain} \PYG{o}{=} \PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{u}\PYG{p}{)}\PYG{p}{;}
+        \PYG{c+cp}{]]\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}/evaluation\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/computed\PYGZus{}vector\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}operator} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}ex\PYGZdq{}} \PYG{n+na}{constant=}\PYG{l+s}{\PYGZdq{}no\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}operator\PYGZus{}names}\PYG{n+nt}{\PYGZgt{}}L\PYG{n+nt}{\PYGZlt{}/operator\PYGZus{}names\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{L} \PYG{o}{=} \PYG{o}{\PYGZhy{}}\PYG{n}{T}\PYG{o}{*}\PYG{n}{kx}\PYG{o}{*}\PYG{n}{kx}\PYG{o}{/}\PYG{n}{mu}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/operator\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}}amp ke\PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}main filter1\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+    \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{n}{amp} \PYG{o}{=} \PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{u} \PYG{o}{+} \PYG{n}{moment}\PYG{p}{)}\PYG{p}{;}
+      \PYG{n}{ke} \PYG{o}{=} \PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{L}\PYG{p}{[}\PYG{n}{u}\PYG{p}{]}\PYG{p}{)}\PYG{p}{;}
+    \PYG{c+cp}{]]\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}kx(0) ky(64)\PYGZdq{}} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}moments}\PYG{n+nt}{\PYGZgt{}}Dens\PYGZus{}P \PYG{n+nt}{\PYGZlt{}/moments\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}fields \PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+    \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{n}{Dens\PYGZus{}P} \PYG{o}{=} \PYG{n+nf}{mod2}\PYG{p}{(}\PYG{n}{psi}\PYG{p}{)}\PYG{p}{;}
+    \PYG{c+cp}{]]\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/output\PYGZgt{}}
+\end{Verbatim}
+
+
+\subsection{XMDS-specific C syntax}
+\label{reference_elements:xmds-specific-c-syntax}\label{reference_elements:xmdscsyntax}
+Sampling complex numbers can be written more efficiently using:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{c+cp}{\PYGZlt{}![CDATA[}
+  \PYG{n}{\PYGZus{}SAMPLE\PYGZus{}COMPLEX}\PYG{p}{(}\PYG{n}{W}\PYG{p}{)}\PYG{p}{;}
+\PYG{c+cp}{]]\PYGZgt{}}
+\end{Verbatim}
+
+which is short for
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{c+cp}{\PYGZlt{}![CDATA[}
+  \PYG{n}{WR} \PYG{o}{=} \PYG{n}{W}\PYG{p}{.}\PYG{n}{Re}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
+  \PYG{n}{WI} \PYG{o}{=} \PYG{n}{W}\PYG{p}{.}\PYG{n}{Im}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
+\PYG{c+cp}{]]\PYGZgt{}}
+\end{Verbatim}
+
+Various properties of dimensions are available.  For example, for a dimension called \code{x}:
+\begin{itemize}
+\item {} 
+The number of points is accessible with the variable \code{\_lattice\_x},
+
+\item {} 
+The minimum range of that dimension is \code{\_min\_x},
+
+\item {} 
+The maximum range of that dimension is \code{\_max\_x},
+
+\item {} 
+The step size of a dimension is \code{dx}, and if it is constant, also available using \code{\_dx}, but note that the latter does not include the effect of any \code{volumePrefix} you may have set!
+
+\end{itemize}
+
+
+\chapter{Advanced Topics}
+\label{advanced_topics:advancedtopics}\label{advanced_topics:advanced-topics}\label{advanced_topics::doc}
+This section has further details on some important topics.
+
+{\hyperref[advanced_topics:importing]{\emph{Importing data}}} (importing data into XMDS2, and data formats used in the export)
+
+{\hyperref[advanced_topics:convolutions]{\emph{Convolutions and Fourier transforms}}} (extra information on the Fourier transforms used in XMDS2, and applications to defining convolutions)
+
+{\hyperref[advanced_topics:dimensionaliases]{\emph{Dimension aliases}}} (dimensions which are declared to be identical, useful for correlation functions)
+
+
+\section{Importing data}
+\label{advanced_topics:importing}\label{advanced_topics:importing-data}
+There are many cases where it is advantageous to import previously acquired data into XMDS2. For example, the differential equation you wish to solve may depend on a complicated functional form, which is more easily obtained via an analytical package such as Mathematica or Maple. Furthermore, importing data from another source can be quicker than needlessly performing calculations in XMDS2. In this tutorial, we shall consider an example of importing into XMDS2 a function generated in Mat [...]
+
+Suppose we want to import the following function into XMDS2:
+\begin{gather}
+\begin{split}f(x) = x^2\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+The first step is to create an hdf5 file, from XMDS2, which specifies the dimensions of the grid for the x dimension. Create and save a new XMDS2 file. For the purposes of this tutorial we shall call it ``grid\_specifier.xmds'' with name ``grid\_specifier''. Within this file, enter the following ``dummy'' vector - which we shall call ``gen\_dummy'' - which depends on the x dimension:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}gen\PYGZus{}dummy\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}dummy\PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{c+cp}{\PYGZlt{}![CDATA[}
+    \PYG{n}{dummy} \PYG{o}{=} \PYG{n}{x}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+\end{Verbatim}
+
+What ``dummy'' is is not actually important. It is only necessary that it is a function of $x$. However, it is important that the domain and lattice for the $x$ dimension are identical to those in the XMDS2 you plan to import the function into. We output the following xsil file (in hdf5 format) by placing a breakpoint in the sequence block as follows:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}sequence}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}breakpoint} \PYG{n+na}{filename=}\PYG{l+s}{\PYGZdq{}grid.xsil\PYGZdq{}} \PYG{n+na}{format=}\PYG{l+s}{\PYGZdq{}hdf5\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}
+        gen\PYGZus{}dummy
+      \PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/breakpoint\PYGZgt{}}
+\end{Verbatim}
+
+In terminal, compile the file ``grid\_specifier.xmds'' in XMDS2 and run the c code as usual. This creates two files - ``grid.xsil'' and ``grid.h5''. The file ``grid.h5'' contains the list of points which make up the grids for the x dimensions. This data can now be used to ensure that the function $f(x)$ which we will import into XMDS2 is compatible with the the specified grid in your primary XMDS2 file.
+
+In order to read the ``grid.h5'' data into Mathematica version 6.0, type the following command into terminal:.. code-block:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+xsil2graphics2 \PYGZhy{}e grid.xsil
+\end{Verbatim}
+
+This creates the Mathematica notebook ``grid.nb''. Open this notebook in Mathematica and evaluate the first set of cells. This has loaded the grid information into Mathematica. For example, suppose you have specified that the $x$ dimension has a lattice of 128 points and a domain of (-32, 32). Then calling ``x1'' in Mathematica should return the following list:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYGZob{}\PYGZhy{}32., \PYGZhy{}31.5, \PYGZhy{}31., \PYGZhy{}30.5, \PYGZhy{}30., \PYGZhy{}29.5, \PYGZhy{}29., \PYGZhy{}28.5, \PYGZhy{}28., \PYGZhy{}27.5,
+\PYGZhy{}27., \PYGZhy{}26.5, \PYGZhy{}26., \PYGZhy{}25.5, \PYGZhy{}25., \PYGZhy{}24.5, \PYGZhy{}24., \PYGZhy{}23.5, \PYGZhy{}23., \PYGZhy{}22.5,
+\PYGZhy{}22., \PYGZhy{}21.5, \PYGZhy{}21., \PYGZhy{}20.5, \PYGZhy{}20., \PYGZhy{}19.5, \PYGZhy{}19., \PYGZhy{}18.5, \PYGZhy{}18., \PYGZhy{}17.5,
+\PYGZhy{}17., \PYGZhy{}16.5, \PYGZhy{}16., \PYGZhy{}15.5, \PYGZhy{}15., \PYGZhy{}14.5, \PYGZhy{}14., \PYGZhy{}13.5, \PYGZhy{}13., \PYGZhy{}12.5,
+\PYGZhy{}12., \PYGZhy{}11.5, \PYGZhy{}11., \PYGZhy{}10.5, \PYGZhy{}10., \PYGZhy{}9.5, \PYGZhy{}9., \PYGZhy{}8.5, \PYGZhy{}8., \PYGZhy{}7.5, \PYGZhy{}7.,
+\PYGZhy{}6.5, \PYGZhy{}6., \PYGZhy{}5.5, \PYGZhy{}5., \PYGZhy{}4.5, \PYGZhy{}4., \PYGZhy{}3.5, \PYGZhy{}3., \PYGZhy{}2.5, \PYGZhy{}2., \PYGZhy{}1.5, \PYGZhy{}1.,
+\PYGZhy{}0.5, 0., 0.5, 1., 1.5, 2., 2.5, 3., 3.5, 4., 4.5, 5., 5.5, 6., 6.5,
+7., 7.5, 8., 8.5, 9., 9.5, 10., 10.5, 11., 11.5, 12., 12.5, 13.,
+13.5, 14., 14.5, 15., 15.5, 16., 16.5, 17., 17.5, 18., 18.5, 19.,
+19.5, 20., 20.5, 21., 21.5, 22., 22.5, 23., 23.5, 24., 24.5, 25.,
+25.5, 26., 26.5, 27., 27.5, 28., 28.5, 29., 29.5, 30., 30.5, 31.,
+31.5\PYGZcb{}
+\end{Verbatim}
+
+This is, of course, the list of points which define our grid.
+
+We are now in a position to define the function $f(x)$ in Mathematica. Type the following command into a cell in the Mathematica notebook ``grid.nb'':
+
+\begin{Verbatim}[commandchars=\\\{\}]
+f[x\PYGZus{}]:= x\PYGZca{}2
+\end{Verbatim}
+
+At this stage this is an abstract mathematical function as defined in Mathematica. What we need is a list of values for $f(x)$ corresponding to the specified grid points. We will call this list ``func''. This achieved by simply acting the function on the list of grid points ``x1'':
+
+\begin{Verbatim}[commandchars=\\\{\}]
+func := f[x1]
+\end{Verbatim}
+
+For the example grid mentioned above, calling ``func'' gives the following list:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYGZob{}1024., 992.25, 961., 930.25, 900., 870.25, 841., 812.25, 784.,
+756.25, 729., 702.25, 676., 650.25, 625., 600.25, 576., 552.25, 529.,
+506.25, 484., 462.25, 441., 420.25, 400., 380.25, 361., 342.25, 324.,
+306.25, 289., 272.25, 256., 240.25, 225., 210.25, 196., 182.25, 169.,
+156.25, 144., 132.25, 121., 110.25, 100., 90.25, 81., 72.25, 64.,
+56.25, 49., 42.25, 36., 30.25, 25., 20.25, 16., 12.25, 9., 6.25, 4.,
+2.25, 1., 0.25, 0., 0.25, 1., 2.25, 4., 6.25, 9., 12.25, 16., 20.25,
+25., 30.25, 36., 42.25, 49., 56.25, 64., 72.25, 81., 90.25, 100.,
+110.25, 121., 132.25, 144., 156.25, 169., 182.25, 196., 210.25, 225.,
+240.25, 256., 272.25, 289., 306.25, 324., 342.25, 361., 380.25, 400.,
+420.25, 441., 462.25, 484., 506.25, 529., 552.25, 576., 600.25, 625.,
+650.25, 676., 702.25, 729., 756.25, 784., 812.25, 841., 870.25, 900.,
+930.25, 961., 992.25\PYGZcb{}
+\end{Verbatim}
+
+The next step is to export the list ``func'' as an h5 file that XMDS2 can read. This is done by typing the following command into a Mathematica cell:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+SetDirectory[NotebookDirectory[]];
+Export[\PYGZdq{}func.h5\PYGZdq{}, \PYGZob{}func, x1\PYGZcb{}, \PYGZob{}\PYGZdq{}Datasets\PYGZdq{}, \PYGZob{} \PYGZdq{}function\PYGZus{}x\PYGZdq{}, \PYGZdq{}x\PYGZdq{}\PYGZcb{}\PYGZcb{}]
+\end{Verbatim}
+
+In the directory containing the notebook ``grid.nb'' you should now see the file ``func.h5''. This file essentially contains the list \code{\{func, x1\}}. However, the hdf5 format stores func and x1 as separate entities called ``Datasets''. For importation into XMDS2 it is necessary that these datasets are named. This is precisely what the segment \code{\{"Datasets", \{ "function\_x", "x"\}\}} in the above Mathematica command does. The dataset corresponding to the grid x1 needs to be giv [...]
+
+The final step is to import the file ``func.h5'' into your primary XMDS2 file. This data will be stored as a vector called ``gen\_function\_x'', in component ``function\_x''.
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}gen\PYGZus{}function\PYGZus{}x\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}function\PYGZus{}x\PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}initialisation} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}hdf5\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}filename}\PYG{n+nt}{\PYGZgt{}} function\PYGZus{}x.h5 \PYG{n+nt}{\PYGZlt{}/filename\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+\end{Verbatim}
+
+You're now done. Anytime you want to use $f(x)$ you can simply refer to ``function\_x'' in the vector ``gen\_function\_x''.
+
+The situation is slightly more complicated if the function you wish to import depends on more than one dimension. For example, consider
+\begin{gather}
+\begin{split}g(x,y) = x \sin(y)\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+As for the single dimensional case, we need to export an hdf5 file from XMDS2 which specifies the dimensions of the grid. As in the one dimensional case, this is done by creating a dummy vector which depends on all the relevant dimensions:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}real\PYGZdq{}} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}gen\PYGZus{}dummy\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}x y\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}dummy\PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{c+cp}{\PYGZlt{}![CDATA[}
+    \PYG{n}{dummy} \PYG{o}{=} \PYG{n}{x}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+\end{Verbatim}
+
+and exporting it as shown above.
+
+After importing the grid data into Mathematica, define the multi-dimensional function which you wish to import into XMDS2:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+g[x\PYGZus{},y\PYGZus{}]:= x*Sin[y]
+\end{Verbatim}
+
+We need to create a 2x2 array of data which depends upon the imported lists x1 and y1. This can be done by using the Table function:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+func := Table[g[x, p], \PYGZob{}x, x1\PYGZcb{}, \PYGZob{}p, p1\PYGZcb{}]
+\end{Verbatim}
+
+This function can be exported as an h5 file,
+
+\begin{Verbatim}[commandchars=\\\{\}]
+SetDirectory[NotebookDirectory[]];
+Export[\PYGZdq{}func.h5\PYGZdq{}, \PYGZob{}func, x1, y1\PYGZcb{}, \PYGZob{}\PYGZdq{}Datasets\PYGZdq{}, \PYGZob{} \PYGZdq{}function\PYGZus{}x\PYGZdq{}, \PYGZdq{}x\PYGZdq{}, \PYGZdq{}y\PYGZdq{}\PYGZcb{}\PYGZcb{}]
+\end{Verbatim}
+
+and imported into XMDS2 as outlined above.
+
+
+\section{Convolutions and Fourier transforms}
+\label{advanced_topics:convolutions-and-fourier-transforms}\label{advanced_topics:convolutions}
+When evaluating a numerical Fourier transform, XMDS2 doesn't behave as expected. While many simulations have ranges in their spatial coordinate (here assumed to be x) that range from some negative value $x_\text{min}$ to some positive value $x_\text{max}$, the Fourier transform used in XMDS2 treats all spatial coordinates as starting at zero. The result of this is that a phase factor of the form $e^{-i x_\text{min} k}$ is applied to the Fourier space functions after all forward (from rea [...]
+
+The standard Fourier transform is
+\begin{gather}
+\begin{split}\mathcal{F}\left[f(x)\right](k) = \frac{1}{\sqrt{2\pi}}\int_{x_\text{min}}^{x_\text{max}} f(x) e^{-i x k} dx\end{split}\notag
+\end{gather}
+The XMDS2 Fourier transform is
+\begin{gather}
+\begin{split}\tilde{\mathcal{F}}\left[f(x)\right](k) &= \frac{1}{\sqrt{2\pi}}\int_{x_\text{min}}^{x_\text{max}} f(x) e^{-i (x+ x_\text{min}) k} dx \\
+&= e^{-i x_\text{min} k} \mathcal{F}\left[f(x)\right](k)\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+When the number of forward Fourier transforms and backwards Fourier transforms are unequal a phase factor is required. Some examples of using Fourier transforms in XMDS2 are shown below.
+
+
+\subsection{Example 1}
+\label{advanced_topics:example-1}
+{\hfill\includegraphics{FourierTransformEx1.pdf}\hfill}
+
+When data is input in Fourier space and output in real space there is one backwards Fourier transform is required. Therefore the Fourier space data must be multiplied by a phase factor before the backwards Fourier transform is applied.
+\begin{gather}
+\begin{split}\mathcal{F}^{-1}[F(k)](x) = \tilde{\mathcal{F}}[e^{i x_\text{min} k} F(k)](x)\end{split}\notag
+\end{gather}
+
+\subsection{Example 2}
+\label{advanced_topics:example-2}
+{\hfill\includegraphics{FourierTransformEx2.pdf}\hfill}
+
+Functions of the form $h(x) = \int f(x') g(x-x') dx'$ can be evaluated using the convolution theorem:
+\begin{gather}
+\begin{split}\mathcal{F}[h(x)](k) = \mathcal{F}[f(x)](k) \times \mathcal{F}[g(x)](k)\end{split}\notag
+\end{gather}
+This requires two forward Fourier transforms to get the two functions f and g into Fourier space, and one backwards Fourier transform to get the resulting product back into real space. Thus in Fourier space the product needs to be multiplied by a phase factor $e^{-i x_\text{min} k}$
+
+
+\subsection{Example 3}
+\label{advanced_topics:example-3}
+{\hfill\includegraphics{FourierTransformEx3.pdf}\hfill}
+
+Sometimes when the convolution theorem is used one of the forward Fourier transforms is calculated analytically and input in Fourier space. In this case only one forward numerical Fourier transform and one backward numerical Fourier transform is used. The number of forward and backward transforms are equal, so no phase factor is required.
+
+
+\section{`Loose' \texttt{geometry\_matching\_mode}}
+\label{advanced_topics:loosegeometrymatchingmode}\label{advanced_topics:loose-geometry-matching-mode}
+
+\section{Dimension aliases}
+\label{advanced_topics:dimension-aliases}\label{advanced_topics:dimensionaliases}
+Dimension aliases specify that two or more dimensions have exactly the same \code{lattice}, \code{domain} and \code{transform}.  This can be useful in situations where the problem enforces this, for example when computing correlation functions or representing square matrices.
+
+Dimension aliases are not just a short-hand for defining an additional dimension, they also permit dimensions to be accessed {\hyperref[reference_elements:referencingnonlocal]{\emph{non-locally}}}, which is essential when computing spatial correlation functions.
+
+Here is how to compute a spatial correlation function $g^{(1)}(x, x') = \psi^*(x) \psi(x')$ of the quantity \code{psi}:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}simulation} \PYG{n+na}{xmds\PYGZhy{}version=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+
+  \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ name, features block }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}geometry}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}propagation\PYGZus{}dimension}\PYG{n+nt}{\PYGZgt{}} t \PYG{n+nt}{\PYGZlt{}/propagation\PYGZus{}dimension\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}transverse\PYGZus{}dimensions}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dimension} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}x\PYGZdq{}} \PYG{n+na}{lattice=}\PYG{l+s}{\PYGZdq{}1024\PYGZdq{}} \PYG{n+na}{domain=}\PYG{l+s}{\PYGZdq{}(\PYGZhy{}1.0, 1.0)\PYGZdq{}} \PYG{n+na}{aliases=}\PYG{l+s}{\PYGZdq{}xp\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/transverse\PYGZus{}dimensions\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/geometry\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}wavefunction\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}complex\PYGZdq{}} \PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} psi \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}initialisation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ initialisation code }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+
+  \PYG{n+nt}{\PYGZlt{}computed\PYGZus{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}correlation\PYGZdq{}} \PYG{n+na}{dimensions=}\PYG{l+s}{\PYGZdq{}x xp\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}complex\PYGZdq{}} \PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}} g1 \PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}evaluation}\PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}} wavefunction \PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{g1} \PYG{o}{=} \PYG{n+nf}{conj}\PYG{p}{(}\PYG{n}{psi}\PYG{p}{(}\PYG{n}{x} \PYG{o}{=}\PYG{o}{\PYGZgt{}} \PYG{n}{x}\PYG{p}{)}\PYG{p}{)} \PYG{o}{*} \PYG{n}{psi}\PYG{p}{(}\PYG{n}{x} \PYG{o}{=}\PYG{o}{\PYGZgt{}} \PYG{n}{xp}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/evaluation\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/computed\PYGZus{}vector\PYGZgt{}}
+
+  \PYG{c}{\PYGZlt{}!\PYGZhy{}\PYGZhy{}}\PYG{c}{ integration and sampling code }\PYG{c}{\PYGZhy{}\PYGZhy{}\PYGZgt{}}
+
+\PYG{n+nt}{\PYGZlt{}/simulation\PYGZgt{}}
+\end{Verbatim}
+
+In this simulation note that the vector \code{wavefunction} defaults to only having the dimension ``x'' even though ``xp'' is also a dimension (implicitly declared through the \code{aliases} attribute).  \code{vector}`s without an explicit \code{dimensions} attribute will only have the dimensions that are explicitly listed in the \code{transverse\_dimensions} block, i.e. this will not include aliases.
+
+See the example \code{groundstate\_gaussian.xmds} for a complete example.
+
+
+\chapter{Frequently Asked Questions}
+\label{faq:faq}\label{faq::doc}\label{faq:frequently-asked-questions}
+
+\section{XMDS scripts look complicated! How do I start?}
+\label{faq:xmds-scripts-look-complicated-how-do-i-start}
+If you're unfamiliar with XMDS2, writing a script from scratch might seem difficult. In most cases, however, the best approach is to take an existing script and modify it for your needs. At the most basic level, you can simply take a script from the /examples directory that is similar to what you want to do, change the name of the integration variable(s) and replace the line describing the differential equation to use your DE instead. That's all you need to do, and will ensure all the sy [...]
+
+You can then incrementally change things such as the number of output points, what quantities get output, number of grid points, and so on. Many XMDS2 users have never written a script from scratch, and just use their previous scripts and example scripts as a scaffold when they create a script for a new problem.
+
+
+\section{Where can I get help?}
+\label{faq:where-can-i-get-help}
+The documentation on this website is currently incomplete, but it still covers a fair bit and is worth reading. Similarly, the example scripts in the /examples directory cover most of the functionality of XMDS2, so it's worth looking looking through them to see if any of them do something similar to what you're trying to do.
+
+You should also feel free to email questions to the XMDS users' mailing list at \href{mailto:xmds-users at lists.sourceforge.net}{xmds-users at lists.sourceforge.net}, where the developers and other users can assist you. You can join the mailing list by going to \href{http://sourceforge.net/projects/xmds/}{http://sourceforge.net/projects/xmds/} and clicking on ``mailing lists.'' Also, if you look through the mailing list archives, your particular problem may already have been discussed.
+
+
+\section{How should I cite XMDS2?}
+\label{faq:how-should-i-cite-xmds2}
+If you publish work that has involved XMDS2, please cite it as: \href{http://dx.doi.org/10.1016/j.cpc.2012.08.016}{Comput. Phys. Commun. 184, 201-208 (2013)}.
+
+
+\section{I think I found a bug! Where should I report it?}
+\label{faq:i-think-i-found-a-bug-where-should-i-report-it}
+Please report bugs to the developer mailing list at \href{mailto:xmds-devel at lists.sourceforge.net}{xmds-devel at lists.sourceforge.net}. In your email, please include a description of the problem and attach the XMDS2 script that triggers the bug.
+
+
+\section{How do I put time dependence into my vectors?}
+\label{faq:how-do-i-put-time-dependence-into-my-vectors}
+Standard vectors can't have time dependence (or, more accurately, depend on the \code{propagation\_dimension} variable), but computed vectors can. So, for example, if you have set your \code{propagation\_dimension} as ``t'', you can simply use the variable ``t'' in your computed vector and it will work.
+
+Alternatively, you can explicitly use the \code{propagation\_dimension} variable in your differential equation inside the \code{\textless{}operators\textgreater{}} block.
+
+
+\section{Can I specify the range of my domain and number of grid points at run-time?}
+\label{faq:can-i-specify-the-range-of-my-domain-and-number-of-grid-points-at-run-time}
+Yes, you can. In your script, specify the domain and number of grid points as arguments to be passed in at run-time, use those variables in your \code{\textless{}geometry\textgreater{}} block rather than explicitly specifying them, and use the \code{\textless{}validation kind="run-time" /\textgreater{}} feature. See the {\hyperref[reference_elements:validation]{\emph{Validation}}} entry in the Reference section for an example.
+
+While the domain can always be specified in this way, specifying the lattice size at run-time is currently only allowed with the following transforms: `dct', `dst', `dft' and `none' (see {\hyperref[reference_elements:validation]{\emph{Transforms}}} in the Reference section).
+
+Also note that for some multi-dimensional spaces using different transforms, XMDS2 will sometimes optimise the code it generates based on the relative sizes of the dimensions. If one or more of the lattices are specified at run-time it is unable to do this and will have to make guesses. In some situations this may result in slightly slower code.
+
+
+\section{When can I use IP operators (and why should I) and when must I use EX operators?}
+\label{faq:when-can-i-use-ip-operators-and-why-should-i-and-when-must-i-use-ex-operators}
+An {\hyperref[reference_elements:operatornameselement]{\emph{\textless{}operator\textgreater{}}}} that specifies named operators to be used in integration equations can have the \code{kind="IP"} or \code{kind="EX"} attribute, standing for `interaction picture' and `explicit' operators respectively.  Explicit operators can be used in all situations, and simply construct and calculate a new vector of the form in the square brackets.  IP operators use less memory and can improve speed by al [...]
+
+Some explanation is in order.  The IP algorithm applies the operator separately to the rest of the evolution.  The reason this can be so effective is that the separate evolution can be performed exactly.  The solution of the equation $\frac{d \psi}{dt} = L \psi$ is $\psi(t+\Delta t) = exp(L \Delta t) \psi(t)$ for arbitrarily large timestep $\Delta t$.  For a diagonal linear \code{L}, the matrix exponential is straightforward.  Also, when it is constant, then the exponential can be comput [...]
+
+Therefore, the limitations of IP operators themselves means that they can only be applied to to named components of one of the integration vectors, and not functions of those components.  Furthermore, an IP operator acting on a component must only be used in the derivative for that particular component.  Secondly, due to the implementation of IP operators in XMDS2, it is not safe to use them in comments, or in conjunction with declared variables.  It is also not safe to multiply or divid [...]
+
+
+\section{Visual Editors}
+\label{faq:visual-editors}
+In this section goes stuff about how to set up TextMate (or other editors to highlight xpdeint scripts).
+
+
+\chapter{Upgrading From XMDS 1.X}
+\label{upgrade:upgradefromxmds1}\label{upgrade::doc}\label{upgrade:upgrading-from-xmds-1-x}
+While \textbf{XMDS2} is a complete rewrite of the \textbf{XMDS} project, much of the syntax has remained very similar.  That said, your code will have to be rewritten as an XMDS2 program.  We recommend that you work through the {\hyperref[tutorial:quickstarttutorial]{\emph{Quickstart Tutorial}}} and perhaps the {\hyperref[worked_examples:workedexamples]{\emph{Worked Examples}}} sections, and then you should be good to go.
+
+The main news when switching to XMDS2 is the long list of new things you can do.  If it's an initial value problem, XMDS2 has a good chance of being able to solve it.
+
+We have made the decision to call the executables ``xmds2'' and ``xsil2graphics2'' so that you can keep using your old installation in parallel with the new version.
+
+
+\chapter{Optimisation Hints}
+\label{optimisation_hints::doc}\label{optimisation_hints:optimisation-hints}
+There are a variety of things you can do to make your simulations run faster.
+
+
+\section{Geometry and transform-based tricks}
+\label{optimisation_hints:geometry-and-transform-based-tricks}
+
+\subsection{Simpler simulation geometries}
+\label{optimisation_hints:simpler-simulation-geometries}
+Consider symmetry, can you use \code{dct} transforms or \code{bessel} transforms? Do you really need that many points? How big does your grid need to be? Could absorbing boundary conditions help?
+
+
+\subsection{Tricks for Bessel and Hermite-Gauss transforms}
+\label{optimisation_hints:tricks-for-bessel-and-hermite-gauss-transforms}
+Dimensions using matrix transforms should be first for performance reasons.  Unless you're using MPI, in which case XMDS can work it out for the first two dimensions.  Ideally, XMDS would sort it out in all cases, but it's not that smart yet.
+
+
+\section{Reduce code complexity}
+\label{optimisation_hints:reduce-code-complexity}
+Avoid transcendental functions like $\sin(x)$ or $\exp(x)$ in inner loops. Not all operations are made equal, use multiplication over division.
+
+
+\subsection{Use the Interaction Picture (IP) operator}
+\label{optimisation_hints:use-the-interaction-picture-ip-operator}
+Just do it. Only use the EX operator when you have to. If you must use the EX operator, consider making it \code{constant="no"}. It uses less memory.
+When you use the IP operator, make sure you know what it's doing.  Do not pre- or post-multiply that term in your equations.
+
+When using the IP operator, check if your operator is purely real or purely imaginary.  If real, (e.g. \code{L = -0.5*kx * kx;}), then add the attribute \code{type="real"} to the \code{\textless{}operator kind="ip"\textgreater{}} tag.  If purely imaginary, use \code{type="imaginary"}.  This optimisation saves performing the part of the complex exponential that is unnecessary.
+
+
+\subsection{Consider writing the evolution in spectral basis}
+\label{optimisation_hints:consider-writing-the-evolution-in-spectral-basis}
+Evolution equations do not need to be written in the position basis.  If your equations are diagonal in the spectral basis, then it makes more sense to compute the time derivative terms in that basis.  For example, if you have the system
+\begin{gather}
+\begin{split}\frac{d\psi_1(x)}{dt} &= i \frac{\hbar}{2M} \frac{d^2\psi_1(x)}{dx^2} - i \Omega \psi_2(x)\\
+\frac{d\psi_2(x)}{dt} &= i \frac{\hbar}{2M} \frac{d^2\psi_2(x)}{dx^2} - i \Omega \psi_1(x)\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+then this is diagonal in the Fourier basis where it takes the form
+\begin{gather}
+\begin{split}\frac{d\psi_1(k_x)}{dt} &= -i \frac{\hbar k_x^2}{2M} \psi_1(k_x) - i \Omega \psi_2(k_x)\\
+\frac{d\psi_2(k_x)}{dt} &= -i \frac{\hbar k_x^2}{2M} \psi_2(k_x) - i \Omega \psi_1(k_x)\end{split}\notag\\\begin{split}\end{split}\notag
+\end{gather}
+The first term in each evolution equation can be solved exactly with an IP operator, and the second term is diagonal in Fourier space.  This can be written in XMDS as:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}operators}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}integration\PYGZus{}vectors} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}kx\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/integration\PYGZus{}vectors\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}operator} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}ip\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}imaginary\PYGZdq{}} \PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}operator\PYGZus{}names}\PYG{n+nt}{\PYGZgt{}}Lxx\PYG{n+nt}{\PYGZlt{}/operator\PYGZus{}names\PYGZgt{}}
+    \PYG{c+cp}{\PYGZlt{}![CDATA[}
+      \PYG{n}{Lxx} \PYG{o}{=} \PYG{o}{\PYGZhy{}}\PYG{k+kc}{i}\PYG{o}{*}\PYG{l+m+mf}{0.5}\PYG{o}{*}\PYG{n}{hbar\PYGZus{}M}\PYG{o}{*}\PYG{p}{(}\PYG{n}{kx}\PYG{o}{*}\PYG{n}{kx}\PYG{p}{)}\PYG{p}{;}
+    \PYG{c+cp}{]]\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/operator\PYGZgt{}}
+  \PYG{c+cp}{\PYGZlt{}![CDATA[}
+
+    \PYG{n}{dpsi0\PYGZus{}dt} \PYG{o}{=} \PYG{n}{Lxx}\PYG{p}{[}\PYG{n}{psi0}\PYG{p}{]} \PYG{o}{\PYGZhy{}} \PYG{k+kc}{i}\PYG{o}{*}\PYG{n}{Omega}\PYG{o}{*}\PYG{n}{psi1}\PYG{p}{;}
+    \PYG{n}{dpsi1\PYGZus{}dt} \PYG{o}{=} \PYG{n}{Lxx}\PYG{p}{[}\PYG{n}{psi1}\PYG{p}{]} \PYG{o}{\PYGZhy{}} \PYG{k+kc}{i}\PYG{o}{*}\PYG{n}{Omega}\PYG{o}{*}\PYG{n}{psi0}\PYG{p}{;}
+
+  \PYG{c+cp}{]]\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/operators\PYGZgt{}}
+\end{Verbatim}
+
+Although the \code{dpsi0\_dt} code reads the same in position and Fourier space, it is the \code{basis=kx} attribute on \code{\textless{}integration\_vectors\textgreater{}} that causes the evolution code to be executed in Fourier space.
+
+A final optimisation is to cause the integration code itself to operate in Fourier space.  By default, all time stepping (i.e. $f(t + \Delta t) = f(t) + f'(t) \Delta t$ for forward-Euler integration) occurs in the position space.  As the derivative terms can be computed in Fourier space, it is faster to also to the time stepping in Fourier space too.  This then means that no Fourier transforms will be needed at all during this integrate block (except as needed by sampling).  To cause tim [...]
+
+The fully optimised code then reads:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}integrate} \PYG{n+na}{algorithm=}\PYG{l+s}{\PYGZdq{}ARK45\PYGZdq{}} \PYG{n+na}{interval=}\PYG{l+s}{\PYGZdq{}1\PYGZdq{}} \PYG{n+na}{tolerance=}\PYG{l+s}{\PYGZdq{}1e\PYGZhy{}6\PYGZdq{}} \PYG{n+na}{home\PYGZus{}space=}\PYG{l+s}{\PYGZdq{}k\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}samples}\PYG{n+nt}{\PYGZgt{}} 10 \PYG{n+nt}{\PYGZlt{}/samples\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}operators}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}integration\PYGZus{}vectors} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}kx\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/integration\PYGZus{}vectors\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}operator} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}ip\PYGZdq{}} \PYG{n+na}{type=}\PYG{l+s}{\PYGZdq{}imaginary\PYGZdq{}} \PYG{n+nt}{\PYGZgt{}}
+      \PYG{n+nt}{\PYGZlt{}operator\PYGZus{}names}\PYG{n+nt}{\PYGZgt{}}Lxx\PYG{n+nt}{\PYGZlt{}/operator\PYGZus{}names\PYGZgt{}}
+      \PYG{c+cp}{\PYGZlt{}![CDATA[}
+        \PYG{n}{Lxx} \PYG{o}{=} \PYG{o}{\PYGZhy{}}\PYG{k+kc}{i}\PYG{o}{*}\PYG{l+m+mf}{0.5}\PYG{o}{*}\PYG{n}{hbar\PYGZus{}M}\PYG{o}{*}\PYG{p}{(}\PYG{n}{kx}\PYG{o}{*}\PYG{n}{kx}\PYG{p}{)}\PYG{p}{;}
+      \PYG{c+cp}{]]\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}/operator\PYGZgt{}}
+    \PYG{c+cp}{\PYGZlt{}![CDATA[}
+
+      \PYG{n}{dpsi0\PYGZus{}dt} \PYG{o}{=} \PYG{n}{Lxx}\PYG{p}{[}\PYG{n}{psi0}\PYG{p}{]} \PYG{o}{\PYGZhy{}} \PYG{k+kc}{i}\PYG{o}{*}\PYG{n}{Omega}\PYG{o}{*}\PYG{n}{psi1}\PYG{p}{;}
+      \PYG{n}{dpsi1\PYGZus{}dt} \PYG{o}{=} \PYG{n}{Lxx}\PYG{p}{[}\PYG{n}{psi1}\PYG{p}{]} \PYG{o}{\PYGZhy{}} \PYG{k+kc}{i}\PYG{o}{*}\PYG{n}{Omega}\PYG{o}{*}\PYG{n}{psi0}\PYG{p}{;}
+
+    \PYG{c+cp}{]]\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/operators\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/integrate\PYGZgt{}}
+\end{Verbatim}
+
+This code will not use any Fourier transforms during an ordinary time-stepping, and will be much faster than if the code were written without the \code{home\_space} and \code{basis} attributes.
+
+
+\subsection{Don't recalculate things you don't have to}
+\label{optimisation_hints:don-t-recalculate-things-you-don-t-have-to}
+Use \code{computed\_vectors} appropriately.
+
+
+\section{Compiler and library tricks}
+\label{optimisation_hints:compiler-and-library-tricks}
+
+\subsection{Faster compiler}
+\label{optimisation_hints:faster-compiler}
+If you're using an Intel CPU, then you should consider using their compiler, icc. They made the silicon, and they also made a compiler that understands how their chips work significantly better than the more-portable GCC.
+
+
+\subsection{Faster libraries}
+\label{optimisation_hints:faster-libraries}
+Intel MKL is faster than ATLAS, which is faster than GSL CBLAS. If you have a Mac, then Apple's vecLib is plenty fast.
+
+
+\subsection{Auto-vectorisation}
+\label{optimisation_hints:auto-vectorisation}
+Auto-vectorisation is a compiler feature that makes compilers generate more efficient code that can execute the same operation on multiple pieces of data simultaneously. To use this feature, you need to add the following to the \code{\textless{}features\textgreater{}} block at the start of your simulation:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}auto\PYGZus{}vectorise} \PYG{n+nt}{/\PYGZgt{}}
+\end{Verbatim}
+
+This will make xpdeint generate code that is more friendly to compiler's auto-vectorisation features so that more code can be vectorised. It will also add the appropriate compiler options to turn on your compiler's auto-vectorisation features. For auto-vectorisation to increase the speed of your simulations, you will need a compiler that supports it such as gcc 4.2 or later, or Intel's C compiler, \code{icc}.
+
+
+\subsection{OpenMP}
+\label{optimisation_hints:openmp}
+\href{http://openmp.org}{OpenMP} is a set of compiler directives to make it easier to use threads (different execution contexts) in programs. Using threads in your simulation does occur some overhead, so for the speedup to outweigh the overhead, you must have a reasonably large simulation grid. To add these compiler directives to the generated simulations, add the tag \code{\textless{}openmp /\textgreater{}} in the \code{\textless{}features\textgreater{}} block. This can be used in combi [...]
+
+If you are using the OpenMP feature and are using \href{http://www.fftw.org}{FFTW}-based transforms (Discrete Fourier/Cosine/Sine Transforms), you should consider using threads with your FFT's by adding the following to the \code{\textless{}features\textgreater{}} block at the start of your simulation:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}fftw} \PYG{n+na}{threads=}\PYG{l+s}{\PYGZdq{}2\PYGZdq{}} \PYG{n+nt}{/\PYGZgt{}}
+\end{Verbatim}
+
+Replace the number of threads in the above code by the number of threads that you want to use.
+
+
+\subsection{Parallelisation with MPI}
+\label{optimisation_hints:parallelisation-with-mpi}
+Some simulations are so large or take so much time that it is not reasonable to run them on a single CPU on a single machine. Fortunately, the \href{http://www.mpi-forum.org/}{Message Passing Interface} was developed to enable different computers working on the same program to exchange data. You will need a MPI package installed to be abel to use this feature with your simulations. One popular implementation of MPI is \href{http://www.open-mpi.org}{OpenMPI}.
+
+
+\section{Atom-optics-specific hints}
+\label{optimisation_hints:atom-optics-specific-hints}
+
+\subsection{Separate out imaginary-time calculation code}
+\label{optimisation_hints:separate-out-imaginary-time-calculation-code}
+When doing simulations that require the calculation of the groundstate (typically via the imaginary time algorithm), typically the groundstate itself does not need to be changed frequently as it is usually the dynamics of the simulation that have the interesting physics. In this case, you can save having to re-calculate groundstate every time by having one script (call it \code{groundstate.xmds}) that saves the calculated groundstate to a file using a breakpoint, and a second simulation  [...]
+
+The file format used in this example is \href{http://www.hdfgroup.org/HDF5/}{HDF5}, and you will need the HDF5 libraries installed to use this example. The alternative is to use the deprecated \code{binary} format, however to load \code{binary} format data \code{xmds}, the predecessor to \code{xpdeint} must be installed. Anyone who has done this before will tell you that installing it isn't a pleasant experience, and so HDF5 is the recommended file format.
+
+If your wavefunction vector is called \code{'wavefunction'}, then to save the groundstate to the file \code{groundstate\_break.h5} in the HDF5 format, put the following code immediately after the integrate block that calculates your groundstate:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}breakpoint} \PYG{n+na}{filename=}\PYG{l+s}{\PYGZdq{}groundstate\PYGZus{}break\PYGZdq{}} \PYG{n+na}{format=}\PYG{l+s}{\PYGZdq{}hdf5\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}dependencies}\PYG{n+nt}{\PYGZgt{}}wavefunction\PYG{n+nt}{\PYGZlt{}/dependencies\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/breakpoint\PYGZgt{}}
+\end{Verbatim}
+
+In addition to the \code{groundstate\_break.h5} file, an XSIL wrapper \code{groundstate\_break.xsil} will also be created for use with {\hyperref[xsil2graphics2:xsil2graphics2]{\emph{xsil2graphics2}}}.
+
+To load this groundstate into your evolution script, the declaration of your \code{'wavefunction'} vector in your evolution script should look something like
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}vector} \PYG{n+na}{name=}\PYG{l+s}{\PYGZdq{}wavefunction\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}components}\PYG{n+nt}{\PYGZgt{}}phi1 phi2\PYG{n+nt}{\PYGZlt{}/components\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}initialisation} \PYG{n+na}{kind=}\PYG{l+s}{\PYGZdq{}hdf5\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}filename}\PYG{n+nt}{\PYGZgt{}}groundstate\PYGZus{}break.h5\PYG{n+nt}{\PYGZlt{}/filename\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}/initialisation\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/vector\PYGZgt{}}
+\end{Verbatim}
+
+Note that the groundstate-finder doesn't need to have all of the components that the evolution script needs. For example, if you are considering the evolution of a two-component BEC where only one component has a population in the groundstate, then your groundstate script can contain only the \code{phi1} component, while your evolution script can contain both the \code{phi1} component and the \code{phi2} component. Note that the geometry of the script generating the groundstate and the e [...]
+
+
+\subsection{Use an energy or momentum offset}
+\label{optimisation_hints:use-an-energy-or-momentum-offset}
+This is just the interaction picture with a constant term in the Hamiltonian. If your state is going to rotate like $e^{i(\omega + \delta\omega)t}$, then transform your equations to remove the $e^{i \omega t}$ term. Likewise for spatial rotations, if one mode will be moving on average with momentum $\hbar k$, then transform your equations to remove that term. This way, you may be able to reduce the density of points you need in that dimension. Warning: don't forget to consider this when  [...]
+
+
+\chapter{xsil2graphics2}
+\label{xsil2graphics2:xsil2graphics2}\label{xsil2graphics2::doc}\label{xsil2graphics2:id1}
+\textbf{xsil2graphics2} is a way of converting ''.xsil'' files to formats that other programs can read.  The syntax is described in the {\hyperref[tutorial:quickstarttutorial]{\emph{Quickstart Tutorial}}}, and by using the \code{xsil2graphics2 -{-}help} option.  It currently can covert any output format for use by Mathematica.
+
+We recommend HDF5 format instead of the binary format for output and input, as many visualisation tools can already read/write to this format directly.
+
+
+\chapter{Developer Documentation}
+\label{developer:developer-documentation}\label{developer::doc}
+Developers need to know more than users.  For example, they need to know about the test suite, and writing test cases.  They need to know how to perform a developer installation.  They need to know how to edit and compile this documentation.  They need a step-by-step release process.
+
+
+\section{Test scripts}
+\label{developer:test-scripts}\label{developer:testscripts}
+Every time you add a new feature and/or fix a new and exciting bug, it is a great idea to make sure that the new feature works and/or the bug stays fixed.  Fortunately, it is pleasantly easy to add a test case to the testing suite.
+\begin{enumerate}
+\item {} 
+Write normal XMDS script that behaves as you expect.
+
+\item {} 
+Add a \code{\textless{}testing\textgreater{}} element to your script.  You can read the description of this element and its contents below, and have a look at other testcases for examples, but the basic structure is simple:.
+
+\end{enumerate}
+{\hyperref[developer:testingelement]{\emph{}}}{\hyperref[developer:commandlineelement]{\emph{}}}{\hyperref[developer:commandlineelement]{\emph{}}}{\hyperref[reference_elements:argumentselement]{\emph{}}}{\hyperref[reference_elements:argumentelement]{\emph{}}}{\hyperref[reference_elements:argumentelement]{\emph{}}}{\hyperref[reference_elements:argumentselement]{\emph{}}}{\hyperref[developer:inputxsilfileelement]{\emph{}}}{\hyperref[developer:xsilfileelement]{\emph{}}}{\hyperref[developer: [...]
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}testing}\PYG{n+nt}{\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}command\PYGZus{}line}\PYG{n+nt}{\PYGZgt{}} \PYG{n+nt}{\PYGZlt{}/command\PYGZus{}line\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}arguments}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}argument} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}argument} \PYG{n+nt}{/\PYGZgt{}}
+    ...
+  \PYG{n+nt}{\PYGZlt{}/arguments\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}input\PYGZus{}xsil\PYGZus{}file} \PYG{n+nt}{/\PYGZgt{}}
+  \PYG{n+nt}{\PYGZlt{}xsil\PYGZus{}file}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}moment\PYGZus{}group} \PYG{n+nt}{/\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}moment\PYGZus{}group} \PYG{n+nt}{/\PYGZgt{}}
+    ...
+  \PYG{n+nt}{\PYGZlt{}/xsil\PYGZus{}file\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/testing\PYGZgt{}}
+\end{Verbatim}
+\begin{enumerate}
+\setcounter{enumi}{2}
+\item {} 
+Put into the appropriate \code{testsuite/} directory.
+
+\item {} 
+run \code{./run\_tests.py} This will automatically generate your \code{\_expected} files.
+
+\item {} 
+Commit the \code{.xmds}, \code{*\_expected.xsil} file and any \code{*\_expected*} data files.
+
+\end{enumerate}
+
+
+\subsection{Testing element}
+\label{developer:testing-element}\label{developer:testingelement}
+
+\subsection{command\_line element}
+\label{developer:commandlineelement}\label{developer:command-line-element}
+
+\subsection{input\_xsil\_file element}
+\label{developer:input-xsil-file-element}\label{developer:inputxsilfileelement}
+
+\subsection{xsil\_file element}
+\label{developer:xsilfileelement}\label{developer:xsil-file-element}
+
+\subsection{moment\_group element}
+\label{developer:momentgroupelement}\label{developer:moment-group-element}
+
+\section{Steps to update \texttt{XMDS} script validator (XML schema)}
+\label{developer:steps-to-update-xmds-script-validator-xml-schema}\begin{enumerate}
+\item {} 
+Modify \code{xpdeint/support/xpdeint.rnc}. This is a RelaxNG compact file, which specifies the XML schema which is only used for issuing warnings to users about missing or extraneous XML tags / attributes.
+
+\item {} 
+Run \code{make} in \code{xpdeint/support/} to update \code{xpdeint/support/xpdeint.rng}. This is the file which is actually used, which is in RelaxNG format, but RelaxNG compact is easier to read and edit.
+
+\item {} 
+Commit both \code{xpdeint/support/xpdeint.rnc} and \code{xpdeint/support/xpdeint.rng}.
+
+\end{enumerate}
+
+
+\section{Directory layout}
+\label{developer:directory-layout}
+
+\subsection{XMDS2's code and templates}
+\label{developer:xmds2-s-code-and-templates}
+All \code{.tmpl} files are Cheetah template files.  These are used to generate C++ code.  These templates are compiled as part of the XMDS2 build process to \code{.py} files of the same name.  Do not edit the generated \code{.py} files, always edit the \code{.tmpl} files and regenerate the corresponding \code{.py} files with \code{make}.
+\begin{itemize}
+\item {} \begin{description}
+\item[{\code{xpdeint/}:}] \leavevmode\begin{itemize}
+\item {} \begin{description}
+\item[{\code{Features/}: Code for all \code{\textless{}feature\textgreater{}} elements, such as \code{\textless{}globals\textgreater{}} and \code{\textless{}auto\_vectorise\textgreater{}}}] \leavevmode\begin{itemize}
+\item {} 
+\code{Transforms/}: Code for the Fourier and matrix-based transforms (including MPI variants).
+
+\end{itemize}
+
+\end{description}
+
+\item {} 
+\code{Geometry/}: Code for describing the geometry of simulation dimensions and domains.  Includes code for \code{Geometry}, \code{Field} and all \code{DimensionRepresentations}.
+
+\item {} 
+\code{Operators/}: Code for all \code{\textless{}operator\textgreater{}} elements, including \code{IP}, \code{EX} and the temporal derivative operator \code{DeltaA}.
+
+\item {} \begin{description}
+\item[{\code{Segments/}: Code for all elements that can appear in a \code{\textless{}segments\textgreater{}} tag.  This includes \code{\textless{}integrate\textgreater{}}, \code{\textless{}filter\textgreater{}}, and \code{\textless{}breakpoint\textgreater{}}.}] \leavevmode\begin{itemize}
+\item {} 
+\code{Integrators}: Code for fixed and adaptive integration schemes, and all steppers (e.g. \code{RK4}, \code{RK45}, \code{RK9}, etc.)
+
+\end{itemize}
+
+\end{description}
+
+\item {} \begin{description}
+\item[{\code{Stochastic/}: Code for all random number generators and the random variables derived from them.}] \leavevmode\begin{itemize}
+\item {} 
+\code{Generators/}: Code for random number generators, includes \code{dSFMT}, \code{POSIX}, \code{Solirte}.
+
+\item {} 
+\code{RandomVariables/}: Code for the random variables derived from the random number generators.  These are the gaussian, poissonian and uniform random variables.
+
+\end{itemize}
+
+\end{description}
+
+\item {} 
+\code{SimulationDrivers/}: Code for all \code{\textless{}driver\textgreater{}} elements.  In particular, this is where the location of MPI and multi-path code.
+
+\item {} 
+\code{Vectors/}: Code for all \code{\textless{}vector\textgreater{}} elements, and their initialisation.  This includes normal \code{\textless{}vector\textgreater{}} elements as well as \code{\textless{}computed\_vector\textgreater{}} and \code{\textless{}noise\_vector\textgreater{}} elements.
+
+\item {} 
+\code{includes/}: C++ header and sources files used by the generated simulations.
+
+\item {} \begin{description}
+\item[{\code{support/}: Support files}] \leavevmode\begin{itemize}
+\item {} 
+\code{wscript}: \code{waf} build script for configuring and compiling generated simulations
+
+\item {} 
+\code{xpdeint.rnc}: Compact RelaxNG XML validation for XMDS scripts.  This is the source file for the XML RelaxNG file \code{xpdeint.rng}
+
+\item {} 
+\code{xpdeint.rng}: RelaxNG XML validation for XMDS scripts.  To regenerate this file from \code{xpdeint.rnc}, just run \code{make} in this directory.
+
+\end{itemize}
+
+\end{description}
+
+\item {} 
+\code{waf/}: Our included version of the Python configuration and build tool \code{waf}.
+
+\item {} 
+\code{waf\_extensions/}: \code{waf} tool for compiling Cheetah templates.
+
+\item {} 
+\code{xsil2graphics2/}: Templates for the output formats supported by \code{xsil2graphics2}.
+
+\item {} 
+\code{wscript}: \code{waf} build script for XMDS2 itself.
+
+\item {} 
+\code{CodeParser.py}: Minimally parses included C++ code for handling nonlocal dimension access, IP/EX operators and IP operator validation.
+
+\item {} 
+\code{Configuration.py}: Manages configuration and building of generated simulations.
+
+\item {} 
+\code{FriendlyPlusStyle.py}: Sphinx plug-in to improve formatting of XMDS scripts in user documentation.
+
+\item {} 
+This directory also contains code for the input script parser, code blocks, code indentation, and the root \code{\_ScriptElement} class.
+
+\end{itemize}
+
+\end{description}
+
+\end{itemize}
+
+
+\subsection{Support files}
+\label{developer:support-files}\begin{itemize}
+\item {} \begin{description}
+\item[{\code{admin/}: Documentation source, Linux installer and release scripts.}] \leavevmode\begin{itemize}
+\item {} 
+\code{developer-doc-source/}: source for epydoc python class documentation (generated from python code).
+
+\item {} 
+\code{userdoc-source/}: source for the user documentation (results visible at www.xmds.org and xmds2.readthedocs.org).
+
+\item {} 
+\code{xpdeint.tmbundle/}: TextMate support bundle for Cheetah templates and XMDS scripts
+
+\end{itemize}
+
+\end{description}
+
+\item {} 
+\code{bin/}: Executable scripts to be installed as part of XMDS2 (includes \code{xmds2} and \code{xsil2graphics2}).
+
+\item {} 
+\code{examples/}: Example XMDS2 input scripts demonstrating most of XMDS2's features.
+
+\item {} 
+\code{testsuite/}: Testsuite of XMDS2 scripts.  Run the testsuite by executing \code{./run\_tests.py}
+
+\end{itemize}
+
+
+\chapter{Licensing}
+\label{licensing::doc}\label{licensing:licensing}\label{licensing:id1}
+XMDS2 is licensed under the GPL version 2 license, which can be found in the COPYING file in the root directory of your XMDS install. You can also find it here: \href{http://www.gnu.org/licenses/}{http://www.gnu.org/licenses/}
+
+We encourage people to submit patches to us that extend XMDS2's functionality and fix bugs. If you do send us a patch, we do not require copyright assignment, but please include a statement saying you agree to license your code under the GPL v2 license.
+
+
+\chapter{News}
+\label{news:news}\label{news::doc}\label{news:id1}
+
+\section{XMDS 2.1.4 ``Well if this isn't nice, I don't know what is'' (September 27, 2013)}
+\label{news:xmds-2-1-4-well-if-this-isn-t-nice-i-don-t-know-what-is-september-27-2013}
+The XMDS 2.1.4 update contains many new improvements and bugfixes:
+\begin{itemize}
+\item {} 
+\emph{xsil2graphics2} now supports all output formats for MATLAB, Octave and Python.  The scripts generated for MATLAB/Octave are compatible with both.
+
+\item {} 
+Fix a bug when {\hyperref[reference_elements:referencingnonlocal]{\emph{nonlocally}}} referencing a {\hyperref[advanced_topics:dimensionaliases]{\emph{dimension alias}}} with subsampling in \emph{sampling\_group} blocks or in some situations when MPI is used.  This bug caused incorrect elements of the vector to be accessed.
+
+\item {} 
+Correct the Fourier basis for dimensions using Hermite-Gauss transforms.  Previously `kx' was effectively behaving as `-kx'.
+
+\item {} 
+Improve the performance of `nx' \textless{}--\textgreater{} `kx' Hermite-Gauss transforms.
+
+\item {} 
+Stochastic error checking with runtime noise generation now works correctly.  Previously different random numbers were generated for the full-step paths and the half-step paths.
+
+\item {} 
+Documentation updates.
+
+\end{itemize}
+
+
+\section{XMDS 2.1.3 ``Happy Mollusc'' (June 7, 2013)}
+\label{news:xmds-2-1-3-happy-mollusc-june-7-2013}
+The XMDS 2.1.3 update is a bugfix release that includes the following improvements:
+\begin{itemize}
+\item {} 
+XMDS will work when MPI isn't installed (but only for single-process simulations).
+
+\item {} 
+Support for GCC 4.8
+
+\item {} 
+The number of paths used by the multi-path driver can now be specified at run-time (using \emph{\textless{}validation kind=''run-time''\textgreater{}})
+
+\item {} 
+Other bug fixes
+
+\end{itemize}
+
+
+\section{XMDS 2.1.2 ``Happy Mollusc'' (October 15, 2012)}
+\label{news:xmds-2-1-2-happy-mollusc-october-15-2012}
+The XMDS 2.1.2 update has many improvements:
+\begin{itemize}
+\item {} 
+Named filters.  You can now specify a name for a filter block and call it like a function if you need to execute it conditionally.  See the documentation for the \emph{\textless{}filter\textgreater{}} block for more information.
+
+\item {} 
+New \emph{chunked\_output} feature.  XMDS can now output simulation results as it goes, reducing the memory requirement for simulations that generate significant amounts of output.  See the documentation for more details.
+
+\item {} 
+Improved OpenMP support
+
+\item {} 
+The EX operator is now faster in the common case (but you should still prefer IP when possible)
+
+\item {} 
+If seeds are not provided for a \emph{noise\_vector}, they are now generated at simulation run-time, so different executions will give different results.  The generated noises can still be found in the output .xsil files enabling results to be reproduced if desired.
+
+\item {} 
+Advanced feature: Dimensions can be accessed non-locally with the index of the lattice point.  This removes the need in hacks to manually access XMDS's underlying C arrays.  This is an advanced feature and requires a little knowledge of XMDS's internal grid representation.  See the advanced topics documentation for further details.
+
+\item {} 
+Fixed adaptive integrator order when noises were used in vector initialisation
+
+\item {} 
+Fix the Spherical Bessel basis.  There were errors in the definition of this basis which made it previously unreliable.
+
+\item {} 
+Other bug fixes
+
+\end{itemize}
+
+
+\section{XMDS 2.1 ``Happy Mollusc'' (June 14, 2012)}
+\label{news:xmds-2-1-happy-mollusc-june-14-2012}
+XMDS 2.1 is a significant upgrade with many improvements and bug fixes since 2.0. We also now have installers for Linux and Mac OS X, so you no longer have to build XMDS from source! See {\hyperref[installation:installation]{\emph{here}}} for details about the installers.
+
+Existing users should note that this release introduces a more concise syntax for moment groups.  You can now use:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}sampling\PYGZus{}group} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}x y z\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+    ...
+\PYG{n+nt}{\PYGZlt{}/sampling\PYGZus{}group\PYGZgt{}}
+\end{Verbatim}
+
+Instead of:
+
+\begin{Verbatim}[commandchars=\\\{\}]
+\PYG{n+nt}{\PYGZlt{}group}\PYG{n+nt}{\PYGZgt{}}
+    \PYG{n+nt}{\PYGZlt{}sampling} \PYG{n+na}{initial\PYGZus{}sample=}\PYG{l+s}{\PYGZdq{}yes\PYGZdq{}} \PYG{n+na}{basis=}\PYG{l+s}{\PYGZdq{}x y z\PYGZdq{}}\PYG{n+nt}{\PYGZgt{}}
+        ...
+    \PYG{n+nt}{\PYGZlt{}/sampling\PYGZgt{}}
+\PYG{n+nt}{\PYGZlt{}/group\PYGZgt{}}
+\end{Verbatim}
+
+Another syntax change is that the initial basis of a vector should be specified with \emph{initial\_basis} instead of \emph{initial\_space}.
+
+In both cases, although the old syntax is not described in the documentation, it is still supported, so existing scripts will work without any changes.
+
+Other changes in XMDS 2.1 include:
+\begin{itemize}
+\item {} 
+The \emph{lattice} attribute for dimensions can now be specified at run-time.  Previously only the minimum and maximum values of the domain could be specified at run-time.  See {\hyperref[reference_elements:validation]{\emph{here}}} for details.
+
+\item {} 
+\emph{noise\_vectors} can now be used in non-uniform dimensions (e.g. dimensions using the Bessel transform for cylindrical symmetry).
+
+\item {} 
+``loose'' \emph{geometry\_matching\_mode} for HDF5 vector initialisation.  This enables extending the simulation grid from one simulation to the next, or coarsening or refining a grid when importing.
+
+\item {} 
+\emph{vectors} can now be initialised by integrating over dimensions of other vectors.  \emph{computed\_vectors} always supported this, now \emph{vectors} do too.
+
+\item {} 
+Update to latest version of waf, which is used for compiling simulations and detecting FFTW, HDF5, etc. This should lead to fewer waf-related problems.
+
+\item {} 
+Bug fixes.
+
+\end{itemize}
+
+
+\section{XMDS 2.0 ``Shiny!'' (September 13, 2010)}
+\label{news:xmds-2-0-shiny-september-13-2010}
+XMDS 2.0 is a major upgrade which has been rewritten from the ground up to make it easier for us to apply new features. And there are many. XMDS 2.0 is faster and far more versatile than previous versions, allowing the efficient integration of almost any initial value problem on regular domains.
+
+The feature list includes:
+\begin{itemize}
+\item {} 
+Quantities of different dimensionalities. So you can have a 1D potential and a 3D wavefunction.
+
+\item {} 
+Integrate more than one vector (in more than one geometry), so you can now simultaneously integrate a PDE and a coupled ODE (or coupled PDEs of different dimensions).
+
+\item {} 
+Non-Fourier transformations including the Bessel basis, Spherical Bessel basis and the Hermite-Gauss (harmonic oscillator) basis.
+
+\item {} 
+The ability to have more than one kind of noise (gaussian, poissonian, etc) in a simulation.
+
+\item {} 
+Integer-valued dimensions with non-local access. You can have an array of variables and access different elements of that array.
+
+\item {} 
+Significantly better error reporting. When errors are found when compiling the script they will almost always be reported with the corresponding line of your script, instead of the generated source.
+
+\item {} 
+\emph{IP}/\emph{EX} operators are separate from the integration algorithm, so you can have both \emph{IP} and \emph{EX} operators in a single integrate block. Also, \emph{EX} operators can act on arbitrary code, not just vector components. (e.g. \emph{L{[}phi*phi{]}}).
+
+\item {} 
+Cross propagation in the increasing direction of a given dimension or in the decreasing dimension. And you can have more than one cross-propagator in a given integrator (going in different directions or dimensions).
+
+\item {} 
+Faster Gaussian noises.
+
+\item {} 
+The ability to calculate spatial correlation functions.
+
+\item {} 
+OpenMP support.
+
+\item {} 
+MPI support.
+
+\item {} 
+Output moment groups use less memory when there isn't a \emph{post\_processing} element.
+
+\item {} 
+Generated source is indented correctly.
+
+\item {} 
+An \emph{xmds1}-like script file format.
+
+\item {} 
+\emph{xmds1}-like generated source.
+
+\item {} 
+All of the integrators from \emph{xmds1} (\emph{SI}, \emph{RK4}, \emph{ARK45}, \emph{RK9}, \emph{ARK89}).
+
+\end{itemize}
+
+
+
+\renewcommand{\indexname}{Index}
+\printindex
+\end{document}
diff --git a/documentation/latex/xmds2.toc b/documentation/latex/xmds2.toc
new file mode 100644
index 0000000..67b0e72
--- /dev/null
+++ b/documentation/latex/xmds2.toc
@@ -0,0 +1,128 @@
+\select at language {english}
+\contentsline {chapter}{\numberline {1}Introduction}{1}{chapter.1}
+\contentsline {chapter}{\numberline {2}Installation}{3}{chapter.2}
+\contentsline {section}{\numberline {2.1}Installers}{3}{section.2.1}
+\contentsline {section}{\numberline {2.2}Linux installer instructions}{3}{section.2.2}
+\contentsline {section}{\numberline {2.3}Mac OS X Installation}{4}{section.2.3}
+\contentsline {subsection}{\numberline {2.3.1}Download}{4}{subsection.2.3.1}
+\contentsline {subsection}{\numberline {2.3.2}Using the Mac OS X Installer}{4}{subsection.2.3.2}
+\contentsline {section}{\numberline {2.4}Manual installation from source}{4}{section.2.4}
+\contentsline {chapter}{\numberline {3}Quickstart Tutorial}{9}{chapter.3}
+\contentsline {chapter}{\numberline {4}Worked Examples}{15}{chapter.4}
+\contentsline {section}{\numberline {4.1}The nonlinear Schr\IeC {\"o}dinger equation}{15}{section.4.1}
+\contentsline {section}{\numberline {4.2}Kubo Oscillator}{19}{section.4.2}
+\contentsline {section}{\numberline {4.3}Fibre Noise}{21}{section.4.3}
+\contentsline {section}{\numberline {4.4}Integer Dimensions}{25}{section.4.4}
+\contentsline {section}{\numberline {4.5}Wigner Function}{28}{section.4.5}
+\contentsline {section}{\numberline {4.6}Finding the Ground State of a BEC (continuous renormalisation)}{31}{section.4.6}
+\contentsline {section}{\numberline {4.7}Finding the Ground State of a BEC again}{35}{section.4.7}
+\contentsline {section}{\numberline {4.8}Multi-component Schr\IeC {\"o}dinger equation}{39}{section.4.8}
+\contentsline {chapter}{\numberline {5}Reference section}{43}{chapter.5}
+\contentsline {section}{\numberline {5.1}Configuration, installation and runtime options}{43}{section.5.1}
+\contentsline {section}{\numberline {5.2}Useful XML Syntax}{44}{section.5.2}
+\contentsline {section}{\numberline {5.3}XMDS2 XML Schema}{44}{section.5.3}
+\contentsline {section}{\numberline {5.4}XMDS2 script elements}{46}{section.5.4}
+\contentsline {subsection}{\numberline {5.4.1}Simulation element}{47}{subsection.5.4.1}
+\contentsline {subsection}{\numberline {5.4.2}Name element}{47}{subsection.5.4.2}
+\contentsline {subsection}{\numberline {5.4.3}Author element}{47}{subsection.5.4.3}
+\contentsline {subsection}{\numberline {5.4.4}Description element}{47}{subsection.5.4.4}
+\contentsline {subsection}{\numberline {5.4.5}Features Elements}{47}{subsection.5.4.5}
+\contentsline {subsubsection}{Arguments Element}{48}{subsubsection*.5}
+\contentsline {paragraph}{Argument element}{49}{paragraph*.6}
+\contentsline {subsubsection}{Auto\_vectorise element}{49}{subsubsection*.7}
+\contentsline {subsubsection}{Benchmark}{49}{subsubsection*.8}
+\contentsline {subsubsection}{Bing}{49}{subsubsection*.9}
+\contentsline {subsubsection}{C Flags}{49}{subsubsection*.10}
+\contentsline {subsubsection}{Chunked Output}{49}{subsubsection*.11}
+\contentsline {subsubsection}{Diagnostics}{50}{subsubsection*.12}
+\contentsline {subsubsection}{Error Check}{50}{subsubsection*.13}
+\contentsline {subsubsection}{Halt\_Non\_Finite}{50}{subsubsection*.14}
+\contentsline {subsubsection}{fftw element}{50}{subsubsection*.15}
+\contentsline {subsubsection}{Globals}{51}{subsubsection*.16}
+\contentsline {subsubsection}{OpenMP}{51}{subsubsection*.17}
+\contentsline {subsubsection}{Precision}{51}{subsubsection*.18}
+\contentsline {subsubsection}{Validation}{52}{subsubsection*.19}
+\contentsline {subsection}{\numberline {5.4.6}Driver Element}{52}{subsection.5.4.6}
+\contentsline {subsection}{\numberline {5.4.7}Geometry Element}{53}{subsection.5.4.7}
+\contentsline {subsubsection}{The ``dft'' transform}{54}{subsubsection*.24}
+\contentsline {subsubsection}{The ``dct'' transform}{55}{subsubsection*.25}
+\contentsline {subsubsection}{The ``dst'' transform}{55}{subsubsection*.26}
+\contentsline {subsubsection}{The ``bessel'' transform}{56}{subsubsection*.27}
+\contentsline {subsubsection}{The ``spherical-bessel'' transform}{57}{subsubsection*.28}
+\contentsline {subsubsection}{The ``hermite-gauss'' transform}{58}{subsubsection*.29}
+\contentsline {subsection}{\numberline {5.4.8}Vector Element}{59}{subsection.5.4.8}
+\contentsline {subsubsection}{The dependencies element}{60}{subsubsection*.34}
+\contentsline {subsection}{\numberline {5.4.9}Computed Vector Element}{61}{subsection.5.4.9}
+\contentsline {subsection}{\numberline {5.4.10}Noise Vector Element}{62}{subsection.5.4.10}
+\contentsline {subsubsection}{Uniform noise}{63}{subsubsection*.36}
+\contentsline {subsubsection}{Gaussian noise}{63}{subsubsection*.37}
+\contentsline {subsubsection}{Wiener noise}{64}{subsubsection*.38}
+\contentsline {subsubsection}{Poissonian noise}{64}{subsubsection*.39}
+\contentsline {subsubsection}{Jump noise}{64}{subsubsection*.40}
+\contentsline {subsection}{\numberline {5.4.11}Sequence Element}{65}{subsection.5.4.11}
+\contentsline {subsection}{\numberline {5.4.12}Filter element}{65}{subsection.5.4.12}
+\contentsline {subsection}{\numberline {5.4.13}Integrate element}{66}{subsection.5.4.13}
+\contentsline {subsubsection}{Operators and operator elements}{67}{subsubsection*.42}
+\contentsline {subsubsection}{Algorithms}{68}{subsubsection*.47}
+\contentsline {paragraph}{SI and SIC algorithms}{69}{paragraph*.48}
+\contentsline {paragraph}{Runge-Kutta algorithms}{69}{paragraph*.49}
+\contentsline {paragraph}{Adaptive Runge-Kutta algorithms}{69}{paragraph*.50}
+\contentsline {subsubsection}{Filters element}{70}{subsubsection*.51}
+\contentsline {subsection}{\numberline {5.4.14}Breakpoint element}{70}{subsection.5.4.14}
+\contentsline {subsection}{\numberline {5.4.15}Output element}{71}{subsection.5.4.15}
+\contentsline {subsubsection}{Sampling Group Element}{71}{subsubsection*.52}
+\contentsline {subsection}{\numberline {5.4.16}XMDS-specific C syntax}{72}{subsection.5.4.16}
+\contentsline {chapter}{\numberline {6}Advanced Topics}{73}{chapter.6}
+\contentsline {section}{\numberline {6.1}Importing data}{73}{section.6.1}
+\contentsline {section}{\numberline {6.2}Convolutions and Fourier transforms}{75}{section.6.2}
+\contentsline {subsection}{\numberline {6.2.1}Example 1}{76}{subsection.6.2.1}
+\contentsline {subsection}{\numberline {6.2.2}Example 2}{77}{subsection.6.2.2}
+\contentsline {subsection}{\numberline {6.2.3}Example 3}{77}{subsection.6.2.3}
+\contentsline {section}{\numberline {6.3}`Loose' \texttt {geometry\_matching\_mode}}{78}{section.6.3}
+\contentsline {section}{\numberline {6.4}Dimension aliases}{78}{section.6.4}
+\contentsline {chapter}{\numberline {7}Frequently Asked Questions}{79}{chapter.7}
+\contentsline {section}{\numberline {7.1}XMDS scripts look complicated! How do I start?}{79}{section.7.1}
+\contentsline {section}{\numberline {7.2}Where can I get help?}{79}{section.7.2}
+\contentsline {section}{\numberline {7.3}How should I cite XMDS2?}{79}{section.7.3}
+\contentsline {section}{\numberline {7.4}I think I found a bug! Where should I report it?}{79}{section.7.4}
+\contentsline {section}{\numberline {7.5}How do I put time dependence into my vectors?}{79}{section.7.5}
+\contentsline {section}{\numberline {7.6}Can I specify the range of my domain and number of grid points at run-time?}{80}{section.7.6}
+\contentsline {section}{\numberline {7.7}When can I use IP operators (and why should I) and when must I use EX operators?}{80}{section.7.7}
+\contentsline {section}{\numberline {7.8}Visual Editors}{80}{section.7.8}
+\contentsline {chapter}{\numberline {8}Upgrading From XMDS 1.X}{81}{chapter.8}
+\contentsline {chapter}{\numberline {9}Optimisation Hints}{83}{chapter.9}
+\contentsline {section}{\numberline {9.1}Geometry and transform-based tricks}{83}{section.9.1}
+\contentsline {subsection}{\numberline {9.1.1}Simpler simulation geometries}{83}{subsection.9.1.1}
+\contentsline {subsection}{\numberline {9.1.2}Tricks for Bessel and Hermite-Gauss transforms}{83}{subsection.9.1.2}
+\contentsline {section}{\numberline {9.2}Reduce code complexity}{83}{section.9.2}
+\contentsline {subsection}{\numberline {9.2.1}Use the Interaction Picture (IP) operator}{83}{subsection.9.2.1}
+\contentsline {subsection}{\numberline {9.2.2}Consider writing the evolution in spectral basis}{83}{subsection.9.2.2}
+\contentsline {subsection}{\numberline {9.2.3}Don't recalculate things you don't have to}{85}{subsection.9.2.3}
+\contentsline {section}{\numberline {9.3}Compiler and library tricks}{85}{section.9.3}
+\contentsline {subsection}{\numberline {9.3.1}Faster compiler}{85}{subsection.9.3.1}
+\contentsline {subsection}{\numberline {9.3.2}Faster libraries}{85}{subsection.9.3.2}
+\contentsline {subsection}{\numberline {9.3.3}Auto-vectorisation}{85}{subsection.9.3.3}
+\contentsline {subsection}{\numberline {9.3.4}OpenMP}{85}{subsection.9.3.4}
+\contentsline {subsection}{\numberline {9.3.5}Parallelisation with MPI}{86}{subsection.9.3.5}
+\contentsline {section}{\numberline {9.4}Atom-optics-specific hints}{86}{section.9.4}
+\contentsline {subsection}{\numberline {9.4.1}Separate out imaginary-time calculation code}{86}{subsection.9.4.1}
+\contentsline {subsection}{\numberline {9.4.2}Use an energy or momentum offset}{86}{subsection.9.4.2}
+\contentsline {chapter}{\numberline {10}xsil2graphics2}{87}{chapter.10}
+\contentsline {chapter}{\numberline {11}Developer Documentation}{89}{chapter.11}
+\contentsline {section}{\numberline {11.1}Test scripts}{89}{section.11.1}
+\contentsline {subsection}{\numberline {11.1.1}Testing element}{90}{subsection.11.1.1}
+\contentsline {subsection}{\numberline {11.1.2}command\_line element}{90}{subsection.11.1.2}
+\contentsline {subsection}{\numberline {11.1.3}input\_xsil\_file element}{90}{subsection.11.1.3}
+\contentsline {subsection}{\numberline {11.1.4}xsil\_file element}{90}{subsection.11.1.4}
+\contentsline {subsection}{\numberline {11.1.5}moment\_group element}{90}{subsection.11.1.5}
+\contentsline {section}{\numberline {11.2}Steps to update \texttt {XMDS} script validator (XML schema)}{90}{section.11.2}
+\contentsline {section}{\numberline {11.3}Directory layout}{90}{section.11.3}
+\contentsline {subsection}{\numberline {11.3.1}XMDS2's code and templates}{90}{subsection.11.3.1}
+\contentsline {subsection}{\numberline {11.3.2}Support files}{91}{subsection.11.3.2}
+\contentsline {chapter}{\numberline {12}Licensing}{93}{chapter.12}
+\contentsline {chapter}{\numberline {13}News}{95}{chapter.13}
+\contentsline {section}{\numberline {13.1}XMDS 2.1.4 ``Well if this isn't nice, I don't know what is'' (September 27, 2013)}{95}{section.13.1}
+\contentsline {section}{\numberline {13.2}XMDS 2.1.3 ``Happy Mollusc'' (June 7, 2013)}{95}{section.13.2}
+\contentsline {section}{\numberline {13.3}XMDS 2.1.2 ``Happy Mollusc'' (October 15, 2012)}{95}{section.13.3}
+\contentsline {section}{\numberline {13.4}XMDS 2.1 ``Happy Mollusc'' (June 14, 2012)}{96}{section.13.4}
+\contentsline {section}{\numberline {13.5}XMDS 2.0 ``Shiny!'' (September 13, 2010)}{97}{section.13.5}
diff --git a/documentation/latex/xmds_logo.pdf b/documentation/latex/xmds_logo.pdf
new file mode 100644
index 0000000..465ba25
Binary files /dev/null and b/documentation/latex/xmds_logo.pdf differ
diff --git a/documentation/licensing.html b/documentation/licensing.html
new file mode 100644
index 0000000..d4ecb47
--- /dev/null
+++ b/documentation/licensing.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>Licensing — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="index.html" /> 
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+  <div class="section" id="licensing">
+<span id="id1"></span><h1>Licensing<a class="headerlink" href="#licensing" title="Permalink to this headline">¶</a></h1>
+<p>XMDS2 is licensed under the GPL version 2 license, which can be found in the COPYING file in the root directory of your XMDS install. You can also find it here: <a class="reference external" href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a></p>
+<p>We encourage people to submit patches to us that extend XMDS2’s functionality and fix bugs. If you do send us a patch, we do not require copyright assignment, but please include a statement saying you agree to license your code under the GPL v2 license.</p>
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="index.html">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+<div id="searchbox" style="display: none">
+  <h3>Quick search</h3>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" />
+      <input type="submit" value="Go" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    <p class="searchtip" style="font-size: 90%">
+    Enter search terms or a module, class or function name.
+    </p>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/documentation/news.html b/documentation/news.html
new file mode 100644
index 0000000..4f8e895
--- /dev/null
+++ b/documentation/news.html
@@ -0,0 +1,193 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>News — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="index.html" /> 
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+  <div class="section" id="news">
+<span id="id1"></span><h1>News<a class="headerlink" href="#news" title="Permalink to this headline">¶</a></h1>
+<div class="section" id="xmds-2-1-4-well-if-this-isn-t-nice-i-don-t-know-what-is-september-27-2013">
+<h2>XMDS 2.1.4 “Well if this isn’t nice, I don’t know what is” (September 27, 2013)<a class="headerlink" href="#xmds-2-1-4-well-if-this-isn-t-nice-i-don-t-know-what-is-september-27-2013" title="Permalink to this headline">¶</a></h2>
+<p>The XMDS 2.1.4 update contains many new improvements and bugfixes:</p>
+<ul class="simple">
+<li><em>xsil2graphics2</em> now supports all output formats for MATLAB, Octave and Python.  The scripts generated for MATLAB/Octave are compatible with both.</li>
+<li>Fix a bug when <a class="reference internal" href="reference_elements.html#referencingnonlocal"><em>nonlocally</em></a> referencing a <a class="reference internal" href="advanced_topics.html#dimensionaliases"><em>dimension alias</em></a> with subsampling in <em>sampling_group</em> blocks or in some situations when MPI is used.  This bug caused incorrect elements of the vector to be accessed.</li>
+<li>Correct the Fourier basis for dimensions using Hermite-Gauss transforms.  Previously ‘kx’ was effectively behaving as ‘-kx’.</li>
+<li>Improve the performance of ‘nx’ <–> ‘kx’ Hermite-Gauss transforms.</li>
+<li>Stochastic error checking with runtime noise generation now works correctly.  Previously different random numbers were generated for the full-step paths and the half-step paths.</li>
+<li>Documentation updates.</li>
+</ul>
+</div>
+<div class="section" id="xmds-2-1-3-happy-mollusc-june-7-2013">
+<h2>XMDS 2.1.3 “Happy Mollusc” (June 7, 2013)<a class="headerlink" href="#xmds-2-1-3-happy-mollusc-june-7-2013" title="Permalink to this headline">¶</a></h2>
+<p>The XMDS 2.1.3 update is a bugfix release that includes the following improvements:</p>
+<ul class="simple">
+<li>XMDS will work when MPI isn’t installed (but only for single-process simulations).</li>
+<li>Support for GCC 4.8</li>
+<li>The number of paths used by the multi-path driver can now be specified at run-time (using <em><validation kind=”run-time”></em>)</li>
+<li>Other bug fixes</li>
+</ul>
+</div>
+<div class="section" id="xmds-2-1-2-happy-mollusc-october-15-2012">
+<h2>XMDS 2.1.2 “Happy Mollusc” (October 15, 2012)<a class="headerlink" href="#xmds-2-1-2-happy-mollusc-october-15-2012" title="Permalink to this headline">¶</a></h2>
+<p>The XMDS 2.1.2 update has many improvements:</p>
+<ul class="simple">
+<li>Named filters.  You can now specify a name for a filter block and call it like a function if you need to execute it conditionally.  See the documentation for the <em><filter></em> block for more information.</li>
+<li>New <em>chunked_output</em> feature.  XMDS can now output simulation results as it goes, reducing the memory requirement for simulations that generate significant amounts of output.  See the documentation for more details.</li>
+<li>Improved OpenMP support</li>
+<li>The EX operator is now faster in the common case (but you should still prefer IP when possible)</li>
+<li>If seeds are not provided for a <em>noise_vector</em>, they are now generated at simulation run-time, so different executions will give different results.  The generated noises can still be found in the output .xsil files enabling results to be reproduced if desired.</li>
+<li>Advanced feature: Dimensions can be accessed non-locally with the index of the lattice point.  This removes the need in hacks to manually access XMDS’s underlying C arrays.  This is an advanced feature and requires a little knowledge of XMDS’s internal grid representation.  See the advanced topics documentation for further details.</li>
+<li>Fixed adaptive integrator order when noises were used in vector initialisation</li>
+<li>Fix the Spherical Bessel basis.  There were errors in the definition of this basis which made it previously unreliable.</li>
+<li>Other bug fixes</li>
+</ul>
+</div>
+<div class="section" id="xmds-2-1-happy-mollusc-june-14-2012">
+<h2>XMDS 2.1 “Happy Mollusc” (June 14, 2012)<a class="headerlink" href="#xmds-2-1-happy-mollusc-june-14-2012" title="Permalink to this headline">¶</a></h2>
+<p>XMDS 2.1 is a significant upgrade with many improvements and bug fixes since 2.0. We also now have installers for Linux and Mac OS X, so you no longer have to build XMDS from source! See <a class="reference internal" href="installation.html#installation"><em>here</em></a> for details about the installers.</p>
+<p>Existing users should note that this release introduces a more concise syntax for moment groups.  You can now use:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><sampling_group</span> <span class="na">initial_sample=</span><span class="s">"yes"</span> <span class="na">basis=</span><span class="s">"x y z"</span><span class="nt">></span>
+    ...
+<span class="nt"></sampling_group></span>
+</pre></div>
+</div>
+<p>Instead of:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><group></span>
+    <span class="nt"><sampling</span> <span class="na">initial_sample=</span><span class="s">"yes"</span> <span class="na">basis=</span><span class="s">"x y z"</span><span class="nt">></span>
+        ...
+    <span class="nt"></sampling></span>
+<span class="nt"></group></span>
+</pre></div>
+</div>
+<p>Another syntax change is that the initial basis of a vector should be specified with <em>initial_basis</em> instead of <em>initial_space</em>.</p>
+<p>In both cases, although the old syntax is not described in the documentation, it is still supported, so existing scripts will work without any changes.</p>
+<p>Other changes in XMDS 2.1 include:</p>
+<ul class="simple">
+<li>The <em>lattice</em> attribute for dimensions can now be specified at run-time.  Previously only the minimum and maximum values of the domain could be specified at run-time.  See <a class="reference internal" href="reference_elements.html#validation"><em>here</em></a> for details.</li>
+<li><em>noise_vectors</em> can now be used in non-uniform dimensions (e.g. dimensions using the Bessel transform for cylindrical symmetry).</li>
+<li>“loose” <em>geometry_matching_mode</em> for HDF5 vector initialisation.  This enables extending the simulation grid from one simulation to the next, or coarsening or refining a grid when importing.</li>
+<li><em>vectors</em> can now be initialised by integrating over dimensions of other vectors.  <em>computed_vectors</em> always supported this, now <em>vectors</em> do too.</li>
+<li>Update to latest version of waf, which is used for compiling simulations and detecting FFTW, HDF5, etc. This should lead to fewer waf-related problems.</li>
+<li>Bug fixes.</li>
+</ul>
+</div>
+<div class="section" id="xmds-2-0-shiny-september-13-2010">
+<h2>XMDS 2.0 “Shiny!” (September 13, 2010)<a class="headerlink" href="#xmds-2-0-shiny-september-13-2010" title="Permalink to this headline">¶</a></h2>
+<p>XMDS 2.0 is a major upgrade which has been rewritten from the ground up to make it easier for us to apply new features. And there are many. XMDS 2.0 is faster and far more versatile than previous versions, allowing the efficient integration of almost any initial value problem on regular domains.</p>
+<p>The feature list includes:</p>
+<ul class="simple">
+<li>Quantities of different dimensionalities. So you can have a 1D potential and a 3D wavefunction.</li>
+<li>Integrate more than one vector (in more than one geometry), so you can now simultaneously integrate a PDE and a coupled ODE (or coupled PDEs of different dimensions).</li>
+<li>Non-Fourier transformations including the Bessel basis, Spherical Bessel basis and the Hermite-Gauss (harmonic oscillator) basis.</li>
+<li>The ability to have more than one kind of noise (gaussian, poissonian, etc) in a simulation.</li>
+<li>Integer-valued dimensions with non-local access. You can have an array of variables and access different elements of that array.</li>
+<li>Significantly better error reporting. When errors are found when compiling the script they will almost always be reported with the corresponding line of your script, instead of the generated source.</li>
+<li><em>IP</em>/<em>EX</em> operators are separate from the integration algorithm, so you can have both <em>IP</em> and <em>EX</em> operators in a single integrate block. Also, <em>EX</em> operators can act on arbitrary code, not just vector components. (e.g. <em>L[phi*phi]</em>).</li>
+<li>Cross propagation in the increasing direction of a given dimension or in the decreasing dimension. And you can have more than one cross-propagator in a given integrator (going in different directions or dimensions).</li>
+<li>Faster Gaussian noises.</li>
+<li>The ability to calculate spatial correlation functions.</li>
+<li>OpenMP support.</li>
+<li>MPI support.</li>
+<li>Output moment groups use less memory when there isn’t a <em>post_processing</em> element.</li>
+<li>Generated source is indented correctly.</li>
+<li>An <em>xmds1</em>-like script file format.</li>
+<li><em>xmds1</em>-like generated source.</li>
+<li>All of the integrators from <em>xmds1</em> (<em>SI</em>, <em>RK4</em>, <em>ARK45</em>, <em>RK9</em>, <em>ARK89</em>).</li>
+</ul>
+</div>
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="index.html">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+  <h3><a href="index.html">Table Of Contents</a></h3>
+  <ul>
+<li><a class="reference internal" href="#">News</a><ul>
+<li><a class="reference internal" href="#xmds-2-1-4-well-if-this-isn-t-nice-i-don-t-know-what-is-september-27-2013">XMDS 2.1.4 “Well if this isn’t nice, I don’t know what is” (September 27, 2013)</a></li>
+<li><a class="reference internal" href="#xmds-2-1-3-happy-mollusc-june-7-2013">XMDS 2.1.3 “Happy Mollusc” (June 7, 2013)</a></li>
+<li><a class="reference internal" href="#xmds-2-1-2-happy-mollusc-october-15-2012">XMDS 2.1.2 “Happy Mollusc” (October 15, 2012)</a></li>
+<li><a class="reference internal" href="#xmds-2-1-happy-mollusc-june-14-2012">XMDS 2.1 “Happy Mollusc” (June 14, 2012)</a></li>
+<li><a class="reference internal" href="#xmds-2-0-shiny-september-13-2010">XMDS 2.0 “Shiny!” (September 13, 2010)</a></li>
+</ul>
+</li>
+</ul>
+
+<div id="searchbox" style="display: none">
+  <h3>Quick search</h3>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" />
+      <input type="submit" value="Go" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    <p class="searchtip" style="font-size: 90%">
+    Enter search terms or a module, class or function name.
+    </p>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/documentation/objects.inv b/documentation/objects.inv
new file mode 100644
index 0000000..f80b0e8
Binary files /dev/null and b/documentation/objects.inv differ
diff --git a/documentation/optimisation_hints.html b/documentation/optimisation_hints.html
new file mode 100644
index 0000000..2700258
--- /dev/null
+++ b/documentation/optimisation_hints.html
@@ -0,0 +1,262 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>Optimisation Hints — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="index.html" /> 
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+  <div class="section" id="optimisation-hints">
+<h1>Optimisation Hints<a class="headerlink" href="#optimisation-hints" title="Permalink to this headline">¶</a></h1>
+<p>There are a variety of things you can do to make your simulations run faster.</p>
+<div class="section" id="geometry-and-transform-based-tricks">
+<h2>Geometry and transform-based tricks<a class="headerlink" href="#geometry-and-transform-based-tricks" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="simpler-simulation-geometries">
+<h3>Simpler simulation geometries<a class="headerlink" href="#simpler-simulation-geometries" title="Permalink to this headline">¶</a></h3>
+<p>Consider symmetry, can you use <tt class="docutils literal"><span class="pre">dct</span></tt> transforms or <tt class="docutils literal"><span class="pre">bessel</span></tt> transforms? Do you really need that many points? How big does your grid need to be? Could absorbing boundary conditions help?</p>
+</div>
+<div class="section" id="tricks-for-bessel-and-hermite-gauss-transforms">
+<h3>Tricks for Bessel and Hermite-Gauss transforms<a class="headerlink" href="#tricks-for-bessel-and-hermite-gauss-transforms" title="Permalink to this headline">¶</a></h3>
+<p>Dimensions using matrix transforms should be first for performance reasons.  Unless you’re using MPI, in which case XMDS can work it out for the first two dimensions.  Ideally, XMDS would sort it out in all cases, but it’s not that smart yet.</p>
+</div>
+</div>
+<div class="section" id="reduce-code-complexity">
+<h2>Reduce code complexity<a class="headerlink" href="#reduce-code-complexity" title="Permalink to this headline">¶</a></h2>
+<p>Avoid transcendental functions like <span class="math">\(\sin(x)\)</span> or <span class="math">\(\exp(x)\)</span> in inner loops. Not all operations are made equal, use multiplication over division.</p>
+<div class="section" id="use-the-interaction-picture-ip-operator">
+<h3>Use the Interaction Picture (IP) operator<a class="headerlink" href="#use-the-interaction-picture-ip-operator" title="Permalink to this headline">¶</a></h3>
+<p>Just do it. Only use the EX operator when you have to. If you must use the EX operator, consider making it <tt class="docutils literal"><span class="pre">constant="no"</span></tt>. It uses less memory.
+When you use the IP operator, make sure you know what it’s doing.  Do not pre- or post-multiply that term in your equations.</p>
+<p>When using the IP operator, check if your operator is purely real or purely imaginary.  If real, (e.g. <tt class="docutils literal"><span class="pre">L</span> <span class="pre">=</span> <span class="pre">-0.5*kx</span> <span class="pre">*</span> <span class="pre">kx;</span></tt>), then add the attribute <tt class="docutils literal"><span class="pre">type="real"</span></tt> to the <tt class="docutils literal"><span class="pre"><operator</span> <span class="pre">kind=" [...]
+</div>
+<div class="section" id="consider-writing-the-evolution-in-spectral-basis">
+<h3>Consider writing the evolution in spectral basis<a class="headerlink" href="#consider-writing-the-evolution-in-spectral-basis" title="Permalink to this headline">¶</a></h3>
+<p>Evolution equations do not need to be written in the position basis.  If your equations are diagonal in the spectral basis, then it makes more sense to compute the time derivative terms in that basis.  For example, if you have the system</p>
+<div class="math">
+\[\begin{split}\frac{d\psi_1(x)}{dt} &= i \frac{\hbar}{2M} \frac{d^2\psi_1(x)}{dx^2} - i \Omega \psi_2(x)\\
+\frac{d\psi_2(x)}{dt} &= i \frac{\hbar}{2M} \frac{d^2\psi_2(x)}{dx^2} - i \Omega \psi_1(x)\end{split}\]</div>
+<p>then this is diagonal in the Fourier basis where it takes the form</p>
+<div class="math">
+\[\begin{split}\frac{d\psi_1(k_x)}{dt} &= -i \frac{\hbar k_x^2}{2M} \psi_1(k_x) - i \Omega \psi_2(k_x)\\
+\frac{d\psi_2(k_x)}{dt} &= -i \frac{\hbar k_x^2}{2M} \psi_2(k_x) - i \Omega \psi_1(k_x)\end{split}\]</div>
+<p>The first term in each evolution equation can be solved exactly with an IP operator, and the second term is diagonal in Fourier space.  This can be written in XMDS as:</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><operators></span>
+  <span class="nt"><integration_vectors</span> <span class="na">basis=</span><span class="s">"kx"</span><span class="nt">></span>wavefunction<span class="nt"></integration_vectors></span>
+  <span class="nt"><operator</span> <span class="na">kind=</span><span class="s">"ip"</span> <span class="na">type=</span><span class="s">"imaginary"</span> <span class="nt">></span>
+    <span class="nt"><operator_names></span>Lxx<span class="nt"></operator_names></span>
+    <span class="cp"><![CDATA[</span>
+      <span class="n">Lxx</span> <span class="o">=</span> <span class="o">-</span><span class="kc">i</span><span class="o">*</span><span class="mf">0.5</span><span class="o">*</span><span class="n">hbar_M</span><span class="o">*</span><span class="p">(</span><span class="n">kx</span><span class="o">*</span><span class="n">kx</span><span class="p">);</span>
+    <span class="cp">]]></span>
+  <span class="nt"></operator></span>
+  <span class="cp"><![CDATA[</span>
+
+    <span class="n">dpsi0_dt</span> <span class="o">=</span> <span class="n">Lxx</span><span class="p">[</span><span class="n">psi0</span><span class="p">]</span> <span class="o">-</span> <span class="kc">i</span><span class="o">*</span><span class="n">Omega</span><span class="o">*</span><span class="n">psi1</span><span class="p">;</span>
+    <span class="n">dpsi1_dt</span> <span class="o">=</span> <span class="n">Lxx</span><span class="p">[</span><span class="n">psi1</span><span class="p">]</span> <span class="o">-</span> <span class="kc">i</span><span class="o">*</span><span class="n">Omega</span><span class="o">*</span><span class="n">psi0</span><span class="p">;</span>
+
+  <span class="cp">]]></span>
+<span class="nt"></operators></span>
+</pre></div>
+</div>
+<p>Although the <tt class="docutils literal"><span class="pre">dpsi0_dt</span></tt> code reads the same in position and Fourier space, it is the <tt class="docutils literal"><span class="pre">basis=kx</span></tt> attribute on <tt class="docutils literal"><span class="pre"><integration_vectors></span></tt> that causes the evolution code to be executed in Fourier space.</p>
+<p>A final optimisation is to cause the integration code itself to operate in Fourier space.  By default, all time stepping (i.e. <span class="math">\(f(t + \Delta t) = f(t) + f'(t) \Delta t\)</span> for forward-Euler integration) occurs in the position space.  As the derivative terms can be computed in Fourier space, it is faster to also to the time stepping in Fourier space too.  This then means that no Fourier transforms will be needed at all during this integrate block (except as nee [...]
+<p>The fully optimised code then reads:</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><integrate</span> <span class="na">algorithm=</span><span class="s">"ARK45"</span> <span class="na">interval=</span><span class="s">"1"</span> <span class="na">tolerance=</span><span class="s">"1e-6"</span> <span class="na">home_space=</span><span class="s">"k"</span><span class="nt">></span>
+  <span class="nt"><samples></span> 10 <span class="nt"></samples></span>
+  <span class="nt"><operators></span>
+    <span class="nt"><integration_vectors</span> <span class="na">basis=</span><span class="s">"kx"</span><span class="nt">></span>wavefunction<span class="nt"></integration_vectors></span>
+    <span class="nt"><operator</span> <span class="na">kind=</span><span class="s">"ip"</span> <span class="na">type=</span><span class="s">"imaginary"</span> <span class="nt">></span>
+      <span class="nt"><operator_names></span>Lxx<span class="nt"></operator_names></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">Lxx</span> <span class="o">=</span> <span class="o">-</span><span class="kc">i</span><span class="o">*</span><span class="mf">0.5</span><span class="o">*</span><span class="n">hbar_M</span><span class="o">*</span><span class="p">(</span><span class="n">kx</span><span class="o">*</span><span class="n">kx</span><span class="p">);</span>
+      <span class="cp">]]></span>
+    <span class="nt"></operator></span>
+    <span class="cp"><![CDATA[</span>
+
+      <span class="n">dpsi0_dt</span> <span class="o">=</span> <span class="n">Lxx</span><span class="p">[</span><span class="n">psi0</span><span class="p">]</span> <span class="o">-</span> <span class="kc">i</span><span class="o">*</span><span class="n">Omega</span><span class="o">*</span><span class="n">psi1</span><span class="p">;</span>
+      <span class="n">dpsi1_dt</span> <span class="o">=</span> <span class="n">Lxx</span><span class="p">[</span><span class="n">psi1</span><span class="p">]</span> <span class="o">-</span> <span class="kc">i</span><span class="o">*</span><span class="n">Omega</span><span class="o">*</span><span class="n">psi0</span><span class="p">;</span>
+
+    <span class="cp">]]></span>
+  <span class="nt"></operators></span>
+<span class="nt"></integrate></span>
+</pre></div>
+</div>
+<p>This code will not use any Fourier transforms during an ordinary time-stepping, and will be much faster than if the code were written without the <tt class="docutils literal"><span class="pre">home_space</span></tt> and <tt class="docutils literal"><span class="pre">basis</span></tt> attributes.</p>
+</div>
+<div class="section" id="don-t-recalculate-things-you-don-t-have-to">
+<h3>Don’t recalculate things you don’t have to<a class="headerlink" href="#don-t-recalculate-things-you-don-t-have-to" title="Permalink to this headline">¶</a></h3>
+<p>Use <tt class="docutils literal"><span class="pre">computed_vectors</span></tt> appropriately.</p>
+</div>
+</div>
+<div class="section" id="compiler-and-library-tricks">
+<h2>Compiler and library tricks<a class="headerlink" href="#compiler-and-library-tricks" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="faster-compiler">
+<h3>Faster compiler<a class="headerlink" href="#faster-compiler" title="Permalink to this headline">¶</a></h3>
+<p>If you’re using an Intel CPU, then you should consider using their compiler, icc. They made the silicon, and they also made a compiler that understands how their chips work significantly better than the more-portable GCC.</p>
+</div>
+<div class="section" id="faster-libraries">
+<h3>Faster libraries<a class="headerlink" href="#faster-libraries" title="Permalink to this headline">¶</a></h3>
+<p>Intel MKL is faster than ATLAS, which is faster than GSL CBLAS. If you have a Mac, then Apple’s vecLib is plenty fast.</p>
+</div>
+<div class="section" id="auto-vectorisation">
+<h3>Auto-vectorisation<a class="headerlink" href="#auto-vectorisation" title="Permalink to this headline">¶</a></h3>
+<p>Auto-vectorisation is a compiler feature that makes compilers generate more efficient code that can execute the same operation on multiple pieces of data simultaneously. To use this feature, you need to add the following to the <tt class="docutils literal"><span class="pre"><features></span></tt> block at the start of your simulation:</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><auto_vectorise</span> <span class="nt">/></span>
+</pre></div>
+</div>
+<p>This will make xpdeint generate code that is more friendly to compiler’s auto-vectorisation features so that more code can be vectorised. It will also add the appropriate compiler options to turn on your compiler’s auto-vectorisation features. For auto-vectorisation to increase the speed of your simulations, you will need a compiler that supports it such as gcc 4.2 or later, or Intel’s C compiler, <tt class="docutils literal"><span class="pre">icc</span></tt>.</p>
+</div>
+<div class="section" id="openmp">
+<h3>OpenMP<a class="headerlink" href="#openmp" title="Permalink to this headline">¶</a></h3>
+<p><a class="reference external" href="http://openmp.org">OpenMP</a> is a set of compiler directives to make it easier to use threads (different execution contexts) in programs. Using threads in your simulation does occur some overhead, so for the speedup to outweigh the overhead, you must have a reasonably large simulation grid. To add these compiler directives to the generated simulations, add the tag <tt class="docutils literal"><span class="pre"><openmp</span> <span class="pre">/& [...]
+<p>If you are using the OpenMP feature and are using <a class="reference external" href="http://www.fftw.org">FFTW</a>-based transforms (Discrete Fourier/Cosine/Sine Transforms), you should consider using threads with your FFT’s by adding the following to the <tt class="docutils literal"><span class="pre"><features></span></tt> block at the start of your simulation:</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><fftw</span> <span class="na">threads=</span><span class="s">"2"</span> <span class="nt">/></span>
+</pre></div>
+</div>
+<p>Replace the number of threads in the above code by the number of threads that you want to use.</p>
+</div>
+<div class="section" id="parallelisation-with-mpi">
+<h3>Parallelisation with MPI<a class="headerlink" href="#parallelisation-with-mpi" title="Permalink to this headline">¶</a></h3>
+<p>Some simulations are so large or take so much time that it is not reasonable to run them on a single CPU on a single machine. Fortunately, the <a class="reference external" href="http://www.mpi-forum.org/">Message Passing Interface</a> was developed to enable different computers working on the same program to exchange data. You will need a MPI package installed to be abel to use this feature with your simulations. One popular implementation of MPI is <a class="reference external" href [...]
+</div>
+</div>
+<div class="section" id="atom-optics-specific-hints">
+<h2>Atom-optics-specific hints<a class="headerlink" href="#atom-optics-specific-hints" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="separate-out-imaginary-time-calculation-code">
+<h3>Separate out imaginary-time calculation code<a class="headerlink" href="#separate-out-imaginary-time-calculation-code" title="Permalink to this headline">¶</a></h3>
+<p>When doing simulations that require the calculation of the groundstate (typically via the imaginary time algorithm), typically the groundstate itself does not need to be changed frequently as it is usually the dynamics of the simulation that have the interesting physics. In this case, you can save having to re-calculate groundstate every time by having one script (call it <tt class="docutils literal"><span class="pre">groundstate.xmds</span></tt>) that saves the calculated groundstate [...]
+<p>The file format used in this example is <a class="reference external" href="http://www.hdfgroup.org/HDF5/">HDF5</a>, and you will need the HDF5 libraries installed to use this example. The alternative is to use the deprecated <tt class="docutils literal"><span class="pre">binary</span></tt> format, however to load <tt class="docutils literal"><span class="pre">binary</span></tt> format data <tt class="docutils literal"><span class="pre">xmds</span></tt>, the predecessor to <tt class=" [...]
+<p>If your wavefunction vector is called <tt class="docutils literal"><span class="pre">'wavefunction'</span></tt>, then to save the groundstate to the file <tt class="docutils literal"><span class="pre">groundstate_break.h5</span></tt> in the HDF5 format, put the following code immediately after the integrate block that calculates your groundstate:</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><breakpoint</span> <span class="na">filename=</span><span class="s">"groundstate_break"</span> <span class="na">format=</span><span class="s">"hdf5"</span><span class="nt">></span>
+  <span class="nt"><dependencies></span>wavefunction<span class="nt"></dependencies></span>
+<span class="nt"></breakpoint></span>
+</pre></div>
+</div>
+<p>In addition to the <tt class="docutils literal"><span class="pre">groundstate_break.h5</span></tt> file, an XSIL wrapper <tt class="docutils literal"><span class="pre">groundstate_break.xsil</span></tt> will also be created for use with <a class="reference internal" href="xsil2graphics2.html#xsil2graphics2"><em>xsil2graphics2</em></a>.</p>
+<p>To load this groundstate into your evolution script, the declaration of your <tt class="docutils literal"><span class="pre">'wavefunction'</span></tt> vector in your evolution script should look something like</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><vector</span> <span class="na">name=</span><span class="s">"wavefunction"</span><span class="nt">></span>
+  <span class="nt"><components></span>phi1 phi2<span class="nt"></components></span>
+  <span class="nt"><initialisation</span> <span class="na">kind=</span><span class="s">"hdf5"</span><span class="nt">></span>
+    <span class="nt"><filename></span>groundstate_break.h5<span class="nt"></filename></span>
+  <span class="nt"></initialisation></span>
+<span class="nt"></vector></span>
+</pre></div>
+</div>
+<p>Note that the groundstate-finder doesn’t need to have all of the components that the evolution script needs. For example, if you are considering the evolution of a two-component BEC where only one component has a population in the groundstate, then your groundstate script can contain only the <tt class="docutils literal"><span class="pre">phi1</span></tt> component, while your evolution script can contain both the <tt class="docutils literal"><span class="pre">phi1</span></tt> c [...]
+</div>
+<div class="section" id="use-an-energy-or-momentum-offset">
+<h3>Use an energy or momentum offset<a class="headerlink" href="#use-an-energy-or-momentum-offset" title="Permalink to this headline">¶</a></h3>
+<p>This is just the interaction picture with a constant term in the Hamiltonian. If your state is going to rotate like <span class="math">\(e^{i(\omega + \delta\omega)t}\)</span>, then transform your equations to remove the <span class="math">\(e^{i \omega t}\)</span> term. Likewise for spatial rotations, if one mode will be moving on average with momentum <span class="math">\(\hbar k\)</span>, then transform your equations to remove that term. This way, you may be able to reduce the den [...]
+</div>
+</div>
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="index.html">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+  <h3><a href="index.html">Table Of Contents</a></h3>
+  <ul>
+<li><a class="reference internal" href="#">Optimisation Hints</a><ul>
+<li><a class="reference internal" href="#geometry-and-transform-based-tricks">Geometry and transform-based tricks</a><ul>
+<li><a class="reference internal" href="#simpler-simulation-geometries">Simpler simulation geometries</a></li>
+<li><a class="reference internal" href="#tricks-for-bessel-and-hermite-gauss-transforms">Tricks for Bessel and Hermite-Gauss transforms</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#reduce-code-complexity">Reduce code complexity</a><ul>
+<li><a class="reference internal" href="#use-the-interaction-picture-ip-operator">Use the Interaction Picture (IP) operator</a></li>
+<li><a class="reference internal" href="#consider-writing-the-evolution-in-spectral-basis">Consider writing the evolution in spectral basis</a></li>
+<li><a class="reference internal" href="#don-t-recalculate-things-you-don-t-have-to">Don’t recalculate things you don’t have to</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#compiler-and-library-tricks">Compiler and library tricks</a><ul>
+<li><a class="reference internal" href="#faster-compiler">Faster compiler</a></li>
+<li><a class="reference internal" href="#faster-libraries">Faster libraries</a></li>
+<li><a class="reference internal" href="#auto-vectorisation">Auto-vectorisation</a></li>
+<li><a class="reference internal" href="#openmp">OpenMP</a></li>
+<li><a class="reference internal" href="#parallelisation-with-mpi">Parallelisation with MPI</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#atom-optics-specific-hints">Atom-optics-specific hints</a><ul>
+<li><a class="reference internal" href="#separate-out-imaginary-time-calculation-code">Separate out imaginary-time calculation code</a></li>
+<li><a class="reference internal" href="#use-an-energy-or-momentum-offset">Use an energy or momentum offset</a></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+
+<div id="searchbox" style="display: none">
+  <h3>Quick search</h3>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" />
+      <input type="submit" value="Go" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    <p class="searchtip" style="font-size: 90%">
+    Enter search terms or a module, class or function name.
+    </p>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/documentation/reference_elements.html b/documentation/reference_elements.html
new file mode 100644
index 0000000..18853c6
--- /dev/null
+++ b/documentation/reference_elements.html
@@ -0,0 +1,1126 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>XMDS2 script elements — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="index.html" /> 
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+  <style> .attributes-code {color:#0000BB; font-family:'monospace'; font-style:italic} </style><style> .attributes-standard {color:#0000BB; font-family:'monospace'; font-style:italic; font-size:smaller} </style><style> .smaller-font {font-size:smaller} </style><div class="section" id="xmds2-script-elements">
+<span id="referenceelements"></span><h1>XMDS2 script elements<a class="headerlink" href="#xmds2-script-elements" title="Permalink to this headline">¶</a></h1>
+<p>This section outlines all the elements and options available in an XMDS2 script.  This is very much a <strong>work in progress</strong>, beginning with placeholders in most cases, as we have prioritised the tutorials for new users.  One of the most productive ways that non-developer veterans can contribute to the project is to help develop this documentation.</p>
+<div class="section" id="simulation-element">
+<span id="simulationelement"></span><h2>Simulation element<a class="headerlink" href="#simulation-element" title="Permalink to this headline">¶</a></h2>
+<p>The <tt class="docutils literal"><span class="pre"><simulation></span></tt> element is the single top level element in an XMDS2 simulation, and contains all the other elements.  All XMDS scripts must contain exactly one simulation element, and it must have the <tt class="docutils literal"><span class="pre">xmds-version="2"</span></tt> attribute defined.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="c"><!-- Rest of simulation goes here --></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="name-element">
+<span id="nameelement"></span><h2>Name element<a class="headerlink" href="#name-element" title="Permalink to this headline">¶</a></h2>
+<p>The name of your simulation. This element is optional, but recommended. If it is set, it will be the name of the executable file generated from this script. It will also be the name of the output file (with an appropriate extension) if the <tt class="docutils literal"><span class="pre">filename</span></tt> attribute is not given a value in the <tt class="docutils literal"><span class="pre"><output></span></tt> element.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><name></span> funky_solver <span class="nt"></name></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="author-element">
+<span id="authorelement"></span><h2>Author element<a class="headerlink" href="#author-element" title="Permalink to this headline">¶</a></h2>
+<p>The author(s) of this script. This element is optional, but can be useful if you need to find the person who has written an incomprehensible script and thinks comments are for the weak.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><author></span> Ima Mollusc <span class="nt"></author></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="description-element">
+<span id="descriptionelement"></span><h2>Description element<a class="headerlink" href="#description-element" title="Permalink to this headline">¶</a></h2>
+<p>A description of what the simulation does. Optional, but recommended, in case you (or someone else) has to revist the script at some distant point in the future.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><description></span>
+  Calculate the 3D ground state of a Rubidium BEC in a harmonic magnetic trap assuming
+  cylindrical symmetry about the z axis and reflection symmetry about z=0.
+  This permits us to use the cylindrical Bessel functions to expand the solution transverse
+  to z and a cosine series to expand the solution along z.
+<span class="nt"></description></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="features-elements">
+<span id="featureselement"></span><h2>Features Elements<a class="headerlink" href="#features-elements" title="Permalink to this headline">¶</a></h2>
+<p>Features elements are where simulation-wide options are specified. The <tt class="docutils literal"><span class="pre"><features></span></tt> element wraps one or more elements describing features. There are many possible feature elements. Currently, a full list of the features supported is:</p>
+<blockquote>
+<div><ul class="simple">
+<li><a class="reference internal" href="#argumentselement"><em>arguments</em></a></li>
+<li><a class="reference internal" href="#autovectorise"><em>auto_vectorise</em></a></li>
+<li><a class="reference internal" href="#benchmark"><em>benchmark</em></a></li>
+<li><a class="reference internal" href="#bing"><em>bing</em></a></li>
+<li><a class="reference internal" href="#cflags"><em>cflags</em></a></li>
+<li><a class="reference internal" href="#chunkedoutput"><em>chunked_output</em></a></li>
+<li><a class="reference internal" href="#diagnostics"><em>diagnostics</em></a></li>
+<li><a class="reference internal" href="#errorcheck"><em>error_check</em></a></li>
+<li><a class="reference internal" href="#haltnonfinite"><em>halt_non_finite</em></a></li>
+<li><a class="reference internal" href="#fftw"><em>fftw</em></a></li>
+<li><a class="reference internal" href="#globals"><em>globals</em></a></li>
+<li><a class="reference internal" href="#openmp"><em>OpenMP</em></a></li>
+<li><a class="reference internal" href="#precision"><em>precision</em></a></li>
+<li><a class="reference internal" href="#validation"><em>validation</em></a></li>
+</ul>
+</div></blockquote>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+  <span class="nt"><features></span>
+    <span class="nt"><bing</span> <span class="nt">/></span>
+    <span class="nt"><precision></span> double <span class="nt"></precision></span>
+    ...
+  <span class="nt"></features></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+<div class="section" id="arguments-element">
+<span id="argumentselement"></span><h3>Arguments Element<a class="headerlink" href="#arguments-element" title="Permalink to this headline">¶</a></h3>
+<p>The <tt class="docutils literal"><span class="pre"><arguments></span></tt> element is optional, and allows defining variables that can be passed to the simulation at run time. These variables are then globally accessible throughout the simulation script. Each of the variables must be defined in an <tt class="docutils literal"><span class="pre"><argument></span></tt> element (see below). The variables can then be passed to the simulation executable as options on the command [...]
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><name></span> arguments_test <span class="nt"></name></span>
+<span class="nt"><features></span>
+  <span class="nt"><arguments></span>
+    <span class="nt"><argument</span> <span class="na">name=</span><span class="s">"size"</span> <span class="na">type=</span><span class="s">"real"</span> <span class="na">default_value=</span><span class="s">"20.0"</span><span class="nt">/></span>
+    <span class="nt"><argument</span> <span class="na">name=</span><span class="s">"number"</span> <span class="na">type=</span><span class="s">"integer"</span> <span class="na">default_value=</span><span class="s">"7"</span><span class="nt">/></span>
+    <span class="nt"><argument</span> <span class="na">name=</span><span class="s">"pulse_shape"</span> <span class="na">type=</span><span class="s">"string"</span> <span class="na">default_value=</span><span class="s">"gaussian"</span><span class="nt">/></span>
+  <span class="nt"></arguments></span>
+<span class="nt"></features></span>
+</pre></div>
+</div>
+<p>When <tt class="docutils literal"><span class="pre">XMDS2</span></tt> is run on this script the executable <tt class="docutils literal"><span class="pre">arguments_test</span></tt> is created. The values of <tt class="docutils literal"><span class="pre">size</span></tt>, <tt class="docutils literal"><span class="pre">number</span></tt>, and <tt class="docutils literal"><span class="pre">pulse_shape</span></tt> can then be set to whatever is desired at runtime via</p>
+<div class="highlight-xmds2"><div class="highlight"><pre>./arguments_test --size=1.3 --number=2 --pulse_shape=lorentzian
+</pre></div>
+</div>
+<p>It is also possible to include an optional <tt class="docutils literal"><span class="pre">CDATA</span></tt> block inside the <tt class="docutils literal"><span class="pre"><arguments></span></tt> block. This code will run after the arguments have been initialised with the values passed from the command line. This code block could be used, for example, to sanity check the parameters passed in, or for assigning values to global variables based on those parameters.  Any references  [...]
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><features></span>
+  <span class="nt"><globals></span>
+    <span class="cp"><![CDATA[</span>
+      <span class="nf">real</span> <span class="n">atom_kick</span><span class="p">;</span>
+    <span class="cp">]]></span>
+  <span class="nt"><globals></span>
+  <span class="nt"><arguments></span>
+    <span class="nt"><argument</span> <span class="na">name=</span><span class="s">"bragg_order"</span> <span class="na">type=</span><span class="s">"integer"</span> <span class="na">default_value=</span><span class="s">"2"</span><span class="nt">/></span>
+    <span class="cp"><![CDATA[</span>
+      <span class="n">atom_kick</span> <span class="o">=</span> <span class="n">bragg_order</span> <span class="o">*</span> <span class="mi">2</span><span class="o">*</span><span class="n">M_PI</span> <span class="o">/</span> <span class="mf">780e-9</span><span class="p">;</span>
+    <span class="cp">]]></span>
+  <span class="nt"></arguments></span>
+<span class="nt"></features></span>
+</pre></div>
+</div>
+<div class="section" id="argument-element">
+<span id="argumentelement"></span><h4>Argument element<a class="headerlink" href="#argument-element" title="Permalink to this headline">¶</a></h4>
+<p>Each <tt class="docutils literal"><span class="pre"><argument></span></tt> element describes one variable that can be passed to the simulation at runtime via the command line. There are three mandatory attributes: <tt class="docutils literal"><span class="pre">name</span></tt>, <tt class="docutils literal"><span class="pre">type</span></tt>, and <tt class="docutils literal"><span class="pre">default_value</span></tt>. <tt class="docutils literal"><span class="pre">name</span></t [...]
+</div>
+</div>
+<div class="section" id="auto-vectorise-element">
+<span id="autovectorise"></span><h3>Auto_vectorise element<a class="headerlink" href="#auto-vectorise-element" title="Permalink to this headline">¶</a></h3>
+<p>The <tt class="docutils literal"><span class="pre"><auto_vectorise</span> <span class="pre">/></span></tt> feature attempts to activate automatic vectorisation for large loops, if it is available in the compiler.  This should make some simulations go faster.</p>
+</div>
+<div class="section" id="benchmark">
+<span id="id1"></span><h3>Benchmark<a class="headerlink" href="#benchmark" title="Permalink to this headline">¶</a></h3>
+<p>The <tt class="docutils literal"><span class="pre"><benchmark</span> <span class="pre">/></span></tt> feature includes a timing routine in the generated code, so that it is possible to see how long the simulations take to run.</p>
+</div>
+<div class="section" id="bing">
+<span id="id2"></span><h3>Bing<a class="headerlink" href="#bing" title="Permalink to this headline">¶</a></h3>
+<p>The <tt class="docutils literal"><span class="pre"><bing</span> <span class="pre">/></span></tt> feature causes the simulation to make an invigorating sound when the simulation finishes executing.</p>
+</div>
+<div class="section" id="c-flags">
+<span id="cflags"></span><h3>C Flags<a class="headerlink" href="#c-flags" title="Permalink to this headline">¶</a></h3>
+<p>The <tt class="docutils literal"><span class="pre"><cflags></span></tt> feature allows extra flags to be passed to the compiler.  This can be useful for optimisation, and also using specific external libraries.  The extra options to be passed are defined with a ‘CDATA’ block.  The compile options can be made visible by running XMDS2 either with the “-v” (verbose) option, or the “-g” (debug) option.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><cflags></span>
+    <span class="cp"><![CDATA[</span>
+        <span class="o">-</span><span class="n">O4</span>
+    <span class="cp">]]></span>
+<span class="nt"></cflags></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="chunked-output">
+<span id="chunkedoutput"></span><h3>Chunked Output<a class="headerlink" href="#chunked-output" title="Permalink to this headline">¶</a></h3>
+<p>By default, XMDS2 keeps the contents of all output moment groups in memory until the end of the simulation when they are written to the output file.  This can be a problem if your simulation creates a very large amount of output.  <tt class="docutils literal"><span class="pre"><chunked_output</span> <span class="pre">/></span></tt> causes the simulation to save the output data in chunks as the simulation progresses.  For some simulations this can significantly reduce the amount  [...]
+<p>Limitations (XMDS will give you an error if you violate any of these):</p>
+<ul class="simple">
+<li>This feature cannot be used with the ASCII output file format due to limitations in the file format.</li>
+<li>This feature cannot be used with the <tt class="docutils literal"><span class="pre">multi-path</span></tt> drivers because all sampling data is required to compute the mean and standard error statistics.</li>
+<li>Neither is this feature compatible with the <tt class="docutils literal"><span class="pre">error_check</span></tt> feature as that relies on all sampling data being available to compute the error.</li>
+</ul>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><features></span>
+        <span class="nt"><chunked_output</span> <span class="na">size=</span><span class="s">"5MB"</span> <span class="nt">/></span>
+    <span class="nt"></features></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="diagnostics">
+<span id="id3"></span><h3>Diagnostics<a class="headerlink" href="#diagnostics" title="Permalink to this headline">¶</a></h3>
+<p>The <tt class="docutils literal"><span class="pre"><diagnostics</span> <span class="pre">/></span></tt> feature causes a simulation to output more information as it executes.  This should be useful when a simulation is dying / giving bad results to help diagnose the cause.  Currently, it largely outputs step error information.</p>
+</div>
+<div class="section" id="error-check">
+<span id="errorcheck"></span><h3>Error Check<a class="headerlink" href="#error-check" title="Permalink to this headline">¶</a></h3>
+<p>It’s often important to know whether you’ve got errors.  This feature runs each integration twice: once with the specified error tolerance or defined lattice spacing in the propagation dimension, and then again with half the lattice spacing, or an equivalently lower error tolerance.  Each component of the output then shows the difference between these two integrations as an estimate of the error.  This feature is particularly useful when integrating stochastic equations, a [...]
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><features></span>
+        <span class="nt"><error_check</span> <span class="nt">/></span>
+    <span class="nt"></features></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="halt-non-finite">
+<span id="haltnonfinite"></span><h3>Halt_Non_Finite<a class="headerlink" href="#halt-non-finite" title="Permalink to this headline">¶</a></h3>
+<p>The <tt class="docutils literal"><span class="pre"><halt_non_finite</span> <span class="pre">/></span></tt> feature is used to stop computations from continuing to run after the vectors stop having numerical values.  This can occur when a number is too large to represent numerically, or when an illegal operation occurs.  Processing variables with non-numerical values is usually much slower than normal processing, and the results are meaningless.  Of course, there is a small cost [...]
+</div>
+<div class="section" id="fftw-element">
+<span id="fftw"></span><h3>fftw element<a class="headerlink" href="#fftw-element" title="Permalink to this headline">¶</a></h3>
+<p>The <tt class="docutils literal"><span class="pre"><fftw</span> <span class="pre">\></span></tt> feature can be used to pass options to the <a class="reference external" href="http://fftw.org">Fast Fourier Transform library</a> used by XMDS.  This library tests algorithms on each architecture to determine the fastest method of solving each problem.  Typically this costs very little overhead, as the results of all previous tests are stored in the directory “~/.xmds/wisdom&# [...]
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><fftw</span> <span class="na">plan=</span><span class="s">"patient"</span> <span class="na">threads=</span><span class="s">"3"</span> <span class="nt">/></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="globals">
+<span id="id4"></span><h3>Globals<a class="headerlink" href="#globals" title="Permalink to this headline">¶</a></h3>
+<p>The globals feature places the contents of a ‘CDATA’ block near the top of the generated program.  Amongst other things, this is useful for defining variables that are then accessible throughout the entire program.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><globals></span>
+  <span class="cp"><![CDATA[</span>
+    <span class="k">const</span> <span class="nf">real</span> <span class="n">omegaz</span> <span class="o">=</span> <span class="mi">2</span><span class="o">*</span><span class="n">M_PI</span><span class="o">*</span><span class="mi">20</span><span class="p">;</span>
+    <span class="kt">long</span> <span class="n">Nparticles</span> <span class="o">=</span> <span class="mi">50000</span><span class="p">;</span>
+
+    <span class="cm">/* offset constants */</span>
+    <span class="nf">real</span> <span class="n">frequency</span> <span class="o">=</span> <span class="n">omegaz</span><span class="o">/</span><span class="mi">2</span><span class="o">/</span><span class="n">M_PI</span><span class="p">;</span>
+  <span class="cp">]]></span>
+<span class="nt"></globals></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="openmp">
+<span id="id5"></span><h3>OpenMP<a class="headerlink" href="#openmp" title="Permalink to this headline">¶</a></h3>
+<p>The <tt class="docutils literal"><span class="pre"><openmp</span> <span class="pre">/></span></tt> feature instructs compatible compilers to parallelise key loops using the <a class="reference external" href="http://www.openmp.org">OpenMP API</a> standard.  By default the simulation will use all available CPUs.  The number of threads used can be restricted by specifying the number of threads in the script with <tt class="docutils literal"><span class="pre"><openmp</span> <spa [...]
+<div class="highlight-xmds2"><div class="highlight"><pre>OMP_NUM_THREADS=2 ./simulation_name
+</pre></div>
+</div>
+</div>
+<div class="section" id="precision">
+<span id="id6"></span><h3>Precision<a class="headerlink" href="#precision" title="Permalink to this headline">¶</a></h3>
+<p>This specifies the precision of the XMDS2 <tt class="docutils literal"><span class="pre">real</span></tt> and <tt class="docutils literal"><span class="pre">complex</span></tt> datatypes, as well as the precision used when computing transforms. Currently two values are accepted: <tt class="docutils literal"><span class="pre">single</span></tt> and <tt class="docutils literal"><span class="pre">double</span></tt>. If this feature isn’t specified, XMDS2 defaults to using double pr [...]
+<p>Single precision has approximately 7.2 decimal digits of accuracy, with a minimum value of 1.4×10<sup>-45</sup> and a maximum of 3.8×10<sup>34</sup>. Double precision has approximately 16 decimal digits of accuracy, a minimum value of 4.9×10<sup>-324</sup> and a maximum value of 1.8×10<sup>308</sup>.</p>
+<p>Using single precision can be attractive, as it can be more than twice as fast, depending on whether a simulation is CPU bound, memory bandwidth bound, MPI bound or bottlenecked elsewhere, although in some situations you may see no speed-up at all. Caution should be exercised, however. Keep in mind how many timesteps your simulation requires, and take note of the tolerance you have set per step, to see if the result will lie within your acceptable total error - seven digit precision i [...]
+<p>Also note that when using an adaptive step integrator, setting a tolerance close to limits of the precision can lead to very slow performance.</p>
+<p>A further limitation is that not all the combinations of random number generators and probability distributions that are supported in double precision are supported in single precision. For example, the <tt class="docutils literal"><span class="pre">solirte</span></tt> generator does not support single precision gaussian distributions. <tt class="docutils literal"><span class="pre">dsfmt</span></tt>, however, is one of the fastest generators, and does support single precision.</p>
+<p>WARNING: Single precision mode has not been tested anywhere near as thoroughly as the default double precision mode, and there is a higher chance you will run into bugs.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><features></span>
+        <span class="nt"><precision></span> single <span class="nt"></precision></span>
+    <span class="nt"></features></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="validation">
+<span id="id7"></span><h3>Validation<a class="headerlink" href="#validation" title="Permalink to this headline">¶</a></h3>
+<p>XMDS2 makes a large number of checks in the code generation process to verify that the values for all parameters are safe choices.  Sometimes we wish to allow these parameters to be specified by variables.  This opens up many possibilities, but requires that any safety checks for parameters be performed during the execution of the program itself.  The <tt class="docutils literal"><span class="pre"><validation></span></tt> feature activates that option, with allowable attributes  [...]
+<p>As an example, one may wish to define the number of grid points and the range of the grid at run-time rather than explicitly define them in the XMDS2 script. To accomplish this, one could do the following:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre> <span class="nt"><name></span> validation_test <span class="nt"></name></span>
+ <span class="nt"><features></span>
+   <span class="nt"><validation</span> <span class="na">kind=</span><span class="s">"run-time"</span> <span class="nt">/></span>
+   <span class="nt"><arguments></span>
+     <span class="nt"><argument</span> <span class="na">name=</span><span class="s">"xmin"</span> <span class="na">type=</span><span class="s">"real"</span> <span class="na">default_value=</span><span class="s">"-1.0"</span><span class="nt">/></span>
+     <span class="nt"><argument</span> <span class="na">name=</span><span class="s">"xmax"</span> <span class="na">type=</span><span class="s">"real"</span> <span class="na">default_value=</span><span class="s">"1.0"</span><span class="nt">/></span>
+     <span class="nt"><argument</span> <span class="na">name=</span><span class="s">"numGridPoints"</span> <span class="na">type=</span><span class="s">"integer"</span> <span class="na">default_value=</span><span class="s">"128"</span><span class="nt">/></span>
+   <span class="nt"></arguments></span>
+ <span class="nt"></features></span>
+
+ <span class="nt"><geometry></span>
+   <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+   <span class="nt"><transverse_dimensions></span>
+     <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"x"</span> <span class="na">lattice=</span><span class="s">"numGridPoints"</span>  <span class="na">domain=</span><span class="s">"(xmin, xmax)"</span> <span class="nt">/></span>
+   <span class="nt"></transverse_dimensions></span>
+<span class="nt"></geometry></span>
+</pre></div>
+</div>
+<p>and then run the resulting executable with:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre>./validation_test --xmin=-2.0 --xmax=2.0 --numGridPoints=64
+</pre></div>
+</div>
+<p>This approach means that when XMDS2 is parsing the script it is unable to tell, for example, if the number of sampling points requested is less than or equal to the lattice size. Consequently it will create an executable with “numGridPoints” as an internal variable, and make the check at run-time, when it knows the value of “numGridPoints” rather than at compile time, when it doesn’t.</p>
+</div>
+</div>
+<div class="section" id="driver-element">
+<span id="driverelement"></span><h2>Driver Element<a class="headerlink" href="#driver-element" title="Permalink to this headline">¶</a></h2>
+<p>The driver element controls the overall management of the simulation, including how many paths of a stochastic simulation are to be averaged, and whether or not it is to be run using distributed memory parallelisation.  If it is not included, then the simulation is performed once without using MPI parallelisation.  If it is included, it must have a <tt class="docutils literal"><span class="pre">name</span></tt> attribute.</p>
+<p>The <tt class="docutils literal"><span class="pre">name</span></tt> attribute can have values of “none” (which is equivalent to the default option of not specifying a driver), “distributed-mpi”, “multi-path” or “mpi-multi-path”.</p>
+<p>Choosing the <tt class="docutils literal"><span class="pre">name="distributed-mpi"</span></tt> option allows a single integration over multiple processors.  The resulting executable can then be run according to your particular implementation of MPI.  The FFTW library only allows MPI processing of multidimensional vectors, as otherwise shared memory parallel processing requires too much inter-process communication to be efficient.  Maximally efficient parallelisation occurs w [...]
+<p>The <tt class="docutils literal"><span class="pre">name="multi-path"</span></tt> option is used for stochastic simulations, which are typically run multiple times and averaged.  It requires a <tt class="docutils literal"><span class="pre">paths</span></tt> attribute with the number of iterations of the integration to be averaged.  The output will report the averages of the desired samples, and the standard error in those averages.
+The <tt class="docutils literal"><span class="pre">name="mpi-multi-path"</span></tt> option integrates separate paths on different processors, which is typically a highly efficient process.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><driver</span> <span class="na">name=</span><span class="s">"distributed-mpi"</span> <span class="nt">/></span>
+        <span class="c"><!-- or --></span>
+    <span class="nt"><driver</span> <span class="na">name=</span><span class="s">"multi-path"</span> <span class="na">paths=</span><span class="s">"10"</span> <span class="nt">/></span>
+        <span class="c"><!-- or --></span>
+    <span class="nt"><driver</span> <span class="na">name=</span><span class="s">"mpi-multi-path"</span> <span class="na">paths=</span><span class="s">"1000"</span> <span class="nt">/></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="geometry-element">
+<span id="geometryelement"></span><h2>Geometry Element<a class="headerlink" href="#geometry-element" title="Permalink to this headline">¶</a></h2>
+<p id="propagationdimensionelement">The <tt class="docutils literal"><span class="pre"><geometry></span></tt> element describes the dimensions used in your simulation, and is required.  The only required element inside is the <tt class="docutils literal"><span class="pre"><propagation_dimension></span></tt> element, which defines the name of the dimension along which your simulation will integrate.  Nothing else about this dimension is specified, as requirements for the latti [...]
+<p id="dimensionelement"><span id="transversedimensionselement"></span>If there are other dimensions in your problem, they are called “transverse dimensions”, and are described in the <tt class="docutils literal"><span class="pre"><transverse_dimensions></span></tt> element.  Each dimension is then described in its own <tt class="docutils literal"><span class="pre"><dimension></span></tt> element.  A transverse dimension must have a unique name defined by a <tt cl [...]
+<p>Each transverse dimension must specify how many points or modes it requires, and the range over which it is defined.  This is done by the <tt class="docutils literal"><span class="pre">lattice</span></tt> and <tt class="docutils literal"><span class="pre">domain</span></tt> attributes respectively.  The <tt class="docutils literal"><span class="pre">lattice</span></tt> attribute is an integer, and is optional for integer dimensions, where it can be defined implicitly by the domain.  T [...]
+<p>Any dimension can have a number of aliases.  These act exactly like copies of that dimension, but must be included explicitly in the definition of subsequent vectors (i.e. they are not included in the default list of dimensions for a new vector).  The list of aliases for a dimension are included in an <tt class="docutils literal"><span class="pre">aliases</span></tt> attribute.  They are useful for non-local reference of variables.  See <tt class="docutils literal"><span class="pre">g [...]
+<p>Integrals over a dimension can be multiplied by a common prefactor, which is specified using the <tt class="docutils literal"><span class="pre">volume_prefactor</span></tt> attribute.  For example, this allows the automatic inclusion of a factor of two due to a reflection symmetry by adding the attribute <tt class="docutils literal"><span class="pre">volume_prefactor="2"</span></tt>.  In very specific cases, you may wish to refer to volume elements explicitly.  This will lea [...]
+<p>If you are using the <tt class="docutils literal"><span class="pre">distributed-mpi</span></tt> driver to parallelise the simulation, place the dimension you wish to split over multiple processors first.  The most efficient parallelisation would involve distributing a dimension with only local evolution, as the different memory blocks would not need to communicate.  Nonlocal evolution that is local in Fourier space is the second preference, as the Fourier transform can also be success [...]
+<p id="transforms">Each transverse dimension can be associated with a transform.  This allows the simulation to manipulate vectors defined on that dimension in the transform space.  The default is Fourier space (with the associated transform being the discrete Fourier transform, or “dft”), but others can be specified with the <tt class="docutils literal"><span class="pre">transform</span></tt> attribute.  The other options are “none”, “dst”, “dct [...]
+<p>An advanced feature discussed further in <a class="reference internal" href="advanced_topics.html#dimensionaliases"><em>Dimension aliases</em></a> are dimension aliases, which are specified by the <tt class="docutils literal"><span class="pre">aliases</span></tt> attribute.  This feature is useful for example, when calculating correlation functions.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><geometry></span>
+        <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+        <span class="nt"><transverse_dimensions></span>
+            <span class="c"><!-- A real-valued dimension from -1.5 to 1.5 --></span>
+            <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"x"</span> <span class="na">lattice=</span><span class="s">"128"</span> <span class="na">domain=</span><span class="s">"(-1.5, 1.5)"</span> <span class="nt">/></span>
+
+            <span class="c"><!-- An integer-valued dimension with the 6 values -2, -1, 0, 1, 2, 3 --></span>
+            <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"j"</span>               <span class="na">domain=</span><span class="s">"(-2,3)"</span> <span class="na">type=</span><span class="s">"integer"</span> <span class="nt">/></span>
+
+            <span class="c"><!-- A real-valued dimension using the bessel transform for a radial coordinate --></span>
+            <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"r"</span> <span class="na">lattice=</span><span class="s">"64"</span> <span class="na">domain=</span><span class="s">"(0, 5)"</span>  <span class="na">transform=</span><span class="s">"bessel"</span> <span class="na">volume_prefactor=</span><span class="s">"2.0*M_PI"</span> <span class="nt">/></span>
+        <span class="nt"></transverse_dimensions></span>
+    <span class="nt"></geometry></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+<div class="section" id="the-dft-transform">
+<span id="dft-transform"></span><h3>The “dft” transform<a class="headerlink" href="#the-dft-transform" title="Permalink to this headline">¶</a></h3>
+<p>The “dft” transform is performed using the the normal discrete Fourier transform, which means that it enforces periodic boundary conditions on vectors defined on that dimension.  Another implication is that it can only be used with complex-valued vectors.  The discrete Fourier transform is almost exactly the same as a standard Fourier transform.  The standard Fourier transform is</p>
+<div class="math">
+\[\mathcal{F}\left[f(x)\right](k) = \frac{1}{\sqrt{2\pi}}\int_{x_\text{min}}^{x_\text{max}} f(x) e^{-i k x} dx\]</div>
+<p>The discrete Fourier transform has no information about the domain of the lattice, so the XMDS2 transform is equivalent to</p>
+<div class="math">
+\[\begin{split}\tilde{\mathcal{F}}\left[f(x)\right](k) &= \frac{1}{\sqrt{2\pi}}\int_{x_\text{min}}^{x_\text{max}} f(x) e^{-i k (x+ x_\text{min})} dx \\
+&= e^{-i x_\text{min} k} \mathcal{F}\left[f(x)\right](k)\end{split}\]</div>
+<p>The standard usage in an XMDS simulation involves moving to Fourier space, applying a transformation, and then moving back.  For this purpose, the two transformations are entirely equivalent as the extra phase factor cancels.  However, when fields are explicitly defined in Fourier space, care must be taken to include this phase factor explicitly.  See section <a class="reference internal" href="advanced_topics.html#convolutions"><em>Convolutions and Fourier transforms</em></a> in the  [...]
+<p>When a dimension uses the “dft” transform, then the Fourier space variable is defined as the name of the dimension prefixed with a “k”.  For example, the dimensions “x”, “y”, “z” and “tau” will be referenced in Fourier space as “kx”,”ky”, “kz” and “ktau”.</p>
+<p>Fourier transforms allow easy calculation of derivatives, as the n<sup>th</sup> derivative of a field is proportional to the n<sup>th</sup> moment of the field in Fourier space:</p>
+<div class="math">
+\[\mathcal{F}\left[\frac{\partial^n f(x)}{\partial x^n}\right](k_x) = \left(i \;k_x\right)^n \mathcal{F}\left[f(x)\right](k_x)\]</div>
+<p>This identity can be used to write the differential operator <span class="math">\(\mathcal{L} = \frac{\partial}{\partial x}\)</span> as an <tt class="docutils literal"><span class="pre">IP</span></tt> or <tt class="docutils literal"><span class="pre">EX</span></tt> operator as <tt class="docutils literal"><span class="pre">L</span> <span class="pre">=</span> <span class="pre">i*kx;</span></tt> (see <a class="reference internal" href="#operatorselement"><em>Operators and operator eleme [...]
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><geometry></span>
+        <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+        <span class="nt"><transverse_dimensions></span>
+            <span class="c"><!-- transform="dft" is the default, omitting it wouldn't change anything --></span>
+            <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"x"</span> <span class="na">lattice=</span><span class="s">"128"</span> <span class="na">domain=</span><span class="s">"(-1.5, 1.5)"</span> <span class="na">transform=</span><span class="s">"dft"</span> <span class="nt">/></span>
+        <span class="nt"></transverse_dimensions></span>
+    <span class="nt"></geometry></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="the-dct-transform">
+<h3>The “dct” transform<a class="headerlink" href="#the-dct-transform" title="Permalink to this headline">¶</a></h3>
+<p>The “dct” (discrete cosine transform) is a Fourier-based transform that implies different boundary conditions for associated vectors.  XMDS uses the type-II DCT, often called “the DCT”, and its inverse, which is also called the type-III DCT.  This transform assumes that any vector using this dimension is both periodic, and also even around a specific point within each period.  The grid is therefore only defined across a half period in order to sample each uniqu [...]
+<p>As the DCT transform can be defined on real data rather only complex data, it can also be superior to DFT-based spectral methods for simulations of real-valued fields where boundary conditions are artificial.</p>
+<p>XMDS labels the cosine transform space variables the same as for <a class="reference internal" href="#dft-transform"><em>Fourier transforms</em></a> and all the even derivatives can be calculated the same way.  Odd moments of the cosine-space variables are in fact <em>not</em> related to the corresponding odd derivatives by an inverse cosine transform.</p>
+<p>Discrete cosine transforms allow easy calculation of even-order derivatives, as the 2n<sup>th</sup> derivative of a field is proportional to the 2n<sup>th</sup> moment of the field in DCT-space:</p>
+<div class="math">
+\[\mathcal{F}_\text{DCT}\left[\frac{\partial^{2n} f(x)}{\partial x^{2n}}\right](k_x) = (-k_x^2)^{n}\; \mathcal{F}_\text{DCT}\left[f(x)\right](k_x)\]</div>
+<p>This identity can be used to write the differential operator <span class="math">\(\mathcal{L} = \frac{\partial^2}{\partial x^2}\)</span> as an <tt class="docutils literal"><span class="pre">IP</span></tt> or <tt class="docutils literal"><span class="pre">EX</span></tt> operator as <tt class="docutils literal"><span class="pre">L</span> <span class="pre">=</span> <span class="pre">-kx*kx;</span></tt> (see <a class="reference internal" href="#operatorselement"><em>Operators and operator [...]
+<p>For problems where you are defining the simulation domain over only half of the physical domain to take advantage of reflection symmetry, consider using <tt class="docutils literal"><span class="pre">volume_prefactor="2.0"</span></tt> so that all volume integrals are over the entire physical domain, not just the simulation domain. i.e. integrals would be over -1 to 1 instead of 0 to 1 if the domain was specified as <tt class="docutils literal"><span class="pre">domain=" [...]
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><geometry></span>
+        <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+        <span class="nt"><transverse_dimensions></span>
+            <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"x"</span> <span class="na">lattice=</span><span class="s">"128"</span> <span class="na">domain=</span><span class="s">"(-1.5, 1.5)"</span> <span class="na">transform=</span><span class="s">"dct"</span> <span class="nt">/></span>
+                <span class="c"><!-- Or to cause volume integrals to be multiplied by 2 --></span>
+            <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"y"</span> <span class="na">lattice=</span><span class="s">"128"</span> <span class="na">domain=</span><span class="s">"(0, 1)"</span> <span class="na">transform=</span><span class="s">"dct"</span> <span class="na">volume_prefactor=</span><span class="s">"2.0"</span> <span class="nt">/></span>
+        <span class="nt"></transverse_dimensions></span>
+    <span class="nt"></geometry></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="the-dst-transform">
+<h3>The “dst” transform<a class="headerlink" href="#the-dst-transform" title="Permalink to this headline">¶</a></h3>
+<p>The “dst” (discrete sine transform) is a counterpart to the DCT transform.  XMDS uses the type-II DST and its inverse, which is also called the type-III DST.  This transform assumes that fields are periodic in this dimension, but also that they are also odd around a specific point within each period.  The grid is therefore only defined across a half period in order to sample each unique point once, and can therefore be of any shape where all the even derivatives are zero a [...]
+<p>The DST transform can be defined on real-valued vectors.  As odd-valued functions are zero at the boundaries, this is a natural transform to use when implementing zero Dirichlet boundary conditions.</p>
+<p>XMDS labels the sine transform space variables the same as for <a class="reference internal" href="#dft-transform"><em>Fourier transforms</em></a> and all the even derivatives can be calculated the same way.  Odd moments of the sine-space variables are in fact <em>not</em> related to the corresponding odd derivatives by an inverse sine transform.</p>
+<p>Discrete sine transforms allow easy calculation of even-order derivatives, as the 2n<sup>th</sup> derivative of a field is proportional to the 2n<sup>th</sup> moment of the field in DST-space:</p>
+<div class="math">
+\[\mathcal{F}_\text{DST}\left[\frac{\partial^{2n} f(x)}{\partial x^{2n}}\right](k_x) = (-k_x^2)^{n}\; \mathcal{F}_\text{DST}\left[f(x)\right](k_x)\]</div>
+<p>This identity can be used to write the differential operator <span class="math">\(\mathcal{L} = \frac{\partial^2}{\partial x^2}\)</span> as an <tt class="docutils literal"><span class="pre">IP</span></tt> or <tt class="docutils literal"><span class="pre">EX</span></tt> operator as <tt class="docutils literal"><span class="pre">L</span> <span class="pre">=</span> <span class="pre">-kx*kx;</span></tt> (see <a class="reference internal" href="#operatorselement"><em>Operators and operator [...]
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><geometry></span>
+        <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+        <span class="nt"><transverse_dimensions></span>
+            <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"x"</span> <span class="na">lattice=</span><span class="s">"128"</span> <span class="na">domain=</span><span class="s">"(0, 1.5)"</span> <span class="na">transform=</span><span class="s">"dst"</span> <span class="nt">/></span>
+        <span class="nt"></transverse_dimensions></span>
+    <span class="nt"></geometry></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="the-bessel-transform">
+<span id="besseltransform"></span><h3>The “bessel” transform<a class="headerlink" href="#the-bessel-transform" title="Permalink to this headline">¶</a></h3>
+<p>Just as the Fourier basis is useful for finding derivatives in Euclidean geometry, the basis of Bessel functions is useful for finding certain common operators in cylindrical co-ordinates.  In particular, we use the Bessel functions of the first kind, <span class="math">\(J_m(u)\)</span>.  The relevant transform is the Hankel transform:</p>
+<div class="math">
+\[F_m(k) = \mathcal{H}_m \left[f\right](k) = \int_0^\infty r f(r) J_m(k r) dr\]</div>
+<p>which has the inverse transform:</p>
+<div class="math">
+\[f(r) = \mathcal{H}^{-1}_m \left[F_m\right](r) = \int_0^\infty k F_m(k) J_m(k r) dk\]</div>
+<p>This transform pair has the useful property that the Laplacian in cylindrical co-ordinates is diagonal in this basis:</p>
+<div class="math">
+\[\begin{split}\nabla^2 \left(f(r) e^{i m \theta}\right) &= \left(\frac{\partial^2 f}{\partial r^2} +\frac{1}{r}\frac{\partial f}{\partial r} -\frac{m^2}{r^2} f \right) e^{i m \theta} = \left\{\mathcal{H}^{-1}_m \left[(-k^2) F_m(k)\right](r) \right\} e^{i m \theta}\end{split}\]</div>
+<p>XMDS labels the variables in the transformed space with a prefix of ‘k’, just as for <a class="reference internal" href="#dft-transform"><em>Fourier transforms</em></a>.  The order <span class="math">\(m\)</span> of the transform is defined by the <tt class="docutils literal"><span class="pre">order</span></tt> attribute in the <tt class="docutils literal"><span class="pre"><dimension></span></tt> element, which must be assigned as a non-negative integer.  If the ord [...]
+<p>It can often be useful to have a different sampling in normal space and Hankel space.  Reducing the number of modes in either space dramatically speeds simulations.  To set the number of lattice points in Hankel space to be different to the number of lattice points for the field in its original space, use the attribute <tt class="docutils literal"><span class="pre">spectral_lattice</span></tt>.  The Bessel space lattice is chosen such that the boundary condition at the edge of the dom [...]
+<p>Hankel transforms allow easy calculation of the Laplacian of fields with cylindrical symmetry.  Applying the operator <tt class="docutils literal"><span class="pre">L</span> <span class="pre">=</span> <span class="pre">-kr*kr</span></tt> in Hankel space is therefore equivalent to applying the operator</p>
+<div class="math">
+\[\mathcal{L} = \left(\frac{\partial^2}{\partial r^2} +\frac{1}{r}\frac{\partial}{\partial r} -\frac{m^2}{r^2} \right)\]</div>
+<p>in coordinate space.</p>
+<p>In non-Euclidean co-ordinates, integrals have non-unit volume elements.  For example, in cylindrical co-ordinates with a radial co-ordinate ‘r’, integrals over this dimension have a volume element <span class="math">\(r dr\)</span>.  When performing integrals along a dimension specified by the “bessel” transform, the factor of the radius is included implicitly.  If you are using a geometry with some symmetry, it is common to have prefactors in your integration. [...]
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><geometry></span>
+        <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+        <span class="nt"><transverse_dimensions></span>
+            <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"r"</span> <span class="na">lattice=</span><span class="s">"128"</span> <span class="na">domain=</span><span class="s">"(0, 3)"</span> <span class="na">transform=</span><span class="s">"bessel"</span> <span class="na">volume_prefactor=</span><span class="s">"2*M_PI"</span> <span class="nt">/></span>
+        <span class="nt"></transverse_dimensions></span>
+    <span class="nt"></geometry></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="the-spherical-bessel-transform">
+<h3>The “spherical-bessel” transform<a class="headerlink" href="#the-spherical-bessel-transform" title="Permalink to this headline">¶</a></h3>
+<p>When working in spherical coordinates, it is often useful to use the spherical Bessel functions <span class="math">\(j_l(x)=\sqrt{\frac{\pi}{2x}}J_{l+\frac{1}{2}}(x)\)</span> as a basis.  These are eigenfunctions of the radial component of Laplace’s equation in spherical coordinates:</p>
+<div class="math">
+\[\begin{split}\nabla^2 \left[j_l(k r)\; Y^m_l(\theta, \phi)\right] &= \left[\frac{\partial^2 }{\partial r^2} +\frac{2}{r}\frac{\partial }{\partial r} -\frac{l(l+1)}{r^2}\right] j_l(k r) \; Y^m_l(\theta, \phi) = -k^2 j_l(k r)\; Y^m_l(\theta, \phi)\end{split}\]</div>
+<p>Just as the Bessel basis above, the transformed dimensions are prefixed with a ‘k’, and it is possible (and usually wise) to use the <tt class="docutils literal"><span class="pre">spectral_lattice</span></tt> attribute to specify a different lattice size in the transformed space.  Also, the spacing of these lattices are again chosen in a non-uniform manner to Gaussian quadrature methods for spectrally accurate transforms.  Finally, the <tt class="docutils literal"><span cl [...]
+<p>If we denote the transformation to and from this basis by <span class="math">\(\mathcal{SH}\)</span>, then we can write the useful property:</p>
+<div class="math">
+\[\frac{\partial^2 f}{\partial r^2} +\frac{2}{r}\frac{\partial f}{\partial r} -\frac{l (l+1)}{r^2} = \mathcal{SH}^{-1}_l \left[(-k^2) F_l(k)\right](r)\]</div>
+<p>Spherical Bessel transforms allow easy calculation of the Laplacian of fields with spherical symmetry. Applying the operator <tt class="docutils literal"><span class="pre">L</span> <span class="pre">=</span> <span class="pre">-kr*kr</span></tt> in Spherical Bessel space is therefore equivalent to applying the operator</p>
+<div class="math">
+\[\mathcal{L} = \left( \frac{\partial^2}{\partial r^2} +\frac{2}{r}\frac{\partial}{\partial r} -\frac{l (l+1)}{r^2} \right)\]</div>
+<p>in coordinate space.</p>
+<p>In non-Euclidean co-ordinates, integrals have non-unit volume elements.  For example, in spherical co-ordinates with a radial co-ordinate ‘r’, integrals over this dimension have a volume element <span class="math">\(r^2 dr\)</span>.  When performing integrals along a dimension specified by the “spherical-bessel” transform, the factor of the square of the radius is included implicitly.  If you are using a geometry with some symmetry, it is common to have prefact [...]
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><geometry></span>
+        <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+        <span class="nt"><transverse_dimensions></span>
+            <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"r"</span> <span class="na">lattice=</span><span class="s">"128"</span> <span class="na">domain=</span><span class="s">"(0, 3)"</span> <span class="na">transform=</span><span class="s">"spherical-bessel"</span> <span class="na">volume_prefactor=</span><span class="s">"4*M_PI"</span> <span class="nt">/></span>
+        <span class="nt"></transverse_dimensions></span>
+    <span class="nt"></geometry></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="the-hermite-gauss-transform">
+<h3>The “hermite-gauss” transform<a class="headerlink" href="#the-hermite-gauss-transform" title="Permalink to this headline">¶</a></h3>
+<p>The “hermite-gauss” transform allows transformations to and from the basis of Hermite functions <span class="math">\(\psi_n(x)\)</span>:</p>
+<div class="math">
+\[\psi_n(x) = \left(2^n n! \sigma \sqrt{\pi}\right)^{-1/2} e^{-x^2/2\sigma^2} H_n(\sigma x)\]</div>
+<p>where the functions <span class="math">\(H_n(x)\)</span> are the Hermite polynomials:</p>
+<div class="math">
+\[\begin{split}H_n(x) &= (-1)^n e^{x^2} \frac{d^n}{dx^n} \left(e^{-x^2}\right)\end{split}\]</div>
+<p>which are eigenfunctions of the Schroedinger equation for a harmonic oscillator:</p>
+<div class="math">
+\[- \frac{\hbar^2}{2 m} \frac{\partial^2 \psi_n}{\partial x^2} + \frac{1}{2} m \omega^2 x^2 \psi_n(x) = \hbar \omega\left(n+\frac{1}{2}\right) \psi_n(x),\]</div>
+<p>with <span class="math">\(\sigma = \sqrt{\frac{\hbar}{m \omega}}\)</span>.</p>
+<p>This transform is different to the others in that it requires a <tt class="docutils literal"><span class="pre">length_scale</span></tt> attribute rather than a <tt class="docutils literal"><span class="pre">domain</span></tt> attribute, as the range of the lattice will depend on the number of basis functions used. The <tt class="docutils literal"><span class="pre">length_scale</span></tt> attribute defines the scale of the domain as the standard deviation <span class="math">\(\sigma\) [...]
+<div class="math">
+\[\psi_0(x) = (\sigma^2 \pi)^{-1/4} e^{-x^2/2 \sigma^2}\]</div>
+<p>When a dimension uses the “hermite-gauss” transform, then the variable indexing the basis functions is defined as the name of the dimension prefixed with an “n”.  For example, when referencing the basis function indices for the dimensions “x”, “y”, “z” and “tau”, use the variable “nx”, “ny”, “nz” and “ntau”.</p>
+<p>Applying the operator <tt class="docutils literal"><span class="pre">L</span> <span class="pre">=</span> <span class="pre">nx</span> <span class="pre">+</span> <span class="pre">0.5</span></tt> in Hermite space is therefore equivalent to applying the operator</p>
+<div class="math">
+\[\mathcal{L} = \left(- \frac{\sigma^2}{2}\frac{\partial^2}{\partial x^2} + \frac{1}{2 \sigma^2} x^2 \right)\]</div>
+<p>in coordinate space.</p>
+<p>The Hermite-Gauss transform permits one to work in energy-space for the harmonic oscillator.  The normal Fourier transform of “hermite-gauss” dimensions can also be referenced using the dimension name prefixed with a “k”.  See the examples <tt class="docutils literal"><span class="pre">hermitegauss_transform.xmds</span></tt> and <tt class="docutils literal"><span class="pre">hermitegauss_groundstate.xmds</span></tt> for examples.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><geometry></span>
+        <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+        <span class="nt"><transverse_dimensions></span>
+            <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"r"</span> <span class="na">lattice=</span><span class="s">"128"</span> <span class="na">length_scale=</span><span class="s">"1.0"</span> <span class="na">transform=</span><span class="s">"hermite-gauss"</span> <span class="nt">/></span>
+        <span class="nt"></transverse_dimensions></span>
+    <span class="nt"></geometry></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+</div>
+</div>
+<div class="section" id="vector-element">
+<span id="vectorelement"></span><h2>Vector Element<a class="headerlink" href="#vector-element" title="Permalink to this headline">¶</a></h2>
+<p>Vectors are arrays of data, defined over any subset of the transverse dimensions defined in your <a class="reference internal" href="#geometryelement"><em>Geometry Element</em></a>.  These dimensions are listed in the attribute <tt class="docutils literal"><span class="pre">dimensions</span></tt>, which can be an empty string if you wish the vector to not be defined on any dimensions.  If you do not include a <tt class="docutils literal"><span class="pre">dimensions</span></tt> attrib [...]
+<p>Each <tt class="docutils literal"><span class="pre"><vector></span></tt> element has a unique name, defined by a <tt class="docutils literal"><span class="pre">name</span></tt> attribute.  It is either complex-valued (the default) or real-valued, which can be specified using the <tt class="docutils literal"><span class="pre">type="real"</span></tt> attribute.</p>
+<p id="componentselement">A vector contains a list of variables, each defined by name in the <tt class="docutils literal"><span class="pre"><components></span></tt> element.  The name of each component is the name used to reference it later in the simulation.</p>
+<p>Vectors are initialised at the beginning of a simulation, either from code or from an input file.  The basis choice for this initialisation defaults to the normal space as defined in the <tt class="docutils literal"><span class="pre"><geometry></span></tt> element, but any transverse dimension can be initialised in their transform basis by specifying them in an <tt class="docutils literal"><span class="pre">initial_basis</span></tt> attribute.  The <tt class="docutils literal">< [...]
+<p id="initialisationelement">When initialising the vector within the XMDS script, the appropriate code is placed in a ‘CDATA’ block inside an <tt class="docutils literal"><span class="pre"><initialisation></span></tt> element.  This code is in standard C-syntax, and should reference the components of the vector by name.  XMDS defines a few useful <a class="reference internal" href="#xmdscsyntax"><em>shorthand macros</em></a> for this C-code.  If you wish to initialise  [...]
+<p id="referencingnonlocal">While the default XMDS behaviour is to reference all variables locally, any vector can be referenced non-locally.  The notation for referencing the value of a vector ‘phi’ with a dimension ‘j’ at a value of ‘j=jk’ is <tt class="docutils literal"><span class="pre">phi(j</span> <span class="pre">=></span> <span class="pre">jk)</span></tt>.  Multiple non-local dimensions are addressed by adding the references in a list, e.g. [...]
+<p>Dimensions can only be accessed non-locally if one of the following conditions is true:</p>
+<ul class="simple">
+<li>The dimension is an <tt class="docutils literal"><span class="pre">integer</span></tt> dimension,</li>
+<li>The dimension is accessed with an <a class="reference internal" href="advanced_topics.html#dimensionaliases"><em>alias</em></a> of that dimension. For example, <tt class="docutils literal"><span class="pre">phi(x</span> <span class="pre">=></span> <span class="pre">y)</span></tt> if the dimension <tt class="docutils literal"><span class="pre">x</span></tt> has <tt class="docutils literal"><span class="pre">y</span></tt> as an alias, or vice-versa.</li>
+<li>The dimension is a Fourier transform dimension (<tt class="docutils literal"><span class="pre">dft</span></tt>), used in the spectral basis (i.e. <tt class="docutils literal"><span class="pre">kx</span></tt> for an <tt class="docutils literal"><span class="pre">x</span></tt> dimension) and it is accessed with the negative of that dimension.  For example <tt class="docutils literal"><span class="pre">phi(kx</span> <span class="pre">=></span> <span class="pre">-kx)</span></tt>.</li>
+<li>The dimension is uniformly spaced (i.e. corresponds to the spatial basis of a dimension with a transform of <tt class="docutils literal"><span class="pre">dft</span></tt>, <tt class="docutils literal"><span class="pre">dct</span></tt>, <tt class="docutils literal"><span class="pre">dst</span></tt> or <tt class="docutils literal"><span class="pre">none</span></tt>), the dimension is symmetric about zero and it is accessed with the negative of the dimension name.  For example <tt class [...]
+<li>The dimension is uniformly spaced (i.e. corresponds to the spatial basis of a dimension with a transform of <tt class="docutils literal"><span class="pre">dft</span></tt>, <tt class="docutils literal"><span class="pre">dct</span></tt>, <tt class="docutils literal"><span class="pre">dst</span></tt> or <tt class="docutils literal"><span class="pre">none</span></tt>), and it is accessed with the lower limit of that dimension.  For example, <tt class="docutils literal"><span class="pre"> [...]
+<li><strong>Advanced behaviour</strong>: The value of a variable at an arbitrary point can be accessed via the integer index for that dimension. For example <tt class="docutils literal"><span class="pre">phi(x_index</span> <span class="pre">=></span> <span class="pre">3)</span></tt> accesses the value of <tt class="docutils literal"><span class="pre">phi</span></tt> at the grid point with index 3.  As <tt class="docutils literal"><span class="pre">x_index</span></tt> is zero-based, th [...]
+</ul>
+<p>Note that a dimension cannot be accessed non-locally in <tt class="docutils literal"><span class="pre">distributed-mpi</span></tt> simulations if the simulation is distributed across that dimension.</p>
+<p id="filenameelement">If you wish to initialise from a file, then you can choose to initialise from an hdf5 file using <tt class="docutils literal"><span class="pre">kind="hdf5"</span></tt> in the <tt class="docutils literal"><span class="pre"><initialisation></span></tt> element, and then supply the name of the input file with the <tt class="docutils literal"><span class="pre">filename</span></tt> element.  This is a standard data format which can be generated from XMD [...]
+<p>When initialising from a file, the default is to require the lattice of the transverse dimensions to exactly match the lattice defined by XMDS.  There is an option to import data defined on a subset or superset of the lattice points.  Obviously, the dimensionality of the imported field still has to be correct.  This option is activated by defining the attribute <tt class="docutils literal"><span class="pre">geometry_matching_mode="loose"</span></tt>.  The default option is d [...]
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><geometry></span>
+        <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+        <span class="nt"><transverse_dimensions></span>
+            <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"x"</span> <span class="na">lattice=</span><span class="s">"128"</span> <span class="na">domain=</span><span class="s">"(-1, 1)"</span> <span class="nt">/></span>
+        <span class="nt"></transverse_dimensions></span>
+    <span class="nt"></geometry></span>
+
+    <span class="c"><!-- A one-dimensional vector with dimension 'x' --></span>
+    <span class="nt"><vector</span> <span class="na">name=</span><span class="s">"wavefunction"</span> <span class="na">initial_basis=</span><span class="s">"x"</span> <span class="na">type=</span><span class="s">"complex"</span><span class="nt">></span>
+        <span class="nt"><components></span> phi <span class="nt"></components></span>
+        <span class="nt"><initialisation></span>
+            <span class="cp"><![CDATA[</span>
+                <span class="c1">// 'cis(x)' is cos(x) + i * sin(x)</span>
+                <span class="n">phi</span> <span class="o">=</span> <span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">x</span> <span class="o">*</span> <span class="n">x</span><span class="p">)</span> <span class="o">*</span> <span class="n">cis</span><span class="p">(</span><span class="mi">40</span> <span class="o">*</span> <span class="n">x</span><span class="p">);</span>
+            <span class="cp">]]></span>
+        <span class="nt"></initialisation></span>
+    <span class="nt"></vector></span>
+
+    <span class="c"><!-- A zero-dimensional real vector with components u and v --></span>
+    <span class="nt"><vector</span> <span class="na">name=</span><span class="s">"zero_dim"</span> <span class="na">dimensions=</span><span class="s">""</span> <span class="na">type=</span><span class="s">"real"</span><span class="nt">></span>
+        <span class="nt"><components></span>
+            u v
+        <span class="nt"></components></span>
+        <span class="nt"><initialisation</span> <span class="na">kind=</span><span class="s">"hdf5"</span><span class="nt">></span>
+            <span class="nt"><filename></span>data.h5<span class="nt"></filename></span>
+        <span class="nt"></initialisation></span>
+    <span class="nt"></vector></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+<div class="section" id="the-dependencies-element">
+<span id="dependencies"></span><h3>The dependencies element<a class="headerlink" href="#the-dependencies-element" title="Permalink to this headline">¶</a></h3>
+<p>Often a vector, computed vector, filter, integration operator or output group will reference the values in one or more other vectors, computed vectors or noise vectors.  These dependencies are defined via a <tt class="docutils literal"><span class="pre"><dependencies></span></tt> element, which lists the names of the vectors.  The components of those vectors will then be available for use in the ‘CDATA’ block, and can be referenced by their name.</p>
+<p>For a vector, the basis of the dependent vectors, and therefore the basis of the dimensions available in the ‘CDATA’ block, are defined by the <tt class="docutils literal"><span class="pre">initial_basis</span></tt> of the vector.  For a <tt class="docutils literal"><span class="pre"><computed_vector></span></tt>, <tt class="docutils literal"><span class="pre"><filter></span></tt> <tt class="docutils literal"><span class="pre"><integration_vector></span>< [...]
+<p>Any transverse dimensions that appear in the <tt class="docutils literal"><span class="pre"><dependencies></span></tt> element that do not appear in the <tt class="docutils literal"><span class="pre">dimensions</span></tt> attribute of the vector are integrated out.  For integer dimensions, this is simply an implicit sum over the dimension.  For real-valued dimensions, this is an implicit integral over the range of that dimension.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><geometry></span>
+        <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+        <span class="nt"><transverse_dimensions></span>
+            <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"x"</span> <span class="na">lattice=</span><span class="s">"128"</span> <span class="na">domain=</span><span class="s">"(-1, 1)"</span> <span class="nt">/></span>
+            <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"y"</span> <span class="na">lattice=</span><span class="s">"10"</span> <span class="na">domain=</span><span class="s">"(-3, 2)"</span> <span class="na">transform=</span><span class="s">"dct"</span> <span class="nt">/></span>
+        <span class="nt"></transverse_dimensions></span>
+    <span class="nt"></geometry></span>
+
+    <span class="c"><!-- A one-dimensional vector with dimension 'x' --></span>
+    <span class="nt"><vector</span> <span class="na">name=</span><span class="s">"wavefunction"</span> <span class="na">dimensions=</span><span class="s">"x"</span> <span class="na">initial_basis=</span><span class="s">"x"</span> <span class="na">type=</span><span class="s">"complex"</span><span class="nt">></span>
+        <span class="nt"><components></span> phi <span class="nt"></components></span>
+        <span class="nt"><initialisation></span>
+            <span class="c"><!--</span>
+<span class="c">                The initialisation of the vector 'wavefunction' depends on information</span>
+<span class="c">                in the 'two_dim' vector.  The vector two_dim is DCT-transformed into the</span>
+<span class="c">                (x, ky) basis, and the ky dimension is implicitly integrated over in the</span>
+<span class="c">                following initialisation code</span>
+<span class="c">              --></span>
+            <span class="nt"><dependencies</span> <span class="na">basis=</span><span class="s">"x ky"</span><span class="nt">></span>two_dim<span class="nt"></dependencies></span>
+            <span class="cp"><![CDATA[</span>
+                <span class="c1">// 'cis(x)' is cos(x) + i * sin(x)</span>
+                <span class="n">phi</span> <span class="o">=</span> <span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">x</span> <span class="o">*</span> <span class="n">x</span> <span class="o">+</span> <span class="n">v</span><span class="p">)</span> <span class="o">*</span> <span class="n">cis</span><span class="p">(</span><span class="n">u</span> <span class="o">*</span> <span class="n">x</span [...]
+            <span class="cp">]]></span>
+        <span class="nt"></initialisation></span>
+    <span class="nt"></vector></span>
+
+    <span class="c"><!-- A two-dimensional real vector with components u and v --></span>
+    <span class="nt"><vector</span> <span class="na">name=</span><span class="s">"two_dim"</span> <span class="na">type=</span><span class="s">"real"</span><span class="nt">></span>
+        <span class="nt"><components></span>
+            u v
+        <span class="nt"></components></span>
+        <span class="nt"><initialisation</span> <span class="na">kind=</span><span class="s">"hdf5"</span><span class="nt">></span>
+            <span class="nt"><filename></span>data.h5<span class="nt"></filename></span>
+        <span class="nt"></initialisation></span>
+    <span class="nt"></vector></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+</div>
+</div>
+<div class="section" id="computed-vector-element">
+<span id="computedvectorelement"></span><h2>Computed Vector Element<a class="headerlink" href="#computed-vector-element" title="Permalink to this headline">¶</a></h2>
+<p id="evaluationelement">Computed vectors are arrays of data much like normal <tt class="docutils literal"><span class="pre"><vector></span></tt> elements, but they are always calculated as they are referenced, so they cannot be initialised from file.  It is defined with a <tt class="docutils literal"><span class="pre"><computed_vector></span></tt> element, which has a <tt class="docutils literal"><span class="pre">name</span></tt> attribute, optional <tt class="docutils lit [...]
+<p>As it is not being stored, a <tt class="docutils literal"><span class="pre"><computed_vector></span></tt> does not have or require an <tt class="docutils literal"><span class="pre">initial_basis</span></tt> attribute, as it will be transformed into an appropriate basis for the element that references it.  The basis for its evaluation will be determined entirely by the <tt class="docutils literal"><span class="pre">basis</span></tt> attribute of the <tt class="docutils literal">< [...]
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><geometry></span>
+        <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+        <span class="nt"><transverse_dimensions></span>
+            <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"x"</span> <span class="na">lattice=</span><span class="s">"128"</span> <span class="na">domain=</span><span class="s">"(-1, 1)"</span> <span class="nt">/></span>
+        <span class="nt"></transverse_dimensions></span>
+    <span class="nt"></geometry></span>
+
+    <span class="c"><!-- A one-dimensional vector with dimension 'x' --></span>
+    <span class="nt"><vector</span> <span class="na">name=</span><span class="s">"wavefunction"</span> <span class="na">type=</span><span class="s">"complex"</span><span class="nt">></span>
+        <span class="nt"><components></span> phi <span class="nt"></components></span>
+        <span class="nt"><initialisation></span>
+            <span class="cp"><![CDATA[</span>
+                <span class="c1">// 'cis(x)' is cos(x) + i * sin(x)</span>
+                <span class="n">phi</span> <span class="o">=</span> <span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span> <span class="o">*</span> <span class="n">x</span> <span class="o">*</span> <span class="n">x</span><span class="p">)</span> <span class="o">*</span> <span class="n">cis</span><span class="p">(</span><span class="mi">40</span> <span class="o">*</span> <span class="n">x</span><span class="p">);</span>
+            <span class="cp">]]></span>
+        <span class="nt"></initialisation></span>
+    <span class="nt"></vector></span>
+
+    <span class="c"><!-- A zero-dimensional real computed vector with components Ncalc --></span>
+    <span class="nt"><computed_vector</span> <span class="na">name=</span><span class="s">"zero_dim"</span> <span class="na">dimensions=</span><span class="s">""</span> <span class="na">type=</span><span class="s">"real"</span><span class="nt">></span>
+        <span class="nt"><components></span>
+            Ncalc
+        <span class="nt"></components></span>
+        <span class="nt"><evaluation></span>
+            <span class="nt"><dependencies></span>wavefunction<span class="nt"></dependencies></span>
+            <span class="cp"><![CDATA[</span>
+                <span class="c1">// Implicitly integrating over the dimension 'x'</span>
+                <span class="n">Ncalc</span> <span class="o">=</span> <span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">);</span>
+            <span class="cp">]]></span>
+        <span class="nt"></evaluation></span>
+    <span class="nt"></computed_vector></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="noise-vector-element">
+<span id="noisevectorelement"></span><h2>Noise Vector Element<a class="headerlink" href="#noise-vector-element" title="Permalink to this headline">¶</a></h2>
+<p>Noise vectors are used like computed vectors, but when they are evaluated they generate arrays of random numbers of various kinds.  They do not depend on other vectors, and are not initialised by code.  They are defined by a <tt class="docutils literal"><span class="pre"><noise_vector></span></tt> element, which has a <tt class="docutils literal"><span class="pre">name</span></tt> attribute, and optional <tt class="docutils literal"><span class="pre">dimensions</span></tt>, <tt  [...]
+<p>The choice of pseudo-random number generator (RNG) can be specified with the <tt class="docutils literal"><span class="pre">method</span></tt> attribute, which has options “posix” (the default), “mkl”, “solirte” and “dsfmt”.  It is only possible to use any particular method if that library is available.  Although “posix” is the default, it is also the slowest, and produces the lowest quality random numbers (although this is t [...]
+<p>The random number generators can be provided with a seed using the <tt class="docutils literal"><span class="pre">seed</span></tt> attribute, which should typically consist of a list of three integers.  All RNGs require positive integers as seeds.  It is possible to use the <a class="reference internal" href="#validation"><em><validation kind=”run-time”/></em></a> feature to use passed variables as seeds.  It is advantageous to use fixed seeds rather than timer-based [...]
+<p>The different types of noise vectors are defined by a mandatory <tt class="docutils literal"><span class="pre">kind</span></tt> attribute, which must take the value of ‘gauss’, ‘gaussian’, ‘wiener’, ‘poissonian’,’jump’ or ‘uniform’.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><geometry></span>
+        <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+        <span class="nt"><transverse_dimensions></span>
+            <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"x"</span> <span class="na">lattice=</span><span class="s">"128"</span> <span class="na">domain=</span><span class="s">"(-1, 1)"</span> <span class="nt">/></span>
+        <span class="nt"></transverse_dimensions></span>
+    <span class="nt"></geometry></span>
+
+    <span class="c"><!--</span>
+<span class="c">        A one-dimensional complex wiener noise vector.</span>
+<span class="c">        This noise is appropriate for using in the complex</span>
+<span class="c">        random-walk equation of motion:</span>
+<span class="c">            dz_dt = eta;</span>
+<span class="c">    --></span>
+    <span class="nt"><noise_vector</span> <span class="na">name=</span><span class="s">"noise"</span> <span class="na">kind=</span><span class="s">"wiener"</span><span class="nt">></span>
+        <span class="nt"><components></span>
+            eta
+        <span class="nt"></components></span>
+    <span class="nt"></vector></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+<div class="section" id="uniform-noise">
+<span id="uniformnoise"></span><h3>Uniform noise<a class="headerlink" href="#uniform-noise" title="Permalink to this headline">¶</a></h3>
+<p>Uniform noises defined over any transverse dimensions are simply uniformly distributed random numbers between zero and one.  This noise is an example of a “static” noise, i.e. one suitable for initial conditions of a field.  If it were included in the equations of motion for a field, then the effect of the noise would depend on the lattice spacing of the propagation dimension.  XMDS therefore does not allow this noise type to be used in integration elements.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><noise_vector</span> <span class="na">name=</span><span class="s">"drivingNoise"</span> <span class="na">dimensions=</span><span class="s">"x"</span> <span class="na">kind=</span><span class="s">"uniform"</span> <span class="na">type=</span><span class="s">"complex"</span> <span class="na">method=</span><span class="s">"dsfmt"</span> <span class="na">seed=</span><span class="s">"314 159 276"</span><span c [...]
+      <span class="nt"><components></span>Eta<span class="nt"></components></span>
+    <span class="nt"></noise_vector></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="gaussian-noise">
+<span id="gaussiannoise"></span><h3>Gaussian noise<a class="headerlink" href="#gaussian-noise" title="Permalink to this headline">¶</a></h3>
+<p>Noise generated with the “gaussian” method is gaussian distributed with zero mean.  For a real-valued noise vector, the variance at each point is the inverse of the volume element of the transverse dimensions in the vector.  This volume element for a single transverse dimension is that used to perform integrals over that dimension.  For example, it would include a factor of <span class="math">\(r^2\)</span> for a dimension “r” defined with a <tt class="docutils [...]
+<p>This lattice-dependent variance is typical in most applications of partial differential equations with stochastic initial conditions, as the physical quantity is the variance of the field over some finite volume, which does not change if the variance at each lattice site varies as described above.</p>
+<p>For complex-valued noise vector, the real and imaginary parts of the noise are independent, and each have half the variance of a real-valued noise.  This means that the modulus squared of a complex-valued noise vector has the same variance as a real-valued noise vector at each point.</p>
+<p>Gaussian noise vectors are an example of a “static” noise, i.e. one suitable for initial conditions of a field.  If they were included in the equations of motion for a field, then the effect of the noise would depend on the lattice spacing of the propagation dimension.  XMDS therefore does not allow this noise type to be used in integration elements.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><noise_vector</span> <span class="na">name=</span><span class="s">"initialNoise"</span> <span class="na">dimensions=</span><span class="s">"x"</span> <span class="na">kind=</span><span class="s">"gauss"</span> <span class="na">type=</span><span class="s">"real"</span> <span class="na">method=</span><span class="s">"posix"</span> <span class="na">seed=</span><span class="s">"314 159 276"</span><span class= [...]
+      <span class="nt"><components></span>fuzz<span class="nt"></components></span>
+    <span class="nt"></noise_vector></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="wiener-noise">
+<span id="wienernoise"></span><h3>Wiener noise<a class="headerlink" href="#wiener-noise" title="Permalink to this headline">¶</a></h3>
+<p>Noise generated with the “wiener” method is gaussian distributed with zero mean and the same variance as the static “gaussian” noise defined above, multiplied by a factor of the lattice step in the propagation dimension.  This means that these noise vectors can be used to define Wiener noises for standard stochastic ordinary or partial differential equations.  Most integrators in XMDS effectively interpret these noises as Stratonovich increments.</p>
+<p>As a dynamic noise, a Wiener process is not well-defined except in an <tt class="docutils literal"><span class="pre">integrate</span></tt> element.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><noise_vector</span> <span class="na">name=</span><span class="s">"diffusion"</span> <span class="na">dimensions=</span><span class="s">"x"</span> <span class="na">kind=</span><span class="s">"wiener"</span> <span class="na">type=</span><span class="s">"real"</span> <span class="na">method=</span><span class="s">"solirte"</span> <span class="na">seed=</span><span class="s">"314 159 276"</span><span class= [...]
+      <span class="nt"><components></span>dW<span class="nt"></components></span>
+    <span class="nt"></noise_vector></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="poissonian-noise">
+<span id="poissioniannoise"></span><h3>Poissonian noise<a class="headerlink" href="#poissonian-noise" title="Permalink to this headline">¶</a></h3>
+<p>A noise vector using the “poissonian” method generates a random variable from a Poissonian distribution.  While the the Poisson distribution is integer-valued, the variable will be cast as a real number.  The rate of the Poissonian distribution is defined by the <tt class="docutils literal"><span class="pre">mean</span></tt> or <tt class="docutils literal"><span class="pre">mean-density</span></tt> attributes.  These are are synonyms, and must be defined as positive real n [...]
+<p>Poissonian noise vectors are an example of a “static” noise, i.e. one suitable for initial conditions of a field.  If they were included in the equations of motion for a field, then the effect of the noise would depend on the lattice spacing of the propagation dimension.  XMDS therefore does not allow this noise type to be used in integration elements.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><noise_vector</span> <span class="na">name=</span><span class="s">"initialDistribution"</span> <span class="na">dimensions=</span><span class="s">"x"</span> <span class="na">kind=</span><span class="s">"poissonian"</span> <span class="na">type=</span><span class="s">"real"</span> <span class="na">mean-density=</span><span class="s">"2.7"</span> <span class="na">method=</span><span class="s">"solirte"</spa [...]
+      <span class="nt"><components></span>Pdist<span class="nt"></components></span>
+    <span class="nt"></noise_vector></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="jump-noise">
+<span id="jumpnoise"></span><h3>Jump noise<a class="headerlink" href="#jump-noise" title="Permalink to this headline">¶</a></h3>
+<p>A noise vector using the “jump” method is the dynamic version of the poissonian noise method, and must have the <tt class="docutils literal"><span class="pre">mean-rate</span></tt> attribute specified as a positive real number.  The variable at each point is chosen from a Poissonian distribution with a mean equal to the product of three variables: the <tt class="docutils literal"><span class="pre">mean-rate</span></tt> attribute; the volume of the element as defined by its [...]
+<p>It is common to wish to vary the mean rate of a jump process, which means that the <tt class="docutils literal"><span class="pre">mean-rate</span></tt> attribute must be a variable or a piece of code.  These cannot be verified to be a positive real number at compile time, so they must be used with the <a class="reference internal" href="#validation"><em><validation></em></a> feature with either the <tt class="docutils literal"><span class="pre">kind="none"</span></tt>  [...]
+<p>As a dynamic noise, a jump process is not well-defined except in an <tt class="docutils literal"><span class="pre">integrate</span></tt> element.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><noise_vector</span> <span class="na">name=</span><span class="s">"initialDistribution"</span> <span class="na">dimensions=</span><span class="s">""</span> <span class="na">kind=</span><span class="s">"jump"</span> <span class="na">type=</span><span class="s">"real"</span> <span class="na">mean-rate=</span><span class="s">"2.7"</span> <span class="na">method=</span><span class="s">"solirte"</span> <span c [...]
+      <span class="nt"><components></span>dN<span class="nt"></components></span>
+    <span class="nt"></noise_vector></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+</div>
+</div>
+<div class="section" id="sequence-element">
+<span id="sequenceelement"></span><h2>Sequence Element<a class="headerlink" href="#sequence-element" title="Permalink to this headline">¶</a></h2>
+<p>All processing of vectors happens in sequence elements.  Each simulation must have exactly one main sequence element, but it can then contain any number of nested sequence elements.  A sequence element can contain any number of <tt class="docutils literal"><span class="pre"><sequence></span></tt>, <a class="reference internal" href="#filterelement"><em><filter></em></a>, <a class="reference internal" href="#integrateelement"><em><integrate></em></a> and/or <a class=" [...]
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+    <span class="nt"><sequence</span> <span class="na">cycles=</span><span class="s">"2"</span><span class="nt">></span>
+        <span class="nt"><sequence></span>  ... <span class="nt"></sequence></span>
+        <span class="nt"><filter></span> ... <span class="nt"></filter></span>
+        <span class="nt"><integrate></span> ...<span class="nt"></integrate></span>
+    <span class="nt"></sequence></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="filter-element">
+<span id="filterelement"></span><h2>Filter element<a class="headerlink" href="#filter-element" title="Permalink to this headline">¶</a></h2>
+<p>A <tt class="docutils literal"><span class="pre"><filter></span></tt> element can be placed inside a <tt class="docutils literal"><span class="pre"><sequence></span></tt> element or an <a class="reference internal" href="#integrateelement"><em><integrate></em></a> element.  It contains a ‘CDATA’ block and an optional <a class="reference internal" href="#dependencies"><em><dependencies></em></a> element, which may give access to variables in other <t [...]
+<p>Sometimes it is desirable to apply a filter conditionally.  The most efficient way of doing this is to call the function from the piece of code that contains the conditional statement (likely another <tt class="docutils literal"><span class="pre"><filter></span></tt> element) rather than embed the conditional function in the filter itself, as the latter method can involve the conditional statement being evaluated multiple times over the transverse dimensions.  For this reason, i [...]
+<p>One of the common uses of a filter element is to apply discontinuous changes to the vectors and variables of the simulation.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><sequence></span>
+    <span class="nt"><filter></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">printf</span><span class="p">(</span><span class="s">"Hello world from the first filter segment!  This filter rather wastefully calls the second one.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
+        <span class="n">fname</span><span class="p">();</span>
+      <span class="cp">]]></span>
+    <span class="nt"></filter></span>
+
+    <span class="nt"><filter</span> <span class="na">name=</span><span class="s">"fname"</span><span class="nt">></span>
+       <span class="nt"><dependencies></span>normalisation wavefunction<span class="nt"></dependencies></span>
+       <span class="cp"><![CDATA[</span>
+         <span class="n">phi</span> <span class="o">*=</span> <span class="n">sqrt</span><span class="p">(</span><span class="n">Nparticles</span><span class="o">/</span><span class="n">Ncalc</span><span class="p">);</span>
+       <span class="cp">]]></span>
+    <span class="nt"></filter></span>
+<span class="nt"></sequence></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="integrate-element">
+<span id="integrateelement"></span><h2>Integrate element<a class="headerlink" href="#integrate-element" title="Permalink to this headline">¶</a></h2>
+<p>The <tt class="docutils literal"><span class="pre"><integrate></span></tt> element is at the heart of most XMDS simulations.  It is used to integrate a set of (potentially stochastic) first-order differential equations for one or more of the vectors defined using the <tt class="docutils literal"><span class="pre"><vector></span></tt> element along the propagation dimension.  At the beginning of the simulation, the value of the propagation dimension is set to zero, and the  [...]
+<p>The length of the integration is defined by the <tt class="docutils literal"><span class="pre">interval</span></tt> attribute, which must be a positive real number.  An <tt class="docutils literal"><span class="pre"><integrate></span></tt> element must have an <tt class="docutils literal"><span class="pre">algorithm</span></tt> attribute defined, which defines the integration method.  Current methods include <a class="reference internal" href="#si"><em>SI</em></a>, <a class="ref [...]
+<p id="sampleselement">The optional <tt class="docutils literal"><span class="pre"><samples></span></tt> element is used to track the evolution of one or more vectors or variables during an integration.  This element must contain a non-negative integer for each <a class="reference internal" href="#samplinggroupelement"><em><sampling_group></em></a> element defined in the simulation’s <a class="reference internal" href="#outputelement"><em><output></em></a> element [...]
+<p>The vectors to be integrated and the form of the differential equations are defined in the <a class="reference internal" href="#operatorselement"><em><operators></em></a> element (or elements).  Filters to be applied each step can be defined with optional <a class="reference internal" href="#filterselement"><em><filters></em></a> elements.</p>
+<p>Computed vectors can be defined with the <tt class="docutils literal"><span class="pre"><computed_vector></span></tt> element.  These act exactly like a globally defined <a class="reference internal" href="#computedvectorelement"><em>Computed Vector Element</em></a>, but are only available within the single <tt class="docutils literal"><span class="pre"><integrate></span></tt> element.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><integrate</span> <span class="na">algorithm=</span><span class="s">"ARK89"</span> <span class="na">interval=</span><span class="s">"1e-4"</span> <span class="na">steps=</span><span class="s">"10000"</span> <span class="na">tolerance=</span><span class="s">"1e-8"</span><span class="nt">></span>
+  <span class="nt"><samples></span>20<span class="nt"></samples></span>
+  <span class="nt"><filters></span>
+    <span class="nt"><filter></span>
+      <span class="nt"><dependencies></span>wavefunction normalisation<span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">phi</span> <span class="o">*=</span> <span class="n">sqrt</span><span class="p">(</span><span class="n">Nparticles</span><span class="o">/</span><span class="n">Ncalc</span><span class="p">);</span>   <span class="c1">// Correct normalisation of the wavefunction</span>
+      <span class="cp">]]></span>
+    <span class="nt"></filter></span>
+  <span class="nt"></filters></span>
+  <span class="nt"><operators></span>
+    <span class="nt"><operator</span> <span class="na">kind=</span><span class="s">"ip"</span> <span class="na">constant=</span><span class="s">"yes"</span><span class="nt">></span>
+      <span class="nt"><operator_names></span>T<span class="nt"></operator_names></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">T</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span><span class="o">*</span><span class="n">hbar</span><span class="o">/</span><span class="n">M</span><span class="o">*</span><span class="n">ky</span><span class="o">*</span><span class="n">ky</span><span class="p">;</span>
+      <span class="cp">]]></span>
+    <span class="nt"></operator></span>
+    <span class="nt"><dependencies></span>potential<span class="nt"></dependencies></span>
+    <span class="cp"><![CDATA[</span>
+      <span class="n">dphi_dt</span> <span class="o">=</span> <span class="n">T</span><span class="p">[</span><span class="n">phi</span><span class="p">]</span> <span class="o">-</span> <span class="p">(</span><span class="n">V1</span> <span class="o">+</span> <span class="n">Uint</span><span class="o">/</span><span class="n">hbar</span><span class="o">*</span><span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">))</span><span class="o">*</span><s [...]
+    <span class="cp">]]></span>
+    <span class="nt"><integration_vectors></span>wavefunction<span class="nt"></integration_vectors></span>
+  <span class="nt"></operators></span>
+<span class="nt"></integrate></span>
+</pre></div>
+</div>
+<div class="section" id="operators-and-operator-elements">
+<span id="operatorselement"></span><h3>Operators and operator elements<a class="headerlink" href="#operators-and-operator-elements" title="Permalink to this headline">¶</a></h3>
+<p>An <a class="reference internal" href="#integrateelement"><em><integrate></em></a> element must contain one or more <tt class="docutils literal"><span class="pre"><operators></span></tt> elements, which define both which vectors are to be integrated, and their derivative in the propagation dimension.  When all vectors to be integrated have the same dimensionality, they can all be defined within a single <tt class="docutils literal"><span class="pre"><operators></span [...]
+<p id="integrationvectorselement">Within each <tt class="docutils literal"><span class="pre"><operators></span></tt> element, the vectors that are to be integrated are listed by name in the <tt class="docutils literal"><span class="pre"><integration_vectors></span></tt> element, and the differential equations are written in a ‘CDATA’ block.   The derivative of each component of the integration vectors must be defined along the propagation dimension.  For example,  [...]
+<p>When noise vectors are referenced, equations with Wiener noises should be written as though the equations are in differential form, as described in the worked examples <a class="reference internal" href="worked_examples.html#kubo"><em>Kubo Oscillator</em></a> and <a class="reference internal" href="worked_examples.html#fibre"><em>Fibre Noise</em></a>.  Jump-based Poisson noises will also be written in an equivalent form, as modelled by the example <tt class="docutils literal"><span cl [...]
+<p>By default, the name of each component references the local value of the vector, but <a class="reference internal" href="#referencingnonlocal"><em>nonlocal variables</em></a> can be accessed using the standard syntax.  However, typically the most common (and most efficient) method of referencing nonlocal variables is to reference variables that are local in the <a class="reference internal" href="#transforms"><em>transformed space</em></a> for a given transverse dimension.  This is do [...]
+<p id="operatorelement">There are three kinds of <tt class="docutils literal"><span class="pre"><operator></span></tt> elements.  The first is denoted with a <tt class="docutils literal"><span class="pre">kind="functions"</span></tt> attribute, and contains a ‘CDATA’ block that will be executed in the order that it is defined.  This is useful when you wish to calculate functions that do not depend on the transverse dimensions.  Defining these along with the ma [...]
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><operator</span> <span class="na">kind=</span><span class="s">"functions"</span><span class="nt">></span>
+  <span class="cp"><![CDATA[</span>
+  <span class="n">f</span> <span class="o">=</span> <span class="n">cos</span><span class="p">(</span><span class="n">t</span><span class="p">);</span>
+  <span class="cp">]]></span>
+<span class="nt"></operator></span>
+</pre></div>
+</div>
+<p id="operatornameselement">The second kind of operator element defines a list of operators in an <tt class="docutils literal"><span class="pre"><operator_names></span></tt> element.  The basis of these operators defaults to the transform space unless a different basis is specified using the <tt class="docutils literal"><span class="pre">basis</span></tt> attribute.  These operators must then be defined in a ‘CDATA’ block, using any <a class="reference internal" href=" [...]
+<p>Operators of this second kind have the <tt class="docutils literal"><span class="pre">kind="IP"</span></tt> or <tt class="docutils literal"><span class="pre">kind="EX"</span></tt> attribute, standing for ‘interaction picture’ and ‘explicit’ operators respectively.  Explicit operators can be used in all situations, and simply construct and calculate a new vector of the form in the square brackets.  IP operators use less memory and can improve [...]
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><operator</span> <span class="na">kind=</span><span class="s">"ex"</span> <span class="na">constant=</span><span class="s">"yes"</span><span class="nt">></span>
+  <span class="nt"><operator_names></span>T<span class="nt"></operator_names></span>
+  <span class="cp"><![CDATA[</span>
+    <span class="n">T</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span><span class="o">*</span><span class="n">hbar</span><span class="o">/</span><span class="n">M</span><span class="o">*</span><span class="n">ky</span><span class="o">*</span><span class="n">ky</span><span class="p">;</span>
+  <span class="cp">]]></span>
+<span class="nt"></operator></span>
+</pre></div>
+</div>
+<p>The third kind of operator element is used to define an integration along a transverse dimension.  This kind of evolution is called “cross-propagation”, and is described briefly in the examples ‘tla.xmds’, ‘tla_sic.xmds’ and ‘sine_cross.xmds’.  This class of equations have a subset of vectors that have an initial condition on one side of a transverse dimension, and a differential equation defined in that dimension, and as such, this kind [...]
+<p>An operator element with the <tt class="docutils literal"><span class="pre">kind="cross_propagation"</span></tt> attribute must specify the transverse dimension along which the integration would proceed with the <tt class="docutils literal"><span class="pre">propagation_dimension</span></tt> attribute.  It must also specify its own <a class="reference internal" href="#integrationvectorselement"><em><integration_vectors></em></a> element, its own <tt class="docutils lit [...]
+<p id="boundaryconditionelement">The boundary conditions are specified by a <tt class="docutils literal"><span class="pre"><boundary_conditions></span></tt> element, which requires the <tt class="docutils literal"><span class="pre">kind="left"</span></tt> or <tt class="docutils literal"><span class="pre">kind="right"</span></tt> attribute to specify on which side of the grid that the boundary conditions are specified.  The boundary conditions for the <tt class=" [...]
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><operator</span> <span class="na">kind=</span><span class="s">"cross_propagation"</span> <span class="na">algorithm=</span><span class="s">"RK4"</span> <span class="na">propagation_dimension=</span><span class="s">"t"</span><span class="nt">></span>
+  <span class="nt"><integration_vectors></span>cross<span class="nt"></integration_vectors></span>
+  <span class="nt"><dependencies></span>constants<span class="nt"></dependencies></span>
+  <span class="nt"><boundary_condition</span> <span class="na">kind=</span><span class="s">"left"</span><span class="nt">></span>
+    <span class="cp"><![CDATA[</span>
+      <span class="n">v</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">;</span>
+      <span class="n">w</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">;</span>
+    <span class="cp">]]></span>
+  <span class="nt"></boundary_condition></span>
+
+  <span class="nt"><operator</span> <span class="na">kind=</span><span class="s">"ip"</span> <span class="na">constant=</span><span class="s">"yes"</span><span class="nt">></span>
+    <span class="nt"><operator_names></span>L<span class="nt"></operator_names></span>
+    <span class="cp"><![CDATA[</span>
+      <span class="n">L</span> <span class="o">=</span> <span class="kc">i</span><span class="p">;</span>
+    <span class="cp">]]></span>
+  <span class="nt"></operator></span>
+
+  <span class="cp"><![CDATA[</span>
+    <span class="n">dv_dt</span> <span class="o">=</span> <span class="kc">i</span><span class="o">*</span><span class="n">v</span><span class="p">;</span>
+    <span class="n">dw_dt</span> <span class="o">=</span> <span class="n">L</span><span class="p">[</span><span class="n">w</span><span class="p">];</span>
+  <span class="cp">]]></span>
+<span class="nt"></operator></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="algorithms">
+<span id="id8"></span><h3>Algorithms<a class="headerlink" href="#algorithms" title="Permalink to this headline">¶</a></h3>
+<p>The stability, efficiency and even convergence of a numerical integration can depend on the method.  Due to the varying properties of different sets of equations, it is impossible to define the best method for all equations, so XMDS provides an option to use different algorithms.  These include fixed step algorithms, which divide the integration region into equal steps, and adaptive stepsize algorithms, which attempt to estimate the error in the simulation in order to choose an approp [...]
+<p>For the purposes of the descriptions below, we will assume that we are considering the following set of coupled differential equations for the vector of variables <span class="math">\(\mathbf{x}(t)\)</span>:</p>
+<div class="math">
+\[\frac{d x_j}{dt} = f_j(\mathbf{x}(t),t)\]</div>
+<div class="section" id="si-and-sic-algorithms">
+<span id="si"></span><h4>SI and SIC algorithms<a class="headerlink" href="#si-and-sic-algorithms" title="Permalink to this headline">¶</a></h4>
+<p>The SI algorithm is a semi-implicit fixed-step algorithm that finds the increment of the vector by solving</p>
+<div class="math">
+\[x_j(t+\Delta t) = x_j(t) + f_j\left(\mathbf{x}(t+\frac{\Delta t}{2}),t+\frac{\Delta t}{2}\right) \;\Delta t\]</div>
+<p>using a simple iteration to find the values of the vector at the midpoint of the step self-consistently.  The number of iterations can be set using the <tt class="docutils literal"><span class="pre">iterations</span></tt> attribute, and it defaults to <tt class="docutils literal"><span class="pre">iterations="3"</span></tt>.  The choice of <tt class="docutils literal"><span class="pre">iterations="1"</span></tt> is therefore fully equivalent to the Euler algorithm, [...]
+<div class="math">
+\[x_j(t+\Delta t) = x_j(t) + f_j\left(\mathbf{x}(t),t\right) \;\Delta t.\]</div>
+<p>The Euler algorithm is the only safe algorithm for direct integration of <a class="reference internal" href="#jumpnoise"><em>jump-based Poisson processes</em></a>.  Efficient numerical solution of those types of equations is best done via a process of triggered filters, which will be described in the <a class="reference internal" href="advanced_topics.html#advancedtopics"><em>Advanced Topics</em></a> section.  Integrating using the Euler algorithm computes the Ito integral, as opposed [...]
+<p>When SI integration is used in conjunction with SI cross-propagation, a slight variant of the SI algorithm can be employed where the integration in both directions is contained within the iteration process.  This is activated by using <tt class="docutils literal"><span class="pre">algorithm="SIC"</span></tt> rather than <tt class="docutils literal"><span class="pre">algorithm="SI"</span></tt>.</p>
+<p>The SI algorithm is correct to second order in the step-size for deterministic equations, and first order in the step-size for Stratonovich stochastic equations with Wiener noises.  This makes it the highest order stochastic algorithm in XMDS, although there are many sets of equations that integrate more efficiently with lower order algorithms.  When called with the <tt class="docutils literal"><span class="pre">iterations="1"</span></tt> option (the Euler algorithm), it is  [...]
+</div>
+<div class="section" id="runge-kutta-algorithms">
+<span id="rk4"></span><h4>Runge-Kutta algorithms<a class="headerlink" href="#runge-kutta-algorithms" title="Permalink to this headline">¶</a></h4>
+<p>Runge-Kutta algorithms are the workhorse of numerical integration, and XMDS employs two fixed step versions: <tt class="docutils literal"><span class="pre">algorithm="RK4"</span></tt>, which is correct to fourth-order in the step size, and <tt class="docutils literal"><span class="pre">algorithm="RK9"</span></tt>, which is correct to ninth order in the step size.  It must be strongly noted that a higher order of convergence does not automatically mean a superior al [...]
+<p>All Runge-Kutta algorithms are convergent for Stratonovich stochastic equations at the order of the square root of the step-size.  This ‘half-order’ convergence may seem very weak, but for some classes of stochastic equation this improves up to one half of the deterministic order of convergence.  Also, the convergence of some stochastic equations is limited by the ‘deterministic part’, which can be improved dramatically by using a higher order Runge-Kutta method.</p>
+</div>
+<div class="section" id="adaptive-runge-kutta-algorithms">
+<span id="ark45"></span><h4>Adaptive Runge-Kutta algorithms<a class="headerlink" href="#adaptive-runge-kutta-algorithms" title="Permalink to this headline">¶</a></h4>
+<p>Fixed step integrators can encounter two issues.  First, as the equations or parameters of a simulation are changed, the minimum number of steps required to integrate it may change.  This means that the convergence must be re-tested multiple times for each set of parameters, as overestimating the number of steps required to perform an integration to a specified error tolerance can be very inefficient. Second, even if the minimum acceptable number of steps required is known for a given [...]
+algorithms get around this problem by testing the convergence during the integration, and adjusting the step-size until it reaches some target tolerance.</p>
+<p>XMDS employs two adaptive step-size algorithms based on ‘embedded Runge-Kutta’ methods.  These are Runge-Kutta methods that can output multiple variables that have different convergence.  The difference between the higher-order and the lower-order solutions gives an estimate of the error in each step, which can then be used to estimate an appropriate size for the next step.  We use <tt class="docutils literal"><span class="pre">algorthim="ARK45"</span></tt>, whic [...]
+<p>All adaptive stepsize algorithms require a <tt class="docutils literal"><span class="pre">tolerance</span></tt> attribute, which must be a positive real number that defines the allowable error per step.  It is also possible to specify a <tt class="docutils literal"><span class="pre">max_iterations</span></tt> attribute, which is a positive integer that stops the integrator from trying too many times to find an acceptable stepsize.  The integrator will abort with an error if the number [...]
+<p>As all Runge-Kutta solutions have equal order of convergence for stochastic equations, <em>if the step-size is limited by the stochastic term then the step-size estimation is entirely unreliable</em>.  Adaptive Runge-Kutta algorithms are therefore not appropriate for stochastic equations.</p>
+</div>
+</div>
+<div class="section" id="filters-element">
+<span id="filterselement"></span><h3>Filters element<a class="headerlink" href="#filters-element" title="Permalink to this headline">¶</a></h3>
+<p><a class="reference internal" href="#filterelement"><em>Filter elements</em></a> are used inside <a class="reference internal" href="#sequenceelement"><em>sequence elements</em></a> to execute arbitrary code, or make discontinuous changes in the vectors.  Sometimes it is desirable to perform a filter element at the beginning or end of each step in an integration.  This can be done by placing <tt class="docutils literal"><span class="pre"><filter></span></tt> elements in a <tt cl [...]
+is then executed in the order found in the <tt class="docutils literal"><span class="pre"><filters></span></tt> element.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><integrate</span> <span class="na">algorithm=</span><span class="s">"ARK45"</span> <span class="na">interval=</span><span class="s">"100000.0"</span> <span class="na">steps=</span><span class="s">"10000000"</span> <span class="na">tolerance=</span><span class="s">"1e-8"</span><span class="nt">></span>
+  <span class="nt"><samples></span>5000 100<span class="nt"></samples></span>
+  <span class="nt"><filters</span> <span class="na">where=</span><span class="s">"step end"</span><span class="nt">></span>
+    <span class="nt"><filter></span>
+        <span class="nt"><dependencies></span>vector1 vector2<span class="nt"></dependencies></span>
+        <span class="cp"><![CDATA[</span>
+            <span class="n">x</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
+            <span class="n">y</span> <span class="o">*=</span> <span class="n">ynorm</span><span class="p">;</span>
+            <span class="cp">]]></span>
+    <span class="nt"></filter></span>
+  <span class="nt"></filters></span>
+
+  <span class="nt"><operators></span>
+    <span class="nt"><integration_vectors></span>vector1<span class="nt"></integration_vectors></span>
+    <span class="cp"><![CDATA[</span>
+    <span class="n">dx_dt</span> <span class="o">=</span> <span class="n">alpha</span><span class="p">;</span>
+    <span class="n">dy_dt</span> <span class="o">=</span> <span class="n">beta</span><span class="o">*</span><span class="n">y</span><span class="p">;</span>
+    <span class="cp">]]></span>
+  <span class="nt"></operators></span>
+<span class="nt"></integrate></span>
+</pre></div>
+</div>
+</div>
+</div>
+<div class="section" id="breakpoint-element">
+<span id="breakpointelement"></span><h2>Breakpoint element<a class="headerlink" href="#breakpoint-element" title="Permalink to this headline">¶</a></h2>
+<p>The <tt class="docutils literal"><span class="pre"><breakpoint></span></tt> element is used to output the full state of one or more vectors.  Unlike sampled output, it executes immediately rather than at the end of a program, and can therefore be used to examine the current state of an ongoing simulation.  The vectors to be output are defined via a <a class="reference internal" href="#dependencies"><em><dependencies></em></a> element, and the basis is chosen by the <tt cla [...]
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><breakpoint</span> <span class="na">filename=</span><span class="s">"groundstate_break.xsil"</span> <span class="na">format=</span><span class="s">"hdf5"</span><span class="nt">></span>
+  <span class="nt"><dependencies</span> <span class="na">basis=</span><span class="s">"ky"</span><span class="nt">></span>wavefunction<span class="nt"></dependencies></span>
+<span class="nt"></breakpoint></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="output-element">
+<span id="outputelement"></span><h2>Output element<a class="headerlink" href="#output-element" title="Permalink to this headline">¶</a></h2>
+<p>The <tt class="docutils literal"><span class="pre"><output></span></tt> element describes the output of the program.  It is often inefficient to output the complete state of all vectors at all times during a large simulation, so the purpose of this function is to define subsets of the information required for output.  Each different format of information is described in a different <tt class="docutils literal"><span class="pre"><sampling_group></span></tt> element inside t [...]
+<p>The <tt class="docutils literal"><span class="pre"><samples></span></tt> inside <tt class="docutils literal"><span class="pre"><integrate></span></tt> elements defines a string of integers, with exactly one for each <tt class="docutils literal"><span class="pre"><sampling_group></span></tt> element.  During that integration, the variables described in each <tt class="docutils literal"><span class="pre"><sampling_group></span></tt> element will be sampled and st [...]
+<div class="section" id="sampling-group-element">
+<span id="samplinggroupelement"></span><h3>Sampling Group Element<a class="headerlink" href="#sampling-group-element" title="Permalink to this headline">¶</a></h3>
+<p>A <tt class="docutils literal"><span class="pre"><sampling_group></span></tt> element defines a set of variables that we wish to output, typically they are functions of some subset of vectors.  The names of the desired variables are listed in a <tt class="docutils literal"><span class="pre"><moments></span></tt> element, just like the <tt class="docutils literal"><span class="pre"><components></span></tt> element of a vector.  They are defined with a ‘<a class= [...]
+<p>The basis of the output is specified by the <tt class="docutils literal"><span class="pre">basis</span></tt> attribute.  This overrides any basis specification in the <tt class="docutils literal"><span class="pre"><dependencies></span></tt> element.  Because we often wish to calculate these vectors on a finer grid than we wish to output, it is possible to specify that the output on a subset of the points defined for any transverse dimension.  This is done by adding a number in p [...]
+<p>The <tt class="docutils literal"><span class="pre">initial_sample</span></tt> attribute, which must be “yes” or “no”, determines whether the moment group will be sampled before any integration occurs.</p>
+<p>Example syntax:</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="nt"><output</span> <span class="na">format=</span><span class="s">"hdf5"</span> <span class="na">filename=</span><span class="s">"SimOutput.xsil"</span><span class="nt">></span>
+  <span class="nt"><sampling_group</span> <span class="na">basis=</span><span class="s">"x y"</span> <span class="na">initial_sample=</span><span class="s">"yes"</span><span class="nt">></span>
+    <span class="nt"><computed_vector</span> <span class="na">name=</span><span class="s">"filter3"</span> <span class="na">dimensions=</span><span class="s">""</span> <span class="na">type=</span><span class="s">"complex"</span><span class="nt">></span>
+      <span class="nt"><components></span>sparemomentagain<span class="nt"></components></span>
+      <span class="nt"><evaluation></span>
+        <span class="nt"><dependencies</span> <span class="na">basis=</span><span class="s">"kx ky"</span><span class="nt">></span>integrated_u main<span class="nt"></dependencies></span>
+        <span class="cp"><![CDATA[</span>
+          <span class="n">sparemomentagain</span> <span class="o">=</span> <span class="nf">mod2</span><span class="p">(</span><span class="n">u</span><span class="p">);</span>
+        <span class="cp">]]></span>
+      <span class="nt"></evaluation></span>
+    <span class="nt"></computed_vector></span>
+    <span class="nt"><operator</span> <span class="na">kind=</span><span class="s">"ex"</span> <span class="na">constant=</span><span class="s">"no"</span><span class="nt">></span>
+      <span class="nt"><operator_names></span>L<span class="nt"></operator_names></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">L</span> <span class="o">=</span> <span class="o">-</span><span class="n">T</span><span class="o">*</span><span class="n">kx</span><span class="o">*</span><span class="n">kx</span><span class="o">/</span><span class="n">mu</span><span class="p">;</span>
+      <span class="cp">]]></span>
+    <span class="nt"></operator></span>
+    <span class="nt"><moments></span>amp ke<span class="nt"></moments></span>
+    <span class="nt"><dependencies></span>main filter1<span class="nt"></dependencies></span>
+    <span class="cp"><![CDATA[</span>
+      <span class="n">amp</span> <span class="o">=</span> <span class="nf">mod2</span><span class="p">(</span><span class="n">u</span> <span class="o">+</span> <span class="n">moment</span><span class="p">);</span>
+      <span class="n">ke</span> <span class="o">=</span> <span class="nf">mod2</span><span class="p">(</span><span class="n">L</span><span class="p">[</span><span class="n">u</span><span class="p">]);</span>
+    <span class="cp">]]></span>
+  <span class="nt"></sampling_group></span>
+
+  <span class="nt"><sampling_group</span> <span class="na">basis=</span><span class="s">"kx(0) ky(64)"</span> <span class="na">initial_sample=</span><span class="s">"yes"</span><span class="nt">></span>
+    <span class="nt"><moments></span>Dens_P <span class="nt"></moments></span>
+    <span class="nt"><dependencies></span>fields <span class="nt"></dependencies></span>
+    <span class="cp"><![CDATA[</span>
+      <span class="n">Dens_P</span> <span class="o">=</span> <span class="nf">mod2</span><span class="p">(</span><span class="n">psi</span><span class="p">);</span>
+    <span class="cp">]]></span>
+  <span class="nt"></sampling_group></span>
+<span class="nt"></output></span>
+</pre></div>
+</div>
+</div>
+</div>
+<div class="section" id="xmds-specific-c-syntax">
+<span id="xmdscsyntax"></span><h2>XMDS-specific C syntax<a class="headerlink" href="#xmds-specific-c-syntax" title="Permalink to this headline">¶</a></h2>
+<p>Sampling complex numbers can be written more efficiently using:</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="cp"><![CDATA[</span>
+  <span class="n">_SAMPLE_COMPLEX</span><span class="p">(</span><span class="n">W</span><span class="p">);</span>
+<span class="cp">]]></span>
+</pre></div>
+</div>
+<p>which is short for</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="cp"><![CDATA[</span>
+  <span class="n">WR</span> <span class="o">=</span> <span class="n">W</span><span class="p">.</span><span class="n">Re</span><span class="p">();</span>
+  <span class="n">WI</span> <span class="o">=</span> <span class="n">W</span><span class="p">.</span><span class="n">Im</span><span class="p">();</span>
+<span class="cp">]]></span>
+</pre></div>
+</div>
+<p>Various properties of dimensions are available.  For example, for a dimension called <tt class="docutils literal"><span class="pre">x</span></tt>:</p>
+<ul class="simple">
+<li>The number of points is accessible with the variable <tt class="docutils literal"><span class="pre">_lattice_x</span></tt>,</li>
+<li>The minimum range of that dimension is <tt class="docutils literal"><span class="pre">_min_x</span></tt>,</li>
+<li>The maximum range of that dimension is <tt class="docutils literal"><span class="pre">_max_x</span></tt>,</li>
+<li>The step size of a dimension is <tt class="docutils literal"><span class="pre">dx</span></tt>, and if it is constant, also available using <tt class="docutils literal"><span class="pre">_dx</span></tt>, but note that the latter does not include the effect of any <tt class="docutils literal"><span class="pre">volumePrefix</span></tt> you may have set!</li>
+</ul>
+</div>
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="index.html">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+  <h3><a href="index.html">Table Of Contents</a></h3>
+  <ul>
+<li><a class="reference internal" href="#">XMDS2 script elements</a><ul>
+<li><a class="reference internal" href="#simulation-element">Simulation element</a></li>
+<li><a class="reference internal" href="#name-element">Name element</a></li>
+<li><a class="reference internal" href="#author-element">Author element</a></li>
+<li><a class="reference internal" href="#description-element">Description element</a></li>
+<li><a class="reference internal" href="#features-elements">Features Elements</a><ul>
+<li><a class="reference internal" href="#arguments-element">Arguments Element</a><ul>
+<li><a class="reference internal" href="#argument-element">Argument element</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#auto-vectorise-element">Auto_vectorise element</a></li>
+<li><a class="reference internal" href="#benchmark">Benchmark</a></li>
+<li><a class="reference internal" href="#bing">Bing</a></li>
+<li><a class="reference internal" href="#c-flags">C Flags</a></li>
+<li><a class="reference internal" href="#chunked-output">Chunked Output</a></li>
+<li><a class="reference internal" href="#diagnostics">Diagnostics</a></li>
+<li><a class="reference internal" href="#error-check">Error Check</a></li>
+<li><a class="reference internal" href="#halt-non-finite">Halt_Non_Finite</a></li>
+<li><a class="reference internal" href="#fftw-element">fftw element</a></li>
+<li><a class="reference internal" href="#globals">Globals</a></li>
+<li><a class="reference internal" href="#openmp">OpenMP</a></li>
+<li><a class="reference internal" href="#precision">Precision</a></li>
+<li><a class="reference internal" href="#validation">Validation</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#driver-element">Driver Element</a></li>
+<li><a class="reference internal" href="#geometry-element">Geometry Element</a><ul>
+<li><a class="reference internal" href="#the-dft-transform">The “dft” transform</a></li>
+<li><a class="reference internal" href="#the-dct-transform">The “dct” transform</a></li>
+<li><a class="reference internal" href="#the-dst-transform">The “dst” transform</a></li>
+<li><a class="reference internal" href="#the-bessel-transform">The “bessel” transform</a></li>
+<li><a class="reference internal" href="#the-spherical-bessel-transform">The “spherical-bessel” transform</a></li>
+<li><a class="reference internal" href="#the-hermite-gauss-transform">The “hermite-gauss” transform</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#vector-element">Vector Element</a><ul>
+<li><a class="reference internal" href="#the-dependencies-element">The dependencies element</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#computed-vector-element">Computed Vector Element</a></li>
+<li><a class="reference internal" href="#noise-vector-element">Noise Vector Element</a><ul>
+<li><a class="reference internal" href="#uniform-noise">Uniform noise</a></li>
+<li><a class="reference internal" href="#gaussian-noise">Gaussian noise</a></li>
+<li><a class="reference internal" href="#wiener-noise">Wiener noise</a></li>
+<li><a class="reference internal" href="#poissonian-noise">Poissonian noise</a></li>
+<li><a class="reference internal" href="#jump-noise">Jump noise</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#sequence-element">Sequence Element</a></li>
+<li><a class="reference internal" href="#filter-element">Filter element</a></li>
+<li><a class="reference internal" href="#integrate-element">Integrate element</a><ul>
+<li><a class="reference internal" href="#operators-and-operator-elements">Operators and operator elements</a></li>
+<li><a class="reference internal" href="#algorithms">Algorithms</a><ul>
+<li><a class="reference internal" href="#si-and-sic-algorithms">SI and SIC algorithms</a></li>
+<li><a class="reference internal" href="#runge-kutta-algorithms">Runge-Kutta algorithms</a></li>
+<li><a class="reference internal" href="#adaptive-runge-kutta-algorithms">Adaptive Runge-Kutta algorithms</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#filters-element">Filters element</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#breakpoint-element">Breakpoint element</a></li>
+<li><a class="reference internal" href="#output-element">Output element</a><ul>
+<li><a class="reference internal" href="#sampling-group-element">Sampling Group Element</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#xmds-specific-c-syntax">XMDS-specific C syntax</a></li>
+</ul>
+</li>
+</ul>
+
+<div id="searchbox" style="display: none">
+  <h3>Quick search</h3>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" />
+      <input type="submit" value="Go" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    <p class="searchtip" style="font-size: 90%">
+    Enter search terms or a module, class or function name.
+    </p>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/documentation/reference_index.html b/documentation/reference_index.html
new file mode 100644
index 0000000..6debac2
--- /dev/null
+++ b/documentation/reference_index.html
@@ -0,0 +1,118 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>Reference section — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="index.html" /> 
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+  <div class="section" id="reference-section">
+<h1>Reference section<a class="headerlink" href="#reference-section" title="Permalink to this headline">¶</a></h1>
+<p>Contents:</p>
+<div class="toctree-wrapper compound">
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="reference_installation_and_configuration.html">Configuration, installation and runtime options</a></li>
+<li class="toctree-l1"><a class="reference internal" href="reference_usefulXMLSyntax.html">Useful XML Syntax</a></li>
+<li class="toctree-l1"><a class="reference internal" href="reference_schema.html">XMDS2 XML Schema</a></li>
+<li class="toctree-l1"><a class="reference internal" href="reference_elements.html">XMDS2 script elements</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="reference_elements.html#simulation-element">Simulation element</a></li>
+<li class="toctree-l2"><a class="reference internal" href="reference_elements.html#name-element">Name element</a></li>
+<li class="toctree-l2"><a class="reference internal" href="reference_elements.html#author-element">Author element</a></li>
+<li class="toctree-l2"><a class="reference internal" href="reference_elements.html#description-element">Description element</a></li>
+<li class="toctree-l2"><a class="reference internal" href="reference_elements.html#features-elements">Features Elements</a></li>
+<li class="toctree-l2"><a class="reference internal" href="reference_elements.html#driver-element">Driver Element</a></li>
+<li class="toctree-l2"><a class="reference internal" href="reference_elements.html#geometry-element">Geometry Element</a></li>
+<li class="toctree-l2"><a class="reference internal" href="reference_elements.html#vector-element">Vector Element</a></li>
+<li class="toctree-l2"><a class="reference internal" href="reference_elements.html#computed-vector-element">Computed Vector Element</a></li>
+<li class="toctree-l2"><a class="reference internal" href="reference_elements.html#noise-vector-element">Noise Vector Element</a></li>
+<li class="toctree-l2"><a class="reference internal" href="reference_elements.html#sequence-element">Sequence Element</a></li>
+<li class="toctree-l2"><a class="reference internal" href="reference_elements.html#filter-element">Filter element</a></li>
+<li class="toctree-l2"><a class="reference internal" href="reference_elements.html#integrate-element">Integrate element</a></li>
+<li class="toctree-l2"><a class="reference internal" href="reference_elements.html#breakpoint-element">Breakpoint element</a></li>
+<li class="toctree-l2"><a class="reference internal" href="reference_elements.html#output-element">Output element</a></li>
+<li class="toctree-l2"><a class="reference internal" href="reference_elements.html#xmds-specific-c-syntax">XMDS-specific C syntax</a></li>
+</ul>
+</li>
+</ul>
+</div>
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="index.html">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+<div id="searchbox" style="display: none">
+  <h3>Quick search</h3>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" />
+      <input type="submit" value="Go" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    <p class="searchtip" style="font-size: 90%">
+    Enter search terms or a module, class or function name.
+    </p>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/documentation/reference_installation_and_configuration.html b/documentation/reference_installation_and_configuration.html
new file mode 100644
index 0000000..f8881ea
--- /dev/null
+++ b/documentation/reference_installation_and_configuration.html
@@ -0,0 +1,118 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>Configuration, installation and runtime options — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="index.html" /> 
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+  <div class="section" id="configuration-installation-and-runtime-options">
+<span id="referenceconfigurationinstallationruntime"></span><h1>Configuration, installation and runtime options<a class="headerlink" href="#configuration-installation-and-runtime-options" title="Permalink to this headline">¶</a></h1>
+<dl class="docutils">
+<dt>Running the ‘xmds2’ program with the option ‘–help’, gives several options that can change its behaviour at runtime.  These include:</dt>
+<dd><ul class="first last simple">
+<li>‘-o’ or ‘–output’, which overrides the name of the output file to be generated</li>
+<li>‘-n’ or ‘–no-compile’, which generates the C code for the simulation, but does not try to compile it</li>
+<li>‘-v’ or ‘–verbose’, which gives verbose output about compilation flags.</li>
+<li>‘-g’ or ‘–debug’, which compiles the simulation in debug mode (compilation errors refer to lines in the source, not the .xmds file). This option implies ‘-v’. This option is mostly useful when debugging XMDS code generation.</li>
+<li>‘–waf-verbose’, which makes <tt class="docutils literal"><span class="pre">waf</span></tt> be very verbose when configuring XMDS or compiling simulations.  This option is intended for developer use only to aid in diagnosing problems with <tt class="docutils literal"><span class="pre">waf</span></tt>.</li>
+</ul>
+</dd>
+</dl>
+<p>It also has commands to configure XMDS2 and recheck the installation.  If your program requires extra paths to compile, you can configure XMDS2 to include those paths by default.  Simply use the command</p>
+<div class="highlight-bash"><div class="highlight"><pre><span class="nv">$ </span>xmds2 --configure --include-path /path/to/include --lib-path /path/to/lib
+</pre></div>
+</div>
+<p>Alternatively, you can set the <tt class="docutils literal"><span class="pre">CXXFLAGS</span></tt> or <tt class="docutils literal"><span class="pre">LINKFLAGS</span></tt> environment variables before calling <tt class="docutils literal"><span class="pre">xmds2</span> <span class="pre">--reconfigure</span></tt>.  For example, to pass the compiler flag <tt class="docutils literal"><span class="pre">-pedantic</span></tt> and the link flag <tt class="docutils literal"><span class="pre">-l [...]
+<div class="highlight-bash"><div class="highlight"><pre><span class="nv">$ </span><span class="nb">export </span><span class="nv">CXXFLAGS</span><span class="o">=</span><span class="s2">"-pedantic"</span>
+<span class="nv">$ </span><span class="nb">export </span><span class="nv">LINKFLAGS</span><span class="o">=</span><span class="s2">"-lm"</span>
+<span class="nv">$ </span>xmds2 --reconfigure<span class="sb">``</span>
+</pre></div>
+</div>
+<p>This method can also be used to change the default compilers for standard and parallel processing, using the CXX and MPICXX flags respectively.</p>
+<p>Running XMDS2 with the ‘–configure’ option also searches for packages that have been installed since you last installed or configured XMDS2.  If you wish to run ‘xmds2 –configure’ with the same extra options as last time, simply use the command:</p>
+<div class="highlight-bash"><div class="highlight"><pre><span class="nv">$ </span>xmds2 --reconfigure
+</pre></div>
+</div>
+<p>A detailed log of the checks is saved in the file ‘~/.xmds/waf_configure/config.log’.  This can be used to identify issues with packages that XMDS2 is not recognised, but you think that you have successfully installed on your system.</p>
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="index.html">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+<div id="searchbox" style="display: none">
+  <h3>Quick search</h3>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" />
+      <input type="submit" value="Go" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    <p class="searchtip" style="font-size: 90%">
+    Enter search terms or a module, class or function name.
+    </p>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/documentation/reference_schema.html b/documentation/reference_schema.html
new file mode 100644
index 0000000..4d9020f
--- /dev/null
+++ b/documentation/reference_schema.html
@@ -0,0 +1,237 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>XMDS2 XML Schema — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="index.html" /> 
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+  <div class="section" id="xmds2-xml-schema">
+<span id="referenceschema"></span><h1>XMDS2 XML Schema<a class="headerlink" href="#xmds2-xml-schema" title="Permalink to this headline">¶</a></h1>
+<p>There are many, many XML tags that can make up an XMDS2 script. Most of them are optional, or have default values if not specified. It is, however, useful to know which elements are possible, and their position and relationship to other elements in the script. Shown below is the full XML tree for XMDS2, which shows all possible elements and their position in the tree. An ellipsis (...) outside an element indicates the element above can be repeated indefinitely, and an ellipsis inside  [...]
+<p>The syntax <element /> can be used for lowest-level elements that have attributes but no content, and are shorthand for <element> </element>. This shorthand notation can also be used for elements which can only contain the content “yes” or “no”; in this case the presence of <element /> is equivalent to <element> yes </element>, and the absence of such an element is equivalent to <element> no </element></p>
+<p>The possible attributes and attribute values for each element are not shown; see the individual entries in the Reference section for details.</p>
+<pre class="literal-block">
+<?xml version="1.0" encoding="UTF-8"?>
+<<a class="reference internal" href="reference_elements.html#simulationelement"><em>simulation</em></a> xmds-version="2">
+  <<a class="reference internal" href="reference_elements.html#nameelement"><em>name</em></a>> <<a class="reference internal" href="reference_elements.html#nameelement"><em>/name</em></a>>
+  <<a class="reference internal" href="reference_elements.html#authorelement"><em>author</em></a>> <<a class="reference internal" href="reference_elements.html#authorelement"><em>author</em></a>>
+  <<a class="reference internal" href="reference_elements.html#descriptionelement"><em>description</em></a>> <<a class="reference internal" href="reference_elements.html#descriptionelement"><em>/description</em></a>>
+
+  <<a class="reference internal" href="reference_elements.html#featureselement"><em>features</em></a>>
+    <<a class="reference internal" href="reference_elements.html#argumentselement"><em>arguments</em></a>>
+      <<a class="reference internal" href="reference_elements.html#argumentelement"><em>argument</em></a> />
+      <<a class="reference internal" href="reference_elements.html#argumentelement"><em>argument</em></a> />
+      ...
+    <<a class="reference internal" href="reference_elements.html#argumentselement"><em>/arguments</em></a>>
+    <<a class="reference internal" href="reference_elements.html#autovectorise"><em>auto_vectorise</em></a> />
+    <<a class="reference internal" href="reference_elements.html#benchmark"><em>benchmark</em></a> />
+    <<a class="reference internal" href="reference_elements.html#bing"><em>bing</em></a> />
+    <<a class="reference internal" href="reference_elements.html#cflags"><em>cflags</em></a>> <<a class="reference internal" href="reference_elements.html#cflags"><em>/cflags</em></a>>
+    <<a class="reference internal" href="reference_elements.html#chunkedoutput"><em>chunked_output</em></a> />
+    <<a class="reference internal" href="reference_elements.html#diagnostics"><em>diagnostics</em></a> />
+    <<a class="reference internal" href="reference_elements.html#errorcheck"><em>error_check</em></a> />
+    <<a class="reference internal" href="reference_elements.html#haltnonfinite"><em>halt_non_finite</em></a> />
+    <<a class="reference internal" href="reference_elements.html#fftw"><em>fftw</em></a> />
+    <<a class="reference internal" href="reference_elements.html#globals"><em>globals</em></a>> <<a class="reference internal" href="reference_elements.html#globals"><em>/globals</em></a>>
+    <<a class="reference internal" href="reference_elements.html#openmp"><em>openmp</em></a> />
+    <<a class="reference internal" href="reference_elements.html#precision"><em>precision</em></a>> <<a class="reference internal" href="reference_elements.html#precision"><em>/precision</em></a>>
+    <<a class="reference internal" href="reference_elements.html#validation"><em>validation</em></a> />
+  <<a class="reference internal" href="reference_elements.html#featureselement"><em>/features</em></a>>
+
+  <<a class="reference internal" href="reference_elements.html#driverelement"><em>driver</em></a> />
+
+  <<a class="reference internal" href="reference_elements.html#geometryelement"><em>geometry</em></a>>
+    <<a class="reference internal" href="reference_elements.html#propagationdimensionelement"><em>propagation_dimension</em></a>> <<a class="reference internal" href="reference_elements.html#propagationdimensionelement"><em>/propagation_dimension</em></a>>
+    <<a class="reference internal" href="reference_elements.html#transversedimensionselement"><em>transverse_dimensions</em></a>>
+      <<a class="reference internal" href="reference_elements.html#dimensionelement"><em>dimension</em></a> />
+      <<a class="reference internal" href="reference_elements.html#dimensionelement"><em>dimension</em></a> />
+      ...
+    <<a class="reference internal" href="reference_elements.html#transversedimensionselement"><em>/transverse_dimensions</em></a>>
+  <<a class="reference internal" href="reference_elements.html#geometryelement"><em>/geometry</em></a>>
+
+  <<a class="reference internal" href="reference_elements.html#vectorelement"><em>vector</em></a>>
+    <<a class="reference internal" href="reference_elements.html#componentselement"><em>components</em></a>> <<a class="reference internal" href="reference_elements.html#componentselement"><em>/components</em></a>>
+    <<a class="reference internal" href="reference_elements.html#initialisationelement"><em>initialisation</em></a>>
+      <<a class="reference internal" href="reference_elements.html#dependencies"><em>dependencies</em></a>> <<a class="reference internal" href="reference_elements.html#dependencies"><em>/dependencies</em></a>>
+      <<a class="reference internal" href="reference_elements.html#filenameelement"><em>filename</em></a>>
+      <![<a class="reference internal" href="reference_elements.html#initialisationelement"><em>CDATA</em></a> [
+      ]]>
+    <<a class="reference internal" href="reference_elements.html#initialisationelement"><em>/initialisation</em></a>>
+  <<a class="reference internal" href="reference_elements.html#vectorelement"><em>/vector</em></a>>
+
+  <<a class="reference internal" href="reference_elements.html#vectorelement"><em>vector</em></a>> ... <<a class="reference internal" href="reference_elements.html#vectorelement"><em>/vector</em></a>>
+  <<a class="reference internal" href="reference_elements.html#vectorelement"><em>vector</em></a>> ... <<a class="reference internal" href="reference_elements.html#vectorelement"><em>/vector</em></a>>
+  ...
+
+  <<a class="reference internal" href="reference_elements.html#computedvectorelement"><em>computed_vector</em></a>>
+    <<a class="reference internal" href="reference_elements.html#componentselement"><em>components</em></a>> <<a class="reference internal" href="reference_elements.html#componentselement"><em>/components</em></a>>
+    <<a class="reference internal" href="reference_elements.html#evaluationelement"><em>evaluation</em></a>>
+      <<a class="reference internal" href="reference_elements.html#dependencies"><em>dependencies</em></a>> <<a class="reference internal" href="reference_elements.html#dependencies"><em>/dependencies</em></a>>
+      <![<a class="reference internal" href="reference_elements.html#initialisationelement"><em>CDATA</em></a> [
+      ]]>
+    <<a class="reference internal" href="reference_elements.html#evaluationelement"><em>/evaluation</em></a>>
+  <<a class="reference internal" href="reference_elements.html#computedvectorelement"><em>/computed_vector</em></a>>
+
+  <<a class="reference internal" href="reference_elements.html#computedvectorelement"><em>computed_vector</em></a>> ... <<a class="reference internal" href="reference_elements.html#computedvectorelement"><em>/computed_vector</em></a>>
+  <<a class="reference internal" href="reference_elements.html#computedvectorelement"><em>computed_vector</em></a>> ... <<a class="reference internal" href="reference_elements.html#computedvectorelement"><em>/computed_vector</em></a>>
+  ...
+
+  <<a class="reference internal" href="reference_elements.html#noisevectorelement"><em>noise_vector</em></a>>
+    <<a class="reference internal" href="reference_elements.html#componentselement"><em>components</em></a>> <<a class="reference internal" href="reference_elements.html#componentselement"><em>/components</em></a>>
+  <<a class="reference internal" href="reference_elements.html#noisevectorelement"><em>/noise_vector</em></a>>
+
+  <<a class="reference internal" href="reference_elements.html#noisevectorelement"><em>noise_vector</em></a>> ... <<a class="reference internal" href="reference_elements.html#noisevectorelement"><em>/noise_vector</em></a>>
+  <<a class="reference internal" href="reference_elements.html#noisevectorelement"><em>noise_vector</em></a>> ... <<a class="reference internal" href="reference_elements.html#noisevectorelement"><em>/noise_vector</em></a>>
+  ...
+
+  <<a class="reference internal" href="reference_elements.html#sequenceelement"><em>sequence</em></a>>
+
+    <<a class="reference internal" href="reference_elements.html#filterelement"><em>filter</em></a>>
+      <<a class="reference internal" href="reference_elements.html#dependencies"><em>dependencies</em></a>> <<a class="reference internal" href="reference_elements.html#dependencies"><em>/dependencies</em></a>>
+      <![<a class="reference internal" href="reference_elements.html#xmdscsyntax"><em>CDATA</em></a> [
+      ]]>
+    <<a class="reference internal" href="reference_elements.html#filterelement"><em>/filter</em></a>>
+
+    <<a class="reference internal" href="reference_elements.html#integrateelement"><em>integrate</em></a>>
+      <<a class="reference internal" href="reference_elements.html#sampleselement"><em>samples</em></a>> <<a class="reference internal" href="reference_elements.html#sampleselement"><em>/samples</em></a>>
+
+      <<a class="reference internal" href="reference_elements.html#computedvectorelement"><em>computed_vector</em></a>> ... <<a class="reference internal" href="reference_elements.html#computedvectorelement"><em>/computed_vector</em></a>>
+
+      <<a class="reference internal" href="reference_elements.html#filterselement"><em>filters</em></a>>
+        <<a class="reference internal" href="reference_elements.html#filterelement"><em>filter</em></a>> ... <<a class="reference internal" href="reference_elements.html#filterelement"><em>/filter</em></a>>
+        <<a class="reference internal" href="reference_elements.html#filterelement"><em>filter</em></a>> ... <<a class="reference internal" href="reference_elements.html#filterelement"><em>/filter</em></a>>
+        ...
+      <<a class="reference internal" href="reference_elements.html#filterselement"><em>/filters</em></a>>
+
+      <<a class="reference internal" href="reference_elements.html#operatorselement"><em>operators</em></a>>
+
+        <<a class="reference internal" href="reference_elements.html#operatorelement"><em>operator</em></a>>
+          <<a class="reference internal" href="reference_elements.html#boundaryconditionelement"><em>boundary_condition</em></a>>
+            <<a class="reference internal" href="reference_elements.html#dependencies"><em>dependencies</em></a>> <<a class="reference internal" href="reference_elements.html#dependencies"><em>/dependencies</em></a>>
+            <![<a class="reference internal" href="reference_elements.html#xmdscsyntax"><em>CDATA</em></a> [
+            ]]>
+          <<a class="reference internal" href="reference_elements.html#boundaryconditionelement"><em>/boundary_condition</em></a>>
+          <<a class="reference internal" href="reference_elements.html#operatornameselement"><em>operator_names</em></a>> <<a class="reference internal" href="reference_elements.html#operatornameselement"><em>/operator_names</em></a>>
+          <<a class="reference internal" href="reference_elements.html#dependencies"><em>dependencies</em></a>> <<a class="reference internal" href="reference_elements.html#dependencies"><em>/dependencies</em></a>>
+          <![<a class="reference internal" href="reference_elements.html#xmdscsyntax"><em>CDATA</em></a> [
+          ]]>
+        <<a class="reference internal" href="reference_elements.html#operatorelement"><em>/operator</em></a>>
+
+        <<a class="reference internal" href="reference_elements.html#operatorelement"><em>operator</em></a>> ... <<a class="reference internal" href="reference_elements.html#operatorelement"><em>/operator</em></a>>
+        <<a class="reference internal" href="reference_elements.html#operatorelement"><em>operator</em></a>> ... <<a class="reference internal" href="reference_elements.html#operatorelement"><em>/operator</em></a>>
+        ...
+
+        <<a class="reference internal" href="reference_elements.html#integrationvectorselement"><em>integration_vectors</em></a>> <<a class="reference internal" href="reference_elements.html#integrationvectorselement"><em>/integration_vectors</em></a>>
+        <<a class="reference internal" href="reference_elements.html#dependencies"><em>dependencies</em></a>> <<a class="reference internal" href="reference_elements.html#dependencies"><em>/dependencies</em></a>>
+        <![<a class="reference internal" href="reference_elements.html#xmdscsyntax"><em>CDATA</em></a> [
+        ]]>
+
+      <<a class="reference internal" href="reference_elements.html#operatorselement"><em>/operators</em></a>>
+
+    <<a class="reference internal" href="reference_elements.html#integrateelement"><em>/integrate</em></a>>
+
+    <<a class="reference internal" href="reference_elements.html#breakpointelement"><em>breakpoint</em></a>>
+      <<a class="reference internal" href="reference_elements.html#dependencies"><em>dependencies</em></a>> <<a class="reference internal" href="reference_elements.html#dependencies"><em>/dependencies</em></a>>
+    <<a class="reference internal" href="reference_elements.html#breakpointelement"><em>/breakpoint</em></a>>
+
+  <<a class="reference internal" href="reference_elements.html#sequenceelement"><em>/sequence</em></a>>
+
+  <<a class="reference internal" href="reference_elements.html#outputelement"><em>output</em></a>>
+    <<a class="reference internal" href="reference_elements.html#samplinggroupelement"><em>sampling_group</em></a>>
+      <<a class="reference internal" href="reference_elements.html#dependencies"><em>dependencies</em></a>> <<a class="reference internal" href="reference_elements.html#dependencies"><em>/dependencies</em></a>>
+      <<a class="reference internal" href="reference_elements.html#samplinggroupelement"><em>moments</em></a>> <<a class="reference internal" href="reference_elements.html#samplinggroupelement"><em>/moments</em></a>>
+      <<a class="reference internal" href="reference_elements.html#operatorelement"><em>operator</em></a>> ... <<a class="reference internal" href="reference_elements.html#operatorelement"><em>/operator</em></a>>
+      <![<a class="reference internal" href="reference_elements.html#xmdscsyntax"><em>CDATA</em></a> [
+      ]]>
+    <<a class="reference internal" href="reference_elements.html#samplinggroupelement"><em>/sampling_group</em></a>>
+
+    <<a class="reference internal" href="reference_elements.html#samplinggroupelement"><em>sampling_group</em></a>> ... <<a class="reference internal" href="reference_elements.html#samplinggroupelement"><em>/sampling_group</em></a>>
+    <<a class="reference internal" href="reference_elements.html#samplinggroupelement"><em>sampling_group</em></a>> ... <<a class="reference internal" href="reference_elements.html#samplinggroupelement"><em>/sampling_group</em></a>>
+    ...
+
+  <<a class="reference internal" href="reference_elements.html#outputelement"><em>/output</em></a>>
+
+<<a class="reference internal" href="reference_elements.html#simulationelement"><em>/simulation</em></a>>
+</pre>
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="index.html">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+<div id="searchbox" style="display: none">
+  <h3>Quick search</h3>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" />
+      <input type="submit" value="Go" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    <p class="searchtip" style="font-size: 90%">
+    Enter search terms or a module, class or function name.
+    </p>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/documentation/reference_usefulXMLSyntax.html b/documentation/reference_usefulXMLSyntax.html
new file mode 100644
index 0000000..0bfffd8
--- /dev/null
+++ b/documentation/reference_usefulXMLSyntax.html
@@ -0,0 +1,109 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>Useful XML Syntax — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="index.html" /> 
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+  <div class="section" id="useful-xml-syntax">
+<span id="referenceusefulxmlsyntax"></span><h1>Useful XML Syntax<a class="headerlink" href="#useful-xml-syntax" title="Permalink to this headline">¶</a></h1>
+<p>Standard XML placeholders can be used to simplify some scripts.  For example, the following (abbreviated) code ensures that the limits of a domain are symmetric.</p>
+<div class="highlight-xmds2"><div class="highlight"><pre><span class="cp"><?xml version="1.0" encoding="UTF-8"?></span>
+<span class="cp"><!DOCTYPE simulation [</span>
+<span class="cp"><!ENTITY Npts    "64"></span>
+<span class="cp"><!ENTITY L      "3.0e-5"></span>
+]>
+  <span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+
+    . . .
+
+    <span class="nt"><geometry></span>
+        <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+        <span class="nt"><transverse_dimensions></span>
+          <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"x"</span> <span class="na">lattice=</span><span class="s">"&Npts;"</span>  <span class="na">domain=</span><span class="s">"(-&L;, &L;)"</span> <span class="nt">/></span>
+        <span class="nt"></transverse_dimensions></span>
+     <span class="nt"></geometry></span>
+</pre></div>
+</div>
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="index.html">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+<div id="searchbox" style="display: none">
+  <h3>Quick search</h3>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" />
+      <input type="submit" value="Go" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    <p class="searchtip" style="font-size: 90%">
+    Enter search terms or a module, class or function name.
+    </p>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/documentation/search.html b/documentation/search.html
new file mode 100644
index 0000000..641c9fe
--- /dev/null
+++ b/documentation/search.html
@@ -0,0 +1,105 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>Search — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <script type="text/javascript" src="_static/searchtools.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="index.html" />
+  <script type="text/javascript">
+    jQuery(function() { Search.loadIndex("searchindex.js"); });
+  </script>
+  
+  <script type="text/javascript" id="searchindexloader"></script>
+   
+
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+  <h1 id="search-documentation">Search</h1>
+  <div id="fallback" class="admonition warning">
+  <script type="text/javascript">$('#fallback').hide();</script>
+  <p>
+    Please activate JavaScript to enable the search
+    functionality.
+  </p>
+  </div>
+  <p>
+    From here you can search these documents. Enter your search
+    words into the box below and click "search". Note that the search
+    function will automatically search for all of the words. Pages
+    containing fewer words won't appear in the result list.
+  </p>
+  <form action="" method="get">
+    <input type="text" name="q" value="" />
+    <input type="submit" value="search" />
+    <span id="search-progress" style="padding-left: 10px"></span>
+  </form>
+  
+  <div id="search-results">
+  
+  </div>
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="index.html">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/documentation/searchindex.js b/documentation/searchindex.js
new file mode 100644
index 0000000..23672fc
--- /dev/null
+++ b/documentation/searchindex.js
@@ -0,0 +1 @@
+Search.setIndex({envversion:42,terms:{orthogon:4,four:7,secondli:8,prefix:[3,4],forget:5,xmds2:13,xmds1:[1,15],accur:[8,17,4],"const":[7,4],wigner_arguments_mpi:7,deviat:4,matlab:[1,3,15],under:[6,7,12],slowest:4,worth:8,two_dim:4,everi:[5,14],vastli:17,hermitegauss_transform:4,vector:[9,13,14],terabyt:4,matric:13,readthedoc:14,initialis:[1,5,7,13,14,15,16,17,4],direct:[1,15,4,5],consequ:4,second:[6,5,4,17,7],grid_specifi:13,libxslt:3,even:[5,4,13,7],neg:[13,4],asid:[7,4],"new":[9,8,13,1 [...]
\ No newline at end of file
diff --git a/documentation/tutorial.html b/documentation/tutorial.html
new file mode 100644
index 0000000..0039408
--- /dev/null
+++ b/documentation/tutorial.html
@@ -0,0 +1,313 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>Quickstart Tutorial — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="index.html" /> 
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+  <div class="section" id="quickstart-tutorial">
+<span id="quickstarttutorial"></span><h1>Quickstart Tutorial<a class="headerlink" href="#quickstart-tutorial" title="Permalink to this headline">¶</a></h1>
+<p>In this tutorial, we will create an XMDS2 script to solve the Lorenz Attractor, an example of a dynamical system that exhibits chaos. The equations describing this problem are</p>
+<div class="math">
+\[\begin{split}\frac{dx}{dt} &= \sigma (y - x)\\
+\frac{dy}{dt} &= x (\rho - z) - y\\
+\frac{dz}{dt} &= xy - \beta z\end{split}\]</div>
+<p>where we will solve with the parameters <span class="math">\(\sigma=10\)</span>, <span class="math">\(\rho=28\)</span>, <span class="math">\(\beta = \frac{8}{3}\)</span> and the initial condition <span class="math">\(x(0) = y(0) = z(0) = 1\)</span>.</p>
+<p>Below is a script that solves this problem (it’s also saved as examples/lorenz.xmds in your XMDS2 directory). Don’t worry if it doesn’t make sense yet, soon we’ll break it down into easily digestible parts.</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="cp"><?xml version="1.0" encoding="UTF-8"?></span>
+<span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+  <span class="nt"><name></span>lorenz<span class="nt"></name></span>
+
+  <span class="c"><!-- While not strictly necessary, the following two tags are handy. --></span>
+  <span class="nt"><author></span>Graham Dennis<span class="nt"></author></span>
+  <span class="nt"><description></span>
+    The Lorenz Attractor, an example of chaos.
+  <span class="nt"></description></span>
+
+  <span class="c"><!--</span>
+<span class="c">  This element defines some constants.  It can be used for other</span>
+<span class="c">  features as well, but we will go into that in more detail later.</span>
+<span class="c">  --></span>
+  <span class="nt"><features></span>
+    <span class="nt"><globals></span>
+        <span class="cp"><![CDATA[</span>
+        <span class="nf">real</span> <span class="n">sigma</span> <span class="o">=</span> <span class="mf">10.0</span><span class="p">;</span>
+        <span class="nf">real</span> <span class="n">b</span> <span class="o">=</span> <span class="mf">8.0</span><span class="o">/</span><span class="mf">3.0</span><span class="p">;</span>
+        <span class="nf">real</span> <span class="n">r</span> <span class="o">=</span> <span class="mf">28.0</span><span class="p">;</span>
+        <span class="cp">]]></span>
+     <span class="nt"></globals></span>
+   <span class="nt"></features></span>
+
+  <span class="c"><!--</span>
+<span class="c">  This part defines all of the dimensions used in the problem,</span>
+<span class="c">  in this case, only the dimension of 'time' is needed.</span>
+<span class="c">  --></span>
+  <span class="nt"><geometry></span>
+    <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+  <span class="nt"></geometry></span>
+
+  <span class="c"><!-- A 'vector' describes the variables that we will be evolving. --></span>
+  <span class="nt"><vector</span> <span class="na">name=</span><span class="s">"position"</span> <span class="na">type=</span><span class="s">"real"</span><span class="nt">></span>
+    <span class="nt"><components></span>
+      x y z
+    <span class="nt"></components></span>
+    <span class="nt"><initialisation></span>
+      <span class="cp"><![CDATA[</span>
+      <span class="n">x</span> <span class="o">=</span> <span class="n">y</span> <span class="o">=</span> <span class="n">z</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">;</span>
+      <span class="cp">]]></span>
+    <span class="nt"></initialisation></span>
+  <span class="nt"></vector></span>
+
+  <span class="nt"><sequence></span>
+    <span class="c"><!--</span>
+<span class="c">    Here we define what differential equations need to be solved</span>
+<span class="c">    and what algorithm we want to use.</span>
+<span class="c">    --></span>
+    <span class="nt"><integrate</span> <span class="na">algorithm=</span><span class="s">"ARK89"</span> <span class="na">interval=</span><span class="s">"20.0"</span> <span class="na">tolerance=</span><span class="s">"1e-7"</span><span class="nt">></span>
+      <span class="nt"><samples></span>5000<span class="nt"></samples></span>
+      <span class="nt"><operators></span>
+        <span class="nt"><integration_vectors></span>position<span class="nt"></integration_vectors></span>
+        <span class="cp"><![CDATA[</span>
+        <span class="n">dx_dt</span> <span class="o">=</span> <span class="n">sigma</span><span class="o">*</span><span class="p">(</span><span class="n">y</span><span class="o">-</span><span class="n">x</span><span class="p">);</span>
+        <span class="n">dy_dt</span> <span class="o">=</span> <span class="n">r</span><span class="o">*</span><span class="n">x</span> <span class="o">-</span> <span class="n">y</span> <span class="o">-</span> <span class="n">x</span><span class="o">*</span><span class="n">z</span><span class="p">;</span>
+        <span class="n">dz_dt</span> <span class="o">=</span> <span class="n">x</span><span class="o">*</span><span class="n">y</span> <span class="o">-</span> <span class="n">b</span><span class="o">*</span><span class="n">z</span><span class="p">;</span>
+        <span class="cp">]]></span>
+      <span class="nt"></operators></span>
+    <span class="nt"></integrate></span>
+  <span class="nt"></sequence></span>
+
+  <span class="c"><!-- This part defines what data will be saved in the output file --></span>
+  <span class="nt"><output</span> <span class="na">format=</span><span class="s">"hdf5"</span> <span class="na">filename=</span><span class="s">"lorenz.xsil"</span><span class="nt">></span>
+    <span class="nt"><sampling_group</span> <span class="na">initial_sample=</span><span class="s">"yes"</span><span class="nt">></span>
+      <span class="nt"><moments></span>xR yR zR<span class="nt"></moments></span>
+      <span class="nt"><dependencies></span>position<span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">xR</span> <span class="o">=</span> <span class="n">x</span><span class="p">;</span>
+        <span class="n">yR</span> <span class="o">=</span> <span class="n">y</span><span class="p">;</span>
+        <span class="n">zR</span> <span class="o">=</span> <span class="n">z</span><span class="p">;</span>
+      <span class="cp">]]></span>
+    <span class="nt"></sampling_group></span>
+  <span class="nt"></output></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+<p>You can compile and run this script with <strong>XMDS2</strong>. To compile the script, just pass the name of the script as an argument to <strong>XMDS2</strong>.</p>
+<blockquote>
+<div><div class="highlight-none"><div class="highlight"><pre>$ xmds2 lorenz.xmds
+xmds2 version 2.1 "Happy Mollusc" (r2680)
+Copyright 2000-2012 Graham Dennis, Joseph Hope, Mattias Johnsson
+                    and the xmds team
+Generating source code...
+... done
+Compiling simulation...
+... done. Type './lorenz' to run.
+</pre></div>
+</div>
+</div></blockquote>
+<p>Now we can execute the generated program ‘lorenz’.</p>
+<blockquote>
+<div><div class="highlight-none"><div class="highlight"><pre>$ ./lorenz
+Sampled field (for moment group #1) at t = 0.000000e+00
+Sampled field (for moment group #1) at t = 4.000000e-03
+Current timestep: 4.000000e-03
+Sampled field (for moment group #1) at t = 8.000000e-03
+Current timestep: 4.000000e-03
+
+... many lines omitted ...
+
+Current timestep: 4.000000e-03
+Sampled field (for moment group #1) at t = 1.999600e+01
+Current timestep: 4.000000e-03
+Sampled field (for moment group #1) at t = 2.000000e+01
+Current timestep: 4.000000e-03
+Segment 1: minimum timestep: 9.997900e-06 maximum timestep: 4.000000e-03
+  Attempted 7386 steps, 0.00% steps failed.
+Generating output for lorenz
+</pre></div>
+</div>
+</div></blockquote>
+<p>The program generated by <strong>XMDS2</strong> has now integrated your equations and produced two files.  The first is the XML file “lorenz.xsil”, which contains the all the information used to generate the simulation (including the XMDS2 code) and the metadata description of the output.  The second file is named “lorenz.h5”, which is a <a class="reference external" href="http://www.hdfgroup.org/HDF5">HDF5</a> file containing all of the output data.   You can  [...]
+<blockquote>
+<div><div class="highlight-none"><div class="highlight"><pre>$ xsil2graphics2 -e lorenz.xsil
+xsil2graphics2 from xmds2 version 2.1 "Happy Mollusc" (r2680)
+Generating output for Mathematica 6+.
+Writing import script for 'lorenz.xsil' to 'lorenz.nb'.
+</pre></div>
+</div>
+</div></blockquote>
+<p>This has now generated the file ‘lorenz.nb’, which is a Mathematica notebook that loads the output data of the simulation.  Loading it into Mathematica allows us to plot the points {xR1, yR1, zR1}:</p>
+<blockquote>
+<div><div class="highlight-none"><div class="highlight"><pre>ll = Transpose[{xR1, yR1, zR1}];
+ListPointPlot3D[ll]
+</pre></div>
+</div>
+</div></blockquote>
+<img alt="_images/lorenz.png" class="align-center" src="_images/lorenz.png" />
+<p>...and we see the lobes of the strange attractor.  Now let us examine the code that produced this simulation.</p>
+<p>First, we have the top level description of the code.</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="cp"><?xml version="1.0" encoding="UTF-8"?></span>
+<span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+  <span class="nt"><name></span>lorenz<span class="nt"></name></span>
+
+  <span class="c"><!-- While not strictly necessary, the following two tags are handy. --></span>
+  <span class="nt"><author></span>Graham Dennis<span class="nt"></author></span>
+  <span class="nt"><description></span>
+    The Lorenz Attractor, an example of chaos.
+  <span class="nt"></description></span>
+</pre></div>
+</div>
+<p>One of the advantages of an XML format is that these tags are almost entirely self-explanatory.  XMDS2 files follow full XML syntax, so elements can be commented out using the <tt class="docutils literal"><span class="pre"><!--</span></tt> and <tt class="docutils literal"><span class="pre">--></span></tt> brackets, and we have an example of that here.</p>
+<p>The first line, <tt class="docutils literal"><span class="pre"><?xml</span> <span class="pre">...></span></tt>, just specifies the encoding and XML version. It is optional, but its presence helps some text editors perform the correct syntax highlighting.</p>
+<p>The <tt class="docutils literal"><span class="pre"><simulation></span></tt> element is mandatory, and encloses the entire simulation script.</p>
+<p>The <tt class="docutils literal"><span class="pre"><name></span></tt> element is optional, but recommended. It defines the name of the executable program that will be generated, as well as the default name of the output data files (although this can be over-ridden in the <tt class="docutils literal"><span class="pre"><output></span></tt> element if desired). If <tt class="docutils literal"><span class="pre"><name></span></tt> is not present, it will default to the fi [...]
+<p>The next element we have used can be skipped entirely if you wish to use the default set of features and you don’t want to define any global constants for your simulation.</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><features></span>
+  <span class="nt"><globals></span>
+      <span class="cp"><![CDATA[</span>
+      <span class="nf">real</span> <span class="n">sigma</span> <span class="o">=</span> <span class="mf">10.0</span><span class="p">;</span>
+      <span class="nf">real</span> <span class="n">b</span> <span class="o">=</span> <span class="mf">8.0</span><span class="o">/</span><span class="mf">3.0</span><span class="p">;</span>
+      <span class="nf">real</span> <span class="n">r</span> <span class="o">=</span> <span class="mf">28.0</span><span class="p">;</span>
+      <span class="cp">]]></span>
+   <span class="nt"></globals></span>
+ <span class="nt"></features></span>
+</pre></div>
+</div>
+<p>The <tt class="docutils literal"><span class="pre"><features></span></tt> element can be used to choose a large number of features that will be discussed later, but here we have only used it to define a <tt class="docutils literal"><span class="pre"><globals></span></tt> element.  This element contains a block of text with <tt class="docutils literal"><span class="pre"><![CDATA[</span></tt> at the start and <tt class="docutils literal"><span class="pre">]]></span></t [...]
+<p>The next element is the essential <tt class="docutils literal"><span class="pre"><geometry></span></tt> element.</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><geometry></span>
+  <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+<span class="nt"></geometry></span>
+</pre></div>
+</div>
+<p>This element is used to define all the dimensions in the problem.  We only require the time dimension, which we are labelling ‘t’, so this is a trivial example.  We will discuss transverse dimensions in more detail in the next worked example (<a class="reference internal" href="worked_examples.html#nonlinearschrodingerequation"><em>The nonlinear Schrödinger equation</em></a>), where we deal with the integration of a partial differential equation rather than ordinary differ [...]
+<p>Next, we have the <tt class="docutils literal"><span class="pre"><vector></span></tt> element.</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><vector</span> <span class="na">name=</span><span class="s">"position"</span> <span class="na">type=</span><span class="s">"real"</span><span class="nt">></span>
+  <span class="nt"><components></span>
+    x y z
+  <span class="nt"></components></span>
+  <span class="nt"><initialisation></span>
+    <span class="cp"><![CDATA[</span>
+    <span class="n">x</span> <span class="o">=</span> <span class="n">y</span> <span class="o">=</span> <span class="n">z</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">;</span>
+    <span class="cp">]]></span>
+  <span class="nt"></initialisation></span>
+<span class="nt"></vector></span>
+</pre></div>
+</div>
+<p>We can define multiple vectors, but here we only need the variables that we wish to integrate.  We named this vector “position”, as it defines the position in phase space.  These variables are real-valued (as opposed to, say, complex numbers), so we define <tt class="docutils literal"><span class="pre">type="real"</span></tt>.  The <tt class="docutils literal"><span class="pre"><components></span></tt> element defines the names of the elements of this vecto [...]
+<p>Now we come to the heart of the simulation, where we define the evolution of our vector.  This evolution is held in the <tt class="docutils literal"><span class="pre"><sequence></span></tt> element, which contains an ordered sequence of actions upon any defined vectors.  Vectors can be altered with a <tt class="docutils literal"><span class="pre"><filter></span></tt> element, or integrated in the propagation dimension with an <tt class="docutils literal"><span class="pre"> [...]
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><sequence></span>
+  <span class="nt"><integrate</span> <span class="na">algorithm=</span><span class="s">"ARK89"</span> <span class="na">interval=</span><span class="s">"20.0"</span> <span class="na">tolerance=</span><span class="s">"1e-7"</span><span class="nt">></span>
+    <span class="nt"><samples></span>5000<span class="nt"></samples></span>
+    <span class="nt"><operators></span>
+      <span class="nt"><integration_vectors></span>position<span class="nt"></integration_vectors></span>
+      <span class="cp"><![CDATA[</span>
+      <span class="n">dx_dt</span> <span class="o">=</span> <span class="n">sigma</span><span class="o">*</span><span class="p">(</span><span class="n">y</span><span class="o">-</span><span class="n">x</span><span class="p">);</span>
+      <span class="n">dy_dt</span> <span class="o">=</span> <span class="n">r</span><span class="o">*</span><span class="n">x</span> <span class="o">-</span> <span class="n">y</span> <span class="o">-</span> <span class="n">x</span><span class="o">*</span><span class="n">z</span><span class="p">;</span>
+      <span class="n">dz_dt</span> <span class="o">=</span> <span class="n">x</span><span class="o">*</span><span class="n">y</span> <span class="o">-</span> <span class="n">b</span><span class="o">*</span><span class="n">z</span><span class="p">;</span>
+      <span class="cp">]]></span>
+    <span class="nt"></operators></span>
+  <span class="nt"></integrate></span>
+<span class="nt"></sequence></span>
+</pre></div>
+</div>
+<p>Here our sequence consists of a single <tt class="docutils literal"><span class="pre"><integrate></span></tt> element.  It contains several important pieces of information.  At the heart, the <tt class="docutils literal"><span class="pre"><operators></span></tt> element contains the equations of motion as described above, written in a very human-readable fashion.  It also contains an <tt class="docutils literal"><span class="pre"><integration_vectors></span></tt> ele [...]
+<p>All integrate blocks must define which algorithm is to be used - in this case the 8th (embedded 9th) order adaptive Runge-Kutta method, called “ARK89”.  The details of different algorithms will be described later (FIXME: Link!), but for now all we need to know is that this algorithm requires a tolerance, and that smaller means more accurate, so we’ll make it <span class="math">\(10^{-7}\)</span> by setting <tt class="docutils literal"><span class="pre">tolerance=&quo [...]
+<p>The <tt class="docutils literal"><span class="pre"><samples></span></tt> element says that the values of the output groups will be sampled 5000 times during this interval.  The nature of the output is defined in the last element in the simulation: the <tt class="docutils literal"><span class="pre"><output></span></tt> element.</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><output</span> <span class="na">format=</span><span class="s">"hdf5"</span> <span class="na">filename=</span><span class="s">"lorenz.xsil"</span><span class="nt">></span>
+  <span class="nt"><sampling_group</span> <span class="na">initial_sample=</span><span class="s">"yes"</span><span class="nt">></span>
+    <span class="nt"><moments></span>xR yR zR<span class="nt"></moments></span>
+    <span class="nt"><dependencies></span>position<span class="nt"></dependencies></span>
+    <span class="cp"><![CDATA[</span>
+      <span class="n">xR</span> <span class="o">=</span> <span class="n">x</span><span class="p">;</span>
+      <span class="n">yR</span> <span class="o">=</span> <span class="n">y</span><span class="p">;</span>
+      <span class="n">zR</span> <span class="o">=</span> <span class="n">z</span><span class="p">;</span>
+    <span class="cp">]]></span>
+  <span class="nt"></sampling_group></span>
+<span class="nt"></output></span>
+</pre></div>
+</div>
+<p>The two top-level arguments in the <tt class="docutils literal"><span class="pre"><output></span></tt> element are “format” and “filename”.  Here we define the output filename, although it would have defaulted to this value.  We also choose the format to be HDF5, which is why the simulation resulted in the binary file “lorenz.h5” as well as “lorenz.xsil”.  If we had instead said <tt class="docutils literal"><span class="pre">format [...]
+<p>The <tt class="docutils literal"><span class="pre"><output></span></tt> element can contain any non-zero number of <tt class="docutils literal"><span class="pre"><sampling_group></span></tt> elements, which specify the entire output of the program.  They allow for subsampling, integration of some or all of the transverse dimensions, and/or conversion of some dimensions into Fourier space, but these will be described in more detail in the following examples.  We have a <tt  [...]
+<p>And that’s it.  This is quite a large framework to integrate three coupled ordinary differential equations, but the advantage of using XMDS2 is that vastly more complicated simulations can be performed without increasing the length or complexity of the XMDS2 script significantly.  The <a class="reference internal" href="worked_examples.html#workedexamples"><em>Worked Examples</em></a> section will provide more complicated examples with stochastic equations and partial differenti [...]
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="index.html">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+<div id="searchbox" style="display: none">
+  <h3>Quick search</h3>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" />
+      <input type="submit" value="Go" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    <p class="searchtip" style="font-size: 90%">
+    Enter search terms or a module, class or function name.
+    </p>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/documentation/upgrade.html b/documentation/upgrade.html
new file mode 100644
index 0000000..405a7b3
--- /dev/null
+++ b/documentation/upgrade.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>Upgrading From XMDS 1.X — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="index.html" /> 
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+  <div class="section" id="upgrading-from-xmds-1-x">
+<span id="upgradefromxmds1"></span><h1>Upgrading From XMDS 1.X<a class="headerlink" href="#upgrading-from-xmds-1-x" title="Permalink to this headline">¶</a></h1>
+<p>While <strong>XMDS2</strong> is a complete rewrite of the <strong>XMDS</strong> project, much of the syntax has remained very similar.  That said, your code will have to be rewritten as an XMDS2 program.  We recommend that you work through the <a class="reference internal" href="tutorial.html#quickstarttutorial"><em>Quickstart Tutorial</em></a> and perhaps the <a class="reference internal" href="worked_examples.html#workedexamples"><em>Worked Examples</em></a> sections, and then you s [...]
+<p>The main news when switching to XMDS2 is the long list of new things you can do.  If it’s an initial value problem, XMDS2 has a good chance of being able to solve it.</p>
+<p>We have made the decision to call the executables “xmds2” and “xsil2graphics2” so that you can keep using your old installation in parallel with the new version.</p>
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="index.html">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+<div id="searchbox" style="display: none">
+  <h3>Quick search</h3>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" />
+      <input type="submit" value="Go" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    <p class="searchtip" style="font-size: 90%">
+    Enter search terms or a module, class or function name.
+    </p>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/documentation/worked_examples.html b/documentation/worked_examples.html
new file mode 100644
index 0000000..2cca1ac
--- /dev/null
+++ b/documentation/worked_examples.html
@@ -0,0 +1,1280 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>Worked Examples — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="index.html" /> 
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+  <div class="section" id="worked-examples">
+<span id="workedexamples"></span><h1>Worked Examples<a class="headerlink" href="#worked-examples" title="Permalink to this headline">¶</a></h1>
+<p>One of the best ways to learn XMDS2 is to see several illustrative examples.  Here are a set of example scripts and explanations of the code, which will be a good way to get started.  As an instructional aid, they are meant to be read sequentially, but the adventurous could try starting with one that looked like a simulation they wanted to run, and adapt for their own purposes.</p>
+<blockquote>
+<div><p><a class="reference internal" href="#nonlinearschrodingerequation"><em>The nonlinear Schrödinger equation</em></a> (partial differential equation)</p>
+<p><a class="reference internal" href="#kubo"><em>Kubo Oscillator</em></a> (stochastic differential equations)</p>
+<p><a class="reference internal" href="#fibre"><em>Fibre Noise</em></a> (stochastic partial differential equation using parallel processing)</p>
+<p><a class="reference internal" href="#integerdimensionexample"><em>Integer Dimensions</em></a> (integer dimensions)</p>
+<p><a class="reference internal" href="#wignerarguments"><em>Wigner Function</em></a> (two dimensional PDE using parallel processing, passing arguments in at run time)</p>
+<p><a class="reference internal" href="#groundstatebec"><em>Finding the Ground State of a BEC (continuous renormalisation)</em></a> (PDE with continual renormalisation - computed vectors, filters, breakpoints)</p>
+<p><a class="reference internal" href="#hermitegaussgroundstatebec"><em>Finding the Ground State of a BEC again</em></a> (Hermite-Gaussian basis)</p>
+<p><a class="reference internal" href="#dmultistatese"><em>Multi-component Schrödinger equation</em></a> (combined integer and continuous dimensions with matrix multiplication, aliases)</p>
+</div></blockquote>
+<p>All of these scripts are available in the included “examples” folder, along with more examples that demonstrate other tricks.  Together, they provide starting points for a huge range of different simulations.</p>
+<div class="section" id="the-nonlinear-schrodinger-equation">
+<span id="nonlinearschrodingerequation"></span><h2>The nonlinear Schrödinger equation<a class="headerlink" href="#the-nonlinear-schrodinger-equation" title="Permalink to this headline">¶</a></h2>
+<p>This worked example will show a range of new features that can be used in an <strong>XMDS2</strong> script, and we will also examine our first partial differential equation.  We will take the one dimensional nonlinear Schrödinger equation, which is a common nonlinear wave equation.  The equation describing this problem is:</p>
+<div class="math">
+\[\frac{\partial \phi}{\partial \xi} = \frac{i}{2}\frac{\partial^2 \phi}{\partial \tau^2} - \Gamma(\tau)\phi+i|\phi|^2 \phi\]</div>
+<p>where <span class="math">\(\phi\)</span> is a complex-valued field, and <span class="math">\(\Gamma(\tau)\)</span> is a <span class="math">\(\tau\)</span>-dependent damping term.  Let us look at an XMDS2 script that integrates this equation, and then examine it in detail.</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+  <span class="nt"><name></span>nlse<span class="nt"></name></span>
+
+  <span class="nt"><author></span>Joe Hope<span class="nt"></author></span>
+  <span class="nt"><description></span>
+    The nonlinear Schrodinger equation in one dimension,
+    which is a simple partial differential equation.
+    We introduce several new features in this script.
+  <span class="nt"></description></span>
+
+  <span class="nt"><features></span>
+      <span class="nt"><benchmark</span> <span class="nt">/></span>
+      <span class="nt"><bing</span> <span class="nt">/></span>
+      <span class="nt"><fftw</span> <span class="na">plan=</span><span class="s">"patient"</span> <span class="nt">/></span>
+      <span class="nt"><openmp</span> <span class="nt">/></span>
+      <span class="nt"><auto_vectorise</span> <span class="nt">/></span>
+      <span class="nt"><globals></span>
+          <span class="cp"><![CDATA[</span>
+          <span class="k">const</span> <span class="kt">double</span> <span class="n">energy</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
+          <span class="k">const</span> <span class="kt">double</span> <span class="n">vel</span> <span class="o">=</span> <span class="mf">0.3</span><span class="p">;</span>
+          <span class="k">const</span> <span class="kt">double</span> <span class="n">hwhm</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">;</span>
+          <span class="cp">]]></span>
+       <span class="nt"></globals></span>
+     <span class="nt"></features></span>
+
+  <span class="nt"><geometry></span>
+      <span class="nt"><propagation_dimension></span> xi <span class="nt"></propagation_dimension></span>
+      <span class="nt"><transverse_dimensions></span>
+        <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"tau"</span> <span class="na">lattice=</span><span class="s">"128"</span>  <span class="na">domain=</span><span class="s">"(-6, 6)"</span> <span class="nt">/></span>
+      <span class="nt"></transverse_dimensions></span>
+   <span class="nt"></geometry></span>
+
+  <span class="nt"><vector</span> <span class="na">name=</span><span class="s">"wavefunction"</span> <span class="na">type=</span><span class="s">"complex"</span> <span class="na">dimensions=</span><span class="s">"tau"</span><span class="nt">></span>
+    <span class="nt"><components></span> phi <span class="nt"></components></span>
+    <span class="nt"><initialisation></span>
+      <span class="cp"><![CDATA[</span>
+      <span class="k">const</span> <span class="kt">double</span> <span class="n">w0</span> <span class="o">=</span> <span class="n">hwhm</span><span class="o">*</span><span class="n">sqrt</span><span class="p">(</span><span class="mi">2</span><span class="o">/</span><span class="n">log</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span>
+      <span class="k">const</span> <span class="kt">double</span> <span class="n">amp</span> <span class="o">=</span> <span class="n">sqrt</span><span class="p">(</span><span class="n">energy</span><span class="o">/</span><span class="n">w0</span><span class="o">/</span><span class="n">sqrt</span><span class="p">(</span><span class="n">M_PI</span><span class="o">/</span><span class="mi">2</span><span class="p">));</span>
+      <span class="n">phi</span> <span class="o">=</span> <span class="n">amp</span><span class="o">*</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="n">tau</span><span class="o">*</span><span class="n">tau</span><span class="o">/</span><span class="n">w0</span><span class="o">/</span><span class="n">w0</span><span class="p">)</span><span class="o">*</span><span class="n">exp</span><span class="p">(</span><span class="kc">i</span><span class=" [...]
+      <span class="cp">]]></span>
+    <span class="nt"></initialisation></span>
+  <span class="nt"></vector></span>
+
+  <span class="nt"><vector</span> <span class="na">name=</span><span class="s">"dampingVector"</span> <span class="na">type=</span><span class="s">"real"</span><span class="nt">></span>
+    <span class="nt"><components></span> Gamma <span class="nt"></components></span>
+    <span class="nt"><initialisation></span>
+      <span class="cp"><![CDATA[</span>
+      <span class="n">Gamma</span><span class="o">=</span><span class="mf">1.0</span><span class="o">*</span><span class="p">(</span><span class="mi">1</span><span class="o">-</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="n">pow</span><span class="p">(</span><span class="n">tau</span><span class="o">*</span><span class="n">tau</span><span class="o">/</span><span class="mf">4.0</span><span class="o">/</span><span class="mf">4.0</span><span cl [...]
+      <span class="cp">]]></span>
+    <span class="nt"></initialisation></span>
+  <span class="nt"></vector></span>
+
+  <span class="nt"><sequence></span>
+    <span class="nt"><integrate</span> <span class="na">algorithm=</span><span class="s">"ARK45"</span> <span class="na">interval=</span><span class="s">"20.0"</span> <span class="na">tolerance=</span><span class="s">"1e-7"</span><span class="nt">></span>
+      <span class="nt"><samples></span>10 100 10<span class="nt"></samples></span>
+      <span class="nt"><operators></span>
+        <span class="nt"><integration_vectors></span>wavefunction<span class="nt"></integration_vectors></span>
+        <span class="nt"><operator</span> <span class="na">kind=</span><span class="s">"ex"</span> <span class="na">constant=</span><span class="s">"yes"</span><span class="nt">></span>
+          <span class="nt"><operator_names></span>Ltt<span class="nt"></operator_names></span>
+          <span class="cp"><![CDATA[</span>
+            <span class="n">Ltt</span> <span class="o">=</span> <span class="o">-</span><span class="kc">i</span><span class="o">*</span><span class="n">ktau</span><span class="o">*</span><span class="n">ktau</span><span class="o">*</span><span class="mf">0.5</span><span class="p">;</span>
+          <span class="cp">]]></span>
+        <span class="nt"></operator></span>
+        <span class="cp"><![CDATA[</span>
+        <span class="n">dphi_dxi</span> <span class="o">=</span> <span class="n">Ltt</span><span class="p">[</span><span class="n">phi</span><span class="p">]</span> <span class="o">-</span> <span class="n">phi</span><span class="o">*</span><span class="n">Gamma</span> <span class="o">+</span> <span class="kc">i</span><span class="o">*</span><span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">)</span><span class="o">*</span><span class="n">phi</s [...]
+        <span class="cp">]]></span>
+        <span class="nt"><dependencies></span>dampingVector<span class="nt"></dependencies></span>
+      <span class="nt"></operators></span>
+    <span class="nt"></integrate></span>
+  <span class="nt"></sequence></span>
+
+  <span class="nt"><output></span>
+    <span class="nt"><sampling_group</span> <span class="na">basis=</span><span class="s">"tau"</span> <span class="na">initial_sample=</span><span class="s">"yes"</span><span class="nt">></span>
+      <span class="nt"><moments></span>density<span class="nt"></moments></span>
+      <span class="nt"><dependencies></span>wavefunction<span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">density</span> <span class="o">=</span> <span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">);</span>
+      <span class="cp">]]></span>
+    <span class="nt"></sampling_group></span>
+
+    <span class="nt"><sampling_group</span> <span class="na">basis=</span><span class="s">"tau(0)"</span> <span class="na">initial_sample=</span><span class="s">"yes"</span><span class="nt">></span>
+      <span class="nt"><moments></span>normalisation<span class="nt"></moments></span>
+      <span class="nt"><dependencies></span>wavefunction<span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">normalisation</span> <span class="o">=</span> <span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">);</span>
+      <span class="cp">]]></span>
+    <span class="nt"></sampling_group></span>
+
+    <span class="nt"><sampling_group</span> <span class="na">basis=</span><span class="s">"ktau(32)"</span> <span class="na">initial_sample=</span><span class="s">"yes"</span><span class="nt">></span>
+      <span class="nt"><moments></span>densityK<span class="nt"></moments></span>
+      <span class="nt"><dependencies></span>wavefunction<span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">densityK</span> <span class="o">=</span> <span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">);</span>
+      <span class="cp">]]></span>
+    <span class="nt"></sampling_group></span>
+
+  <span class="nt"></output></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+<p>Let us examine the new items in the <tt class="docutils literal"><span class="pre"><features></span></tt> element that we have demonstrated here.  The existence of the <tt class="docutils literal"><span class="pre"><benchmark></span></tt> element causes the simulation to be timed.  The <tt class="docutils literal"><span class="pre"><bing></span></tt> element causes the computer to make a sound upon the conclusion of the simulation.  The <tt class="docutils literal">< [...]
+<p>Finally, we use two tags to make the simulation run faster.  The <tt class="docutils literal"><span class="pre"><auto_vectorise></span></tt> element switches on several loop optimisations that exist in later versions of the GCC compiler.  The <tt class="docutils literal"><span class="pre"><openmp></span></tt> element turns on threaded parallel processing using the OpenMP standard where possible.  These options are not activated by default as they only exist on certain comp [...]
+<p>Let us examine the <tt class="docutils literal"><span class="pre"><geometry></span></tt> element.</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><geometry></span>
+    <span class="nt"><propagation_dimension></span> xi <span class="nt"></propagation_dimension></span>
+    <span class="nt"><transverse_dimensions></span>
+      <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"tau"</span> <span class="na">lattice=</span><span class="s">"128"</span>  <span class="na">domain=</span><span class="s">"(-6, 6)"</span> <span class="nt">/></span>
+    <span class="nt"></transverse_dimensions></span>
+ <span class="nt"></geometry></span>
+</pre></div>
+</div>
+<p>This is the first example that includes a transverse dimension.  We have only one dimension, and we have labelled it “tau”.  It is a continuous dimension, but only defined on a grid containing 128 points (defined with the lattice variable), and on a domain from -6 to 6.  The default is that transforms in continuous dimensions are fast Fourier transforms, which means that this dimension is effectively defined on a loop, and the “tau=-6” and “tau=6” p [...]
+<p>Two vector elements have been defined in this simulation.  One defines the complex-valued wavefunction “phi” that we wish to evolve.  We define the transverse dimensions over which this vector is defined by the <tt class="docutils literal"><span class="pre">dimensions</span></tt> tag in the description.  By default, it is defined over all of the transverse dimensions in the <tt class="docutils literal"><span class="pre"><geometry></span></tt> element, so even though  [...]
+<p>The second vector element contains the component “Gamma” which is a function of the transverse variable tau, as specified in the equation of motion for the field.  This second vector could have been avoided in two ways.  First, the function could have been written explicitly in the integrate block where it is required, but calculating it once and then recalling it from memory is far more efficient.  Second, it could have been included in the “wavefunction” vect [...]
+<p>The <tt class="docutils literal"><span class="pre"><integrate></span></tt> element for a partial differential equation has some new features:</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><integrate</span> <span class="na">algorithm=</span><span class="s">"ARK45"</span> <span class="na">interval=</span><span class="s">"20.0"</span> <span class="na">tolerance=</span><span class="s">"1e-7"</span><span class="nt">></span>
+  <span class="nt"><samples></span>10 100 10<span class="nt"></samples></span>
+  <span class="nt"><operators></span>
+    <span class="nt"><integration_vectors></span>wavefunction<span class="nt"></integration_vectors></span>
+    <span class="nt"><operator</span> <span class="na">kind=</span><span class="s">"ex"</span> <span class="na">constant=</span><span class="s">"yes"</span><span class="nt">></span>
+      <span class="nt"><operator_names></span>Ltt<span class="nt"></operator_names></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">Ltt</span> <span class="o">=</span> <span class="o">-</span><span class="kc">i</span><span class="o">*</span><span class="n">ktau</span><span class="o">*</span><span class="n">ktau</span><span class="o">*</span><span class="mf">0.5</span><span class="p">;</span>
+      <span class="cp">]]></span>
+    <span class="nt"></operator></span>
+    <span class="cp"><![CDATA[</span>
+    <span class="n">dphi_dxi</span> <span class="o">=</span> <span class="n">Ltt</span><span class="p">[</span><span class="n">phi</span><span class="p">]</span> <span class="o">-</span> <span class="n">phi</span><span class="o">*</span><span class="n">Gamma</span> <span class="o">+</span> <span class="kc">i</span><span class="o">*</span><span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">)</span><span class="o">*</span><span class="n">phi</span> [...]
+    <span class="cp">]]></span>
+    <span class="nt"><dependencies></span>dampingVector<span class="nt"></dependencies></span>
+  <span class="nt"></operators></span>
+<span class="nt"></integrate></span>
+</pre></div>
+</div>
+<p>There are some trivial changes from the tutorial script, such as the fact that we are using the ARK45 algorithm rather than ARK89.  Higher order algorithms are often better, but not always.  Also, since this script has multiple output groups, we have to specify how many times each of these output groups are sampled in the <tt class="docutils literal"><span class="pre"><samples></span></tt> element, so there are three numbers there.  Besides the vectors that are to be integrated, [...]
+<p>The equation of motion as written in the CDATA block looks almost identical to our desired equation of motion, except for the term based on the second derivative, which introduces an important new concept.  Inside the <tt class="docutils literal"><span class="pre"><operators></span></tt> element, we can define any number of operators.  Operators are used to define functions in the transformed space of each dimension, which in this case is Fourier space.  The derivative of a func [...]
+<p>Operators can be explicit (<tt class="docutils literal"><span class="pre">kind="ex"</span></tt>) or in the interaction picture (<tt class="docutils literal"><span class="pre">kind="ip"</span></tt>).  The interaction picture can be more efficient, but it restricts the possible syntax of the equation of motion.  Safe utilisation of interaction picture operators will be described later, but for now let us emphasise that <strong>explicit operators should be used</stron [...]
+<p>The output of a partial differential equation offers more possibilities than an ordinary differential equation, and we examine some in this example.</p>
+<p>For vectors with transverse dimensions, we can sample functions of the vectors on the full lattice or a subset of the points.  In the <tt class="docutils literal"><span class="pre"><sampling_group></span></tt> element, we must add a string called “basis” that determines the space in which each transverse dimension is to be sampled, optionally followed by the number of points to be sampled in parentheses.  If the number of points is not specified, it will default to a [...]
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><sampling_group</span> <span class="na">basis=</span><span class="s">"tau"</span> <span class="na">initial_sample=</span><span class="s">"yes"</span><span class="nt">></span>
+  <span class="nt"><moments></span>density<span class="nt"></moments></span>
+  <span class="nt"><dependencies></span>wavefunction<span class="nt"></dependencies></span>
+  <span class="cp"><![CDATA[</span>
+    <span class="n">density</span> <span class="o">=</span> <span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">);</span>
+  <span class="cp">]]></span>
+<span class="nt"></sampling_group></span>
+</pre></div>
+</div>
+<p>The first output group samples the mod square of the vector “phi” over the full lattice of 128 points.</p>
+<p>If the lattice parameter is set to zero points, then the corresponding dimension is integrated.</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><sampling_group</span> <span class="na">basis=</span><span class="s">"tau(0)"</span> <span class="na">initial_sample=</span><span class="s">"yes"</span><span class="nt">></span>
+  <span class="nt"><moments></span>normalisation<span class="nt"></moments></span>
+  <span class="nt"><dependencies></span>wavefunction<span class="nt"></dependencies></span>
+  <span class="cp"><![CDATA[</span>
+    <span class="n">normalisation</span> <span class="o">=</span> <span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">);</span>
+  <span class="cp">]]></span>
+<span class="nt"></sampling_group></span>
+</pre></div>
+</div>
+<p>This second output group samples the normalisation of the wavefunction <span class="math">\(\int d\tau |\phi(\tau)|^2\)</span> over the domain of <span class="math">\(\tau\)</span>.  This output requires only a single real number per sample, so in the integrate element we have chosen to sample it many more times than the vectors themselves.</p>
+<p>Finally, functions of the vectors can be sampled with their dimensions in Fourier space.</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><sampling_group</span> <span class="na">basis=</span><span class="s">"ktau(32)"</span> <span class="na">initial_sample=</span><span class="s">"yes"</span><span class="nt">></span>
+  <span class="nt"><moments></span>densityK<span class="nt"></moments></span>
+  <span class="nt"><dependencies></span>wavefunction<span class="nt"></dependencies></span>
+  <span class="cp"><![CDATA[</span>
+    <span class="n">densityK</span> <span class="o">=</span> <span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">);</span>
+  <span class="cp">]]></span>
+<span class="nt"></sampling_group></span>
+</pre></div>
+</div>
+<p>The final output group above samples the mod square of the Fourier-space wavefunction phi on a sample of 32 points.</p>
+</div>
+<div class="section" id="kubo-oscillator">
+<span id="kubo"></span><h2>Kubo Oscillator<a class="headerlink" href="#kubo-oscillator" title="Permalink to this headline">¶</a></h2>
+<p>This example demonstrates the integration of a stochastic differential equation.  We examine the Kubo oscillator, which is a complex variable whose phase is evolving according to a Wiener noise.  In a suitable rotating frame, the equation of motion for the variable is</p>
+<div class="math">
+\[\frac{dz}{dt} = i z \;\eta\]</div>
+<p>where <span class="math">\(\eta(t)\)</span> is the Wiener differential, and we interpret this as a Stratonovich equation.  In other common notation, this is sometimes written:</p>
+<div class="math">
+\[dz = i z \;\circ dW\]</div>
+<p>Most algorithms employed by XMDS require the equations to be input in the Stratonovich form.  Ito differential equations can always be transformed into Stratonovich euqations, and in this case the difference is equivalent to the choice of rotating frame.  This equation is solved by the following XMDS2 script:</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+  <span class="nt"><name></span>kubo<span class="nt"></name></span>
+  <span class="nt"><author></span>Graham Dennis and Joe Hope<span class="nt"></author></span>
+  <span class="nt"><description></span>
+    Example Kubo oscillator simulation
+  <span class="nt"></description></span>
+
+  <span class="nt"><geometry></span>
+    <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+  <span class="nt"></geometry></span>
+
+  <span class="nt"><driver</span> <span class="na">name=</span><span class="s">"multi-path"</span> <span class="na">paths=</span><span class="s">"10000"</span> <span class="nt">/></span>
+
+  <span class="nt"><features></span>
+    <span class="nt"><error_check</span> <span class="nt">/></span>
+    <span class="nt"><benchmark</span> <span class="nt">/></span>
+  <span class="nt"></features></span>
+
+  <span class="nt"><noise_vector</span> <span class="na">name=</span><span class="s">"drivingNoise"</span> <span class="na">dimensions=</span><span class="s">""</span> <span class="na">kind=</span><span class="s">"wiener"</span> <span class="na">type=</span><span class="s">"real"</span> <span class="na">method=</span><span class="s">"dsfmt"</span> <span class="na">seed=</span><span class="s">"314 159 276"</span><span class="n [...]
+    <span class="nt"><components></span>eta<span class="nt"></components></span>
+  <span class="nt"></noise_vector></span>
+
+  <span class="nt"><vector</span> <span class="na">name=</span><span class="s">"main"</span> <span class="na">type=</span><span class="s">"complex"</span><span class="nt">></span>
+    <span class="nt"><components></span> z <span class="nt"></components></span>
+    <span class="nt"><initialisation></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">z</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">;</span>
+      <span class="cp">]]></span>
+    <span class="nt"></initialisation></span>
+  <span class="nt"></vector></span>
+
+  <span class="nt"><sequence></span>
+    <span class="nt"><integrate</span> <span class="na">algorithm=</span><span class="s">"SI"</span> <span class="na">interval=</span><span class="s">"10"</span> <span class="na">steps=</span><span class="s">"1000"</span><span class="nt">></span>
+      <span class="nt"><samples></span>100<span class="nt"></samples></span>
+      <span class="nt"><operators></span>
+        <span class="nt"><integration_vectors></span>main<span class="nt"></integration_vectors></span>
+        <span class="nt"><dependencies></span>drivingNoise<span class="nt"></dependencies></span>
+        <span class="cp"><![CDATA[</span>
+          <span class="n">dz_dt</span> <span class="o">=</span> <span class="kc">i</span><span class="o">*</span><span class="n">z</span><span class="o">*</span><span class="n">eta</span><span class="p">;</span>
+        <span class="cp">]]></span>
+      <span class="nt"></operators></span>
+    <span class="nt"></integrate></span>
+  <span class="nt"></sequence></span>
+
+  <span class="nt"><output></span>
+    <span class="nt"><sampling_group</span> <span class="na">initial_sample=</span><span class="s">"yes"</span><span class="nt">></span>
+      <span class="nt"><moments></span>zR zI<span class="nt"></moments></span>
+      <span class="nt"><dependencies></span>main<span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">zR</span> <span class="o">=</span> <span class="n">z</span><span class="p">.</span><span class="n">Re</span><span class="p">();</span>
+        <span class="n">zI</span> <span class="o">=</span> <span class="n">z</span><span class="p">.</span><span class="n">Im</span><span class="p">();</span>
+      <span class="cp">]]></span>
+    <span class="nt"></sampling_group></span>
+  <span class="nt"></output></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+<p>The first new item in this script is the <tt class="docutils literal"><span class="pre"><driver></span></tt> element.  This element enables us to change top level management of the simulation.  Without this element, XMDS2 will integrate the stochastic equation as described.  With this element and the option <tt class="docutils literal"><span class="pre">name="multi-path"</span></tt>, it will integrate it multiple times, using different random numbers each time.  The ou [...]
+<p>In the <tt class="docutils literal"><span class="pre"><features></span></tt> element we have included the <tt class="docutils literal"><span class="pre"><error_check></span></tt> element.  This performs the integration first with the specified number of steps (or with the specified tolerance), and then with twice the number of steps (or equivalently reduced tolerance).  The output then includes the difference between the output variables on the coarse and the fine grids as [...]
+<p>We define the stochastic elements in a simulation with the <tt class="docutils literal"><span class="pre"><noise_vector></span></tt> element.</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><noise_vector</span> <span class="na">name=</span><span class="s">"drivingNoise"</span> <span class="na">dimensions=</span><span class="s">""</span> <span class="na">kind=</span><span class="s">"wiener"</span> <span class="na">type=</span><span class="s">"real"</span> <span class="na">method=</span><span class="s">"dsfmt"</span> <span class="na">seed=</span><sp [...]
+ <span class="nt"><components></span>eta<span class="nt"></components></span>
+<span class="nt"></noise_vector></span>
+</pre></div>
+</div>
+<p>This defines a vector that is used like any other, but it will be randomly generated with particular statistics and characteristics rather than initialised.  The name, dimensions and type tags are defined just as for normal vectors.  The names of the components are also defined in the same way.  The noise is defined as a Wiener noise here (<tt class="docutils literal"><span class="pre">kind</span> <span class="pre">=</span> <span class="pre">"wiener"</span></tt>), which is a [...]
+<p>We may also define a noise method to choose a non-default pseudo random number generator, and a seed for the random number generator.  Using a seed can be very useful when debugging the behaviour of a simulation, and many compilers have pseudo-random number generators that are superior to the default option (posix).</p>
+<p>The integrate block is using the semi-implicit algorithm (<tt class="docutils literal"><span class="pre">algorithm="SI"</span></tt>), which is a good default choice for stochastic problems, even though it is only second order convergent for deterministic equations.  More will be said about algorithm choice later, but for now we should note that adaptive algorithms based on Runge-Kutta methods are not guaranteed to converge safely for stochastic equations.  This can be partic [...]
+<p>We include elements from the noise vector in the equation of motion just as we do for any other vector.  The default SI and Runge-Kutta algorithms converge to the <em>Stratonovich</em> integral.  Ito stochastic equations can be converted to Stratonovich form and vice versa.</p>
+<p>Executing the generated program ‘kubo’ gives slightly different output due to the “multi-path” driver.</p>
+<div class="highlight-none"><div class="highlight"><pre>$ ./kubo
+Beginning full step integration ...
+Starting path 1
+Starting path 2
+
+... many lines omitted ...
+
+Starting path 9999
+Starting path 10000
+Beginning half step integration ...
+Starting path 1
+Starting path 2
+
+... many lines omitted ...
+
+Starting path 9999
+Starting path 10000
+Generating output for kubo
+Maximum step error in moment group 1 was 4.942549e-04
+Time elapsed for simulation is: 2.71 seconds
+</pre></div>
+</div>
+<p>The maximum step error in each moment group is given in absolute terms.  This is the largest difference between the full step integration and the half step integration.  While a single path might be very stochastic:</p>
+<div class="figure align-center">
+<img alt="_images/kuboSingle.png" src="_images/kuboSingle.png" />
+<p class="caption">The mean value of the real and imaginary components of the z variable for a single path of the simulation.</p>
+</div>
+<p>The average over multiple paths can be increasingly smooth.</p>
+<div class="figure align-center">
+<img alt="_images/kubo10000.png" src="_images/kubo10000.png" />
+<p class="caption">The mean and standard error of the z variable averaged over 10000 paths, as given by this simulation.  It agrees within the standard error with the expected result of <span class="math">\(\exp(-t/2)\)</span>.</p>
+</div>
+</div>
+<div class="section" id="fibre-noise">
+<span id="fibre"></span><h2>Fibre Noise<a class="headerlink" href="#fibre-noise" title="Permalink to this headline">¶</a></h2>
+<p>This simulation is a stochastic partial differential equation, in which a one-dimensional damped field is subject to a complex noise. This script can be found in <tt class="docutils literal"><span class="pre">examples/fibre.xmds</span></tt>.</p>
+<div class="math">
+\[\frac{\partial \psi}{\partial t} = -i \frac{\partial^2 \psi}{\partial x^2} -\gamma \psi+\beta \frac{1}{\sqrt{2}}\left(\eta_1(x)+i\eta_2(x)\right)\]</div>
+<p>where the noise terms <span class="math">\(\eta_j(x,t)\)</span> are Wiener differentials and the equation is interpreted as a Stratonovich differential equation.  On a finite grid, these increments have variance <span class="math">\(\frac{1}{\Delta x \Delta t}\)</span>.</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+  <span class="nt"><name></span>fibre<span class="nt"></name></span>
+  <span class="nt"><author></span>Joe Hope and Graham Dennis<span class="nt"></author></span>
+  <span class="nt"><description></span>
+    Example fibre noise simulation
+  <span class="nt"></description></span>
+
+  <span class="nt"><geometry></span>
+    <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+    <span class="nt"><transverse_dimensions></span>
+      <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"x"</span> <span class="na">lattice=</span><span class="s">"64"</span>  <span class="na">domain=</span><span class="s">"(-5, 5)"</span> <span class="nt">/></span>
+    <span class="nt"></transverse_dimensions></span>
+  <span class="nt"></geometry></span>
+
+  <span class="nt"><driver</span> <span class="na">name=</span><span class="s">"mpi-multi-path"</span> <span class="na">paths=</span><span class="s">"8"</span> <span class="nt">/></span>
+
+  <span class="nt"><features></span>
+    <span class="nt"><auto_vectorise</span> <span class="nt">/></span>
+    <span class="nt"><benchmark</span> <span class="nt">/></span>
+    <span class="nt"><error_check</span> <span class="nt">/></span>
+    <span class="nt"><globals></span>
+      <span class="cp"><![CDATA[</span>
+      <span class="k">const</span> <span class="nf">real</span> <span class="n">ggamma</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">;</span>
+      <span class="k">const</span> <span class="nf">real</span> <span class="n">beta</span> <span class="o">=</span> <span class="n">sqrt</span><span class="p">(</span><span class="n">M_PI</span><span class="o">*</span><span class="n">ggamma</span><span class="o">/</span><span class="mf">10.0</span><span class="p">);</span>
+      <span class="cp">]]></span>
+    <span class="nt"></globals></span>
+  <span class="nt"></features></span>
+
+  <span class="nt"><noise_vector</span> <span class="na">name=</span><span class="s">"drivingNoise"</span> <span class="na">dimensions=</span><span class="s">"x"</span> <span class="na">kind=</span><span class="s">"wiener"</span> <span class="na">type=</span><span class="s">"complex"</span> <span class="na">method=</span><span class="s">"dsfmt"</span> <span class="na">seed=</span><span class="s">"314 159 276"</span><span clas [...]
+    <span class="nt"><components></span>Eta<span class="nt"></components></span>
+  <span class="nt"></noise_vector></span>
+
+  <span class="nt"><vector</span> <span class="na">name=</span><span class="s">"main"</span> <span class="na">initial_basis=</span><span class="s">"x"</span> <span class="na">type=</span><span class="s">"complex"</span><span class="nt">></span>
+    <span class="nt"><components></span>phi<span class="nt"></components></span>
+    <span class="nt"><initialisation></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">phi</span> <span class="o">=</span> <span class="mf">0.0</span><span class="p">;</span>
+      <span class="cp">]]></span>
+    <span class="nt"></initialisation></span>
+  <span class="nt"></vector></span>
+
+  <span class="nt"><sequence></span>
+    <span class="nt"><integrate</span> <span class="na">algorithm=</span><span class="s">"SI"</span> <span class="na">iterations=</span><span class="s">"3"</span> <span class="na">interval=</span><span class="s">"2.5"</span> <span class="na">steps=</span><span class="s">"200000"</span><span class="nt">></span>
+      <span class="nt"><samples></span>50<span class="nt"></samples></span>
+      <span class="nt"><operators></span>
+        <span class="nt"><operator</span> <span class="na">kind=</span><span class="s">"ex"</span> <span class="na">constant=</span><span class="s">"yes"</span><span class="nt">></span>
+          <span class="nt"><operator_names></span>L<span class="nt"></operator_names></span>
+          <span class="cp"><![CDATA[</span>
+            <span class="n">L</span> <span class="o">=</span> <span class="o">-</span><span class="kc">i</span><span class="o">*</span><span class="n">kx</span><span class="o">*</span><span class="n">kx</span><span class="p">;</span>
+          <span class="cp">]]></span>
+        <span class="nt"></operator></span>
+        <span class="nt"><dependencies></span>drivingNoise<span class="nt"></dependencies></span>
+        <span class="nt"><integration_vectors></span>main<span class="nt"></integration_vectors></span>
+        <span class="cp"><![CDATA[</span>
+          <span class="n">dphi_dt</span> <span class="o">=</span> <span class="n">L</span><span class="p">[</span><span class="n">phi</span><span class="p">]</span> <span class="o">-</span> <span class="n">ggamma</span><span class="o">*</span><span class="n">phi</span> <span class="o">+</span> <span class="n">beta</span><span class="o">*</span><span class="n">Eta</span><span class="p">;</span>
+        <span class="cp">]]></span>
+      <span class="nt"></operators></span>
+    <span class="nt"></integrate></span>
+  <span class="nt"></sequence></span>
+
+  <span class="nt"><output></span>
+    <span class="nt"><sampling_group</span> <span class="na">basis=</span><span class="s">"kx"</span> <span class="na">initial_sample=</span><span class="s">"yes"</span><span class="nt">></span>
+      <span class="nt"><moments></span>pow_dens<span class="nt"></moments></span>
+      <span class="nt"><dependencies></span>main<span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">pow_dens</span> <span class="o">=</span> <span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">);</span>
+      <span class="cp">]]></span>
+    <span class="nt"></sampling_group></span>
+  <span class="nt"></output></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+<p>Note that the noise vector used in this example is complex-valued, and has the argument <tt class="docutils literal"><span class="pre">dimensions="x"</span></tt> to define it as a field of delta-correlated noises along the x-dimension.</p>
+<p>This simulation demonstrates the ease with which XMDS2 can be used in a parallel processing environment.  Instead of using the stochastic driver “multi-path”, we simply replace it with “mpi-multi-path”.  This instructs XMDS2 to write a parallel version of the program based on the widespread <a class="reference external" href="http://www.open-mpi.org/">MPI standard</a>.  This protocol allows multiple processors or clusters of computers to work simultaneously on  [...]
+<p>Executing this program is slightly different with the MPI option.  The details can change between MPI implementations, but as an example:</p>
+<div class="highlight-none"><div class="highlight"><pre>$xmds2 fibre.xmds
+xmds2 version 2.1 "Happy Mollusc" (r2543)
+Copyright 2000-2012 Graham Dennis, Joseph Hope, Mattias Johnsson
+                    and the xmds team
+Generating source code...
+... done
+Compiling simulation...
+... done. Type './fibre' to run.
+</pre></div>
+</div>
+<p>Note that different compile options (and potentially a different compiler) are used by XMDS2, but this is transparent to the user.  MPI simulations will have to be run using syntax that will depend on the MPI implementation.  Here we show the version based on the popular open source <a class="reference external" href="http://www.open-mpi.org/">Open-MPI</a> implementation.</p>
+<div class="highlight-none"><div class="highlight"><pre>$ mpirun -np 4 ./fibre
+Found enlightenment... (Importing wisdom)
+Planning for x <---> kx transform... done.
+Beginning full step integration ...
+Rank[0]: Starting path 1
+Rank[1]: Starting path 2
+Rank[2]: Starting path 3
+Rank[3]: Starting path 4
+Rank[3]: Starting path 8
+Rank[0]: Starting path 5
+Rank[1]: Starting path 6
+Rank[2]: Starting path 7
+Rank[3]: Starting path 4
+Beginning half step integration ...
+Rank[0]: Starting path 1
+Rank[2]: Starting path 3
+Rank[1]: Starting path 2
+Rank[3]: Starting path 8
+Rank[0]: Starting path 5
+Rank[2]: Starting path 7
+Rank[1]: Starting path 6
+Generating output for fibre
+Maximum step error in moment group 1 was 4.893437e-04
+Time elapsed for simulation is: 20.99 seconds
+</pre></div>
+</div>
+<p>In this example we used four processors.  The different processors are labelled by their “Rank”, starting at zero.  Because the processors are working independently, the output from the different processors can come in a randomised order.  In the end, however, the .xsil and data files are constructed identically to the single processor outputs.</p>
+<p>The analytic solution to the stochastic averages of this equation is given by</p>
+<div class="math">
+\[\langle |\psi(k,t)|^2 \rangle = \exp(-2\gamma t)|\psi(k,0)|^2 +\frac{\beta^2 L_x}{4\pi \gamma} \left(1-\exp(-2\gamma t)\right)\]</div>
+<p>where <span class="math">\(L_x\)</span> is the length of the x domain.  We see that a single integration of these equations is quite chaotic:</p>
+<div class="figure align-center">
+<img alt="_images/fibreSingle.png" src="_images/fibreSingle.png" />
+<p class="caption">The momentum space density of the field as a function of time for a single path realisation.</p>
+</div>
+<p>while an average of 1024 paths (change <tt class="docutils literal"><span class="pre">paths="8"</span></tt> to <tt class="docutils literal"><span class="pre">paths="1024"</span></tt> in the <tt class="docutils literal"><span class="pre"><driver></span></tt> element) converges nicely to the analytic solution:</p>
+<div class="figure align-center">
+<img alt="_images/fibre1024.png" src="_images/fibre1024.png" />
+<p class="caption">The momentum space density of the field as a function of time for an average of 1024 paths.</p>
+</div>
+</div>
+<div class="section" id="integer-dimensions">
+<span id="integerdimensionexample"></span><h2>Integer Dimensions<a class="headerlink" href="#integer-dimensions" title="Permalink to this headline">¶</a></h2>
+<p>This example shows how to handle systems with integer-valued transverse dimensions.  We will integrate the following set of equations</p>
+<div class="math">
+\[\frac{dx_j}{dt} = x_j \left(x_{j-1}-x_{j+1}\right)\]</div>
+<p>where <span class="math">\(x_j\)</span> are complex-valued variables defined on a ring, such that <span class="math">\(j\in \{0,j_{max}\}\)</span> and the <span class="math">\(x_{j_{max}+1}\)</span> variable is identified with the variable <span class="math">\(x_{0}\)</span>, and the variable <span class="math">\(x_{-1}\)</span> is identified with the variable <span class="math">\(x_{j_{max}}\)</span>.</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+  <span class="nt"><name></span>integer_dimensions<span class="nt"></name></span>
+  <span class="nt"><author></span>Graham Dennis<span class="nt"></author></span>
+  <span class="nt"><description></span>
+    XMDS2 script to test integer dimensions.
+  <span class="nt"></description></span>
+
+  <span class="nt"><features></span>
+    <span class="nt"><benchmark</span> <span class="nt">/></span>
+    <span class="nt"><error_check</span> <span class="nt">/></span>
+    <span class="nt"><bing</span> <span class="nt">/></span>
+    <span class="nt"><diagnostics</span> <span class="nt">/></span> <span class="c"><!-- This will make sure that all nonlocal accesses of dimensions are safe --></span>
+  <span class="nt"></features></span>
+
+  <span class="nt"><geometry></span>
+    <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+    <span class="nt"><transverse_dimensions></span>
+      <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"j"</span> <span class="na">type=</span><span class="s">"integer"</span> <span class="na">lattice=</span><span class="s">"5"</span> <span class="na">domain=</span><span class="s">"(0,4)"</span> <span class="nt">/></span>
+    <span class="nt"></transverse_dimensions></span>
+  <span class="nt"></geometry></span>
+
+  <span class="nt"><vector</span> <span class="na">name=</span><span class="s">"main"</span> <span class="na">type=</span><span class="s">"complex"</span><span class="nt">></span>
+    <span class="nt"><components></span> x <span class="nt"></components></span>
+    <span class="nt"><initialisation></span>
+      <span class="cp"><![CDATA[</span>
+      <span class="n">x</span> <span class="o">=</span> <span class="mf">1.0e-3</span><span class="p">;</span>
+      <span class="n">x</span><span class="p">(</span><span class="n">j</span> <span class="o">=></span> <span class="mi">0</span><span class="p">)</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">;</span>
+      <span class="cp">]]></span>
+    <span class="nt"></initialisation></span>
+  <span class="nt"></vector></span>
+
+  <span class="nt"><sequence></span>
+    <span class="nt"><integrate</span> <span class="na">algorithm=</span><span class="s">"ARK45"</span> <span class="na">interval=</span><span class="s">"60"</span> <span class="na">steps=</span><span class="s">"25000"</span> <span class="na">tolerance=</span><span class="s">"1.0e-9"</span><span class="nt">></span>
+      <span class="nt"><samples></span>1000<span class="nt"></samples></span>
+      <span class="nt"><operators></span>
+        <span class="nt"><integration_vectors></span>main<span class="nt"></integration_vectors></span>
+        <span class="cp"><![CDATA[</span>
+        <span class="kt">long</span> <span class="n">j_minus_one</span> <span class="o">=</span> <span class="p">(</span><span class="n">j</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="n">_lattice_j</span><span class="p">;</span>
+        <span class="k">if</span> <span class="p">(</span><span class="n">j_minus_one</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span>
+          <span class="n">j_minus_one</span> <span class="o">+=</span> <span class="n">_lattice_j</span><span class="p">;</span>
+        <span class="kt">long</span> <span class="n">j_plus_one</span>  <span class="o">=</span> <span class="p">(</span><span class="n">j</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="n">_lattice_j</span><span class="p">;</span>
+        <span class="n">dx_dt</span><span class="p">(</span><span class="n">j</span> <span class="o">=></span> <span class="n">j</span><span class="p">)</span> <span class="o">=</span> <span class="n">x</span><span class="p">(</span><span class="n">j</span> <span class="o">=></span> <span class="n">j</span><span class="p">)</span><span class="o">*</span><span class="p">(</span><span class="n">x</span><span class="p">(</span><span class="n">j</span> <span class="o">=></span> <spa [...]
+        <span class="cp">]]></span>
+      <span class="nt"></operators></span>
+    <span class="nt"></integrate></span>
+  <span class="nt"></sequence></span>
+
+  <span class="nt"><output></span>
+    <span class="nt"><sampling_group</span> <span class="na">basis=</span><span class="s">"j"</span> <span class="na">initial_sample=</span><span class="s">"yes"</span><span class="nt">></span>
+      <span class="nt"><moments></span>xR<span class="nt"></moments></span>
+      <span class="nt"><dependencies></span>main<span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">xR</span> <span class="o">=</span> <span class="n">x</span><span class="p">.</span><span class="n">Re</span><span class="p">();</span>
+      <span class="cp">]]></span>
+    <span class="nt"></sampling_group></span>
+  <span class="nt"></output></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+<p>The first extra feature we have used in this script is the <tt class="docutils literal"><span class="pre"><diagnostics></span></tt> element.  It performs run-time checking that our generated code does not accidentally attempt to access a part of our vector that does not exist.  Removing this tag will increase the speed of the simulation, but its presence helps catch coding errors.</p>
+<p>The simulation defines a vector with a single transverse dimension labelled “j”, of type “integer” (“int” and “long” can also be used as synonyms for “integer”).  In the absence of an explicit type, the dimension is assumed to be real-valued.  The dimension has a “domain” argument as normal, defining the minimum and maximum values of the dimension’s range.  The lattice element, if specified, is used as a che [...]
+<p>Integer-valued dimensions can be called non-locally.  Real-valued dimensions are typically coupled non-locally only through local operations in the transformed space of the dimension, but can be called non-locally in certain other situations as described in <a class="reference internal" href="reference_elements.html#referencingnonlocal"><em>the reference</em></a>.  The syntax for calling integer dimensions non-locally can be seen in the initialisation CDATA block:</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre>x = 1.0e-3;
+x(j => 0) = 1.0;
+</pre></div>
+</div>
+<p>where the syntax <tt class="docutils literal"><span class="pre">x(j</span> <span class="pre">=></span> <span class="pre">0)</span></tt> is used to reference the variable <span class="math">\(x_0\)</span> directly.  We see a more elaborate example in the integrate CDATA block:</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre>dx_dt(j => j) = x(j => j)*(x(j => j_minus_one) - x(j => j_plus_one));
+</pre></div>
+</div>
+<p>where the vector “x” is called using locally defined variables.  This syntax is chosen so that multiple dimensions can be addressed non-locally with minimal possibility for confusion.</p>
+</div>
+<div class="section" id="wigner-function">
+<span id="wignerarguments"></span><h2>Wigner Function<a class="headerlink" href="#wigner-function" title="Permalink to this headline">¶</a></h2>
+<p>This example integrates the two-dimensional partial differential equation</p>
+<div class="math">
+\[\begin{split}\begin{split}
+\frac{\partial W}{\partial t} &= \Bigg[ \left(\omega + \frac{U_{int}}{\hbar}\left(x^2+y^2-1\right)\right) \left(x \frac{\partial}{\partial y}
+- y \frac{\partial}{\partial x}\right)\\
+&\phantom{=\Bigg[} - \frac{U_{int}}{16 \hbar}\left(x\left(\frac{\partial^3}{\partial x^2 \partial y}
++\frac{\partial^3}{\partial y^3}\right)-y\left(\frac{\partial^3}{\partial y^2 \partial x}+\frac{\partial^3}{\partial x^3}\right)\right)\Bigg]W(x,y,t)
+\end{split}\end{split}\]</div>
+<p>with the added restriction that the derivative is forced to zero outside a certain radius.  This extra condition helps maintain the long-term stability of the integration. The script can be found in <tt class="docutils literal"><span class="pre">examples/wigner_arguments_mpi.xmds</span></tt> under your XMDS2 installation directory.</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+  <span class="nt"><name></span>wigner<span class="nt"></name></span>
+  <span class="nt"><author></span>Graham Dennis and Joe Hope<span class="nt"></author></span>
+  <span class="nt"><description></span>
+    Simulation of the Wigner function for an anharmonic oscillator with the initial state
+    being a coherent state.
+  <span class="nt"></description></span>
+  <span class="nt"><features></span>
+    <span class="nt"><benchmark</span> <span class="nt">/></span>
+    <span class="nt"><globals></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="nf">real</span> <span class="n">Uint_hbar_on16</span><span class="p">;</span>
+      <span class="cp">]]></span>
+    <span class="nt"></globals></span>
+    <span class="nt"><arguments></span>
+      <span class="nt"><argument</span> <span class="na">name=</span><span class="s">"omega"</span> <span class="na">type=</span><span class="s">"real"</span> <span class="na">default_value=</span><span class="s">"0.0"</span> <span class="nt">/></span>
+      <span class="nt"><argument</span> <span class="na">name=</span><span class="s">"alpha_0"</span>     <span class="na">type=</span><span class="s">"real"</span> <span class="na">default_value=</span><span class="s">"3.0"</span> <span class="nt">/></span>
+      <span class="nt"><argument</span> <span class="na">name=</span><span class="s">"absorb"</span>     <span class="na">type=</span><span class="s">"real"</span> <span class="na">default_value=</span><span class="s">"8.0"</span> <span class="nt">/></span>
+      <span class="nt"><argument</span> <span class="na">name=</span><span class="s">"width"</span> <span class="na">type=</span><span class="s">"real"</span> <span class="na">default_value=</span><span class="s">"0.3"</span> <span class="nt">/></span>
+      <span class="nt"><argument</span> <span class="na">name=</span><span class="s">"Uint_hbar"</span> <span class="na">type=</span><span class="s">"real"</span> <span class="na">default_value=</span><span class="s">"1.0"</span> <span class="nt">/></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="cm">/* derived constants */</span>
+        <span class="n">Uint_hbar_on16</span> <span class="o">=</span> <span class="n">Uint_hbar</span><span class="o">/</span><span class="mf">16.0</span><span class="p">;</span>
+      <span class="cp">]]></span>
+    <span class="nt"></arguments></span>
+    <span class="nt"><bing</span> <span class="nt">/></span>
+    <span class="nt"><fftw</span> <span class="na">plan=</span><span class="s">"patient"</span> <span class="nt">/></span>
+    <span class="nt"><openmp</span> <span class="nt">/></span>
+  <span class="nt"></features></span>
+
+  <span class="nt"><driver</span> <span class="na">name=</span><span class="s">"distributed-mpi"</span> <span class="nt">/></span>
+
+  <span class="nt"><geometry></span>
+    <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+    <span class="nt"><transverse_dimensions></span>
+      <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"x"</span> <span class="na">lattice=</span><span class="s">"128"</span>  <span class="na">domain=</span><span class="s">"(-6, 6)"</span> <span class="nt">/></span>
+      <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"y"</span> <span class="na">lattice=</span><span class="s">"128"</span>  <span class="na">domain=</span><span class="s">"(-6, 6)"</span> <span class="nt">/></span>
+    <span class="nt"></transverse_dimensions></span>
+  <span class="nt"></geometry></span>
+
+  <span class="nt"><vector</span> <span class="na">name=</span><span class="s">"main"</span> <span class="na">initial_basis=</span><span class="s">"x y"</span> <span class="na">type=</span><span class="s">"complex"</span><span class="nt">></span>
+    <span class="nt"><components></span> W <span class="nt"></components></span>
+    <span class="nt"><initialisation></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">W</span> <span class="o">=</span> <span class="mf">2.0</span><span class="o">/</span><span class="n">M_PI</span> <span class="o">*</span> <span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="mf">2.0</span><span class="o">*</span><span class="p">(</span><span class="n">y</span><span class="o">*</span><span class="n">y</span> <span class="o">+</span> <span class="p">(</span><span class="n">x</span><span class="o">-</span><span class [...]
+      <span class="cp">]]></span>
+    <span class="nt"></initialisation></span>
+  <span class="nt"></vector></span>
+
+  <span class="nt"><vector</span> <span class="na">name=</span><span class="s">"dampConstants"</span> <span class="na">initial_basis=</span><span class="s">"x y"</span> <span class="na">type=</span><span class="s">"real"</span><span class="nt">></span>
+    <span class="nt"><components></span>damping<span class="nt"></components></span>
+    <span class="nt"><initialisation></span>
+      <span class="cp"><![CDATA[</span>
+      <span class="k">if</span> <span class="p">(</span><span class="n">sqrt</span><span class="p">(</span><span class="n">x</span><span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="n">y</span><span class="o">*</span><span class="n">y</span><span class="p">)</span> <span class="o">></span> <span class="n">_max_x</span><span class="o">-</span><span class="n">width</span><span class="p">)</span>
+        <span class="n">damping</span> <span class="o">=</span> <span class="mf">0.0</span><span class="p">;</span>
+      <span class="k">else</span>
+        <span class="n">damping</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">;</span>
+      <span class="cp">]]></span>
+    <span class="nt"></initialisation></span>
+  <span class="nt"></vector></span>
+
+  <span class="nt"><sequence></span>
+    <span class="nt"><integrate</span> <span class="na">algorithm=</span><span class="s">"ARK89"</span> <span class="na">tolerance=</span><span class="s">"1e-7"</span> <span class="na">interval=</span><span class="s">"7.0e-4"</span> <span class="na">steps=</span><span class="s">"100000"</span><span class="nt">></span>
+      <span class="nt"><samples></span>50<span class="nt"></samples></span>
+      <span class="nt"><operators></span>
+        <span class="nt"><operator</span> <span class="na">kind=</span><span class="s">"ex"</span> <span class="na">constant=</span><span class="s">"yes"</span><span class="nt">></span>
+          <span class="nt"><operator_names></span>Lx Ly Lxxx Lxxy Lxyy Lyyy<span class="nt"></operator_names></span>
+          <span class="cp"><![CDATA[</span>
+            <span class="n">Lx</span> <span class="o">=</span> <span class="kc">i</span><span class="o">*</span><span class="n">kx</span><span class="p">;</span>
+            <span class="n">Ly</span> <span class="o">=</span> <span class="kc">i</span><span class="o">*</span><span class="n">ky</span><span class="p">;</span>
+            <span class="n">Lxxx</span> <span class="o">=</span> <span class="o">-</span><span class="kc">i</span><span class="o">*</span><span class="n">kx</span><span class="o">*</span><span class="n">kx</span><span class="o">*</span><span class="n">kx</span><span class="p">;</span>
+            <span class="n">Lxxy</span> <span class="o">=</span> <span class="o">-</span><span class="kc">i</span><span class="o">*</span><span class="n">kx</span><span class="o">*</span><span class="n">kx</span><span class="o">*</span><span class="n">ky</span><span class="p">;</span>
+            <span class="n">Lxyy</span> <span class="o">=</span> <span class="o">-</span><span class="kc">i</span><span class="o">*</span><span class="n">kx</span><span class="o">*</span><span class="n">ky</span><span class="o">*</span><span class="n">ky</span><span class="p">;</span>
+            <span class="n">Lyyy</span> <span class="o">=</span> <span class="o">-</span><span class="kc">i</span><span class="o">*</span><span class="n">ky</span><span class="o">*</span><span class="n">ky</span><span class="o">*</span><span class="n">ky</span><span class="p">;</span>
+          <span class="cp">]]></span>
+        <span class="nt"></operator></span>
+        <span class="nt"><integration_vectors></span>main<span class="nt"></integration_vectors></span>
+        <span class="nt"><dependencies></span>dampConstants<span class="nt"></dependencies></span>
+        <span class="cp"><![CDATA[</span>
+        <span class="nf">real</span> <span class="n">rotation</span> <span class="o">=</span> <span class="n">omega</span> <span class="o">+</span> <span class="n">Uint_hbar</span><span class="o">*</span><span class="p">(</span><span class="o">-</span><span class="mf">1.0</span> <span class="o">+</span> <span class="n">x</span><span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="n">y</span><span class="o">*</span><span class="n">y</span><span class="p">) [...]
+
+        <span class="n">dW_dt</span> <span class="o">=</span> <span class="n">damping</span> <span class="o">*</span> <span class="p">(</span> <span class="n">rotation</span> <span class="o">*</span> <span class="p">(</span><span class="n">x</span><span class="o">*</span><span class="n">Ly</span><span class="p">[</span><span class="n">W</span><span class="p">]</span> <span class="o">-</span> <span class="n">y</span><span class="o">*</span><span class="n">Lx</span><span class="p">[</span> [...]
+                    <span class="o">-</span> <span class="n">Uint_hbar_on16</span><span class="o">*</span><span class="p">(</span> <span class="n">x</span><span class="o">*</span><span class="p">(</span><span class="n">Lxxy</span><span class="p">[</span><span class="n">W</span><span class="p">]</span> <span class="o">+</span> <span class="n">Lyyy</span><span class="p">[</span><span class="n">W</span><span class="p">])</span> <span class="o">-</span> <span class="n">y</span><span class="o [...]
+                <span class="p">);</span>
+        <span class="cp">]]></span>
+      <span class="nt"></operators></span>
+    <span class="nt"></integrate></span>
+  <span class="nt"></sequence></span>
+
+  <span class="nt"><output></span>
+    <span class="nt"><sampling_group</span> <span class="na">basis=</span><span class="s">"x y"</span> <span class="na">initial_sample=</span><span class="s">"yes"</span><span class="nt">></span>
+      <span class="nt"><moments></span>WR WI<span class="nt"></moments></span>
+      <span class="nt"><dependencies></span>main<span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">_SAMPLE_COMPLEX</span><span class="p">(</span><span class="n">W</span><span class="p">);</span>
+      <span class="cp">]]></span>
+    <span class="nt"></sampling_group></span>
+  <span class="nt"></output></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+<p>This example demonstrates two new features of XMDS2.  The first is the use of parallel processing for a deterministic problem.  The FFTW library only allows MPI processing of multidimensional vectors.  For multidimensional simulations, the generated program can be parallelised simply by adding the <tt class="docutils literal"><span class="pre">name="distributed-mpi"</span></tt> argument to the <tt class="docutils literal"><span class="pre"><driver></span></tt> element.</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre>$ xmds2 wigner_argument_mpi.xmds
+xmds2 version 2.1 "Happy Mollusc" (r2680)
+Copyright 2000-2012 Graham Dennis, Joseph Hope, Mattias Johnsson
+                    and the xmds team
+Generating source code...
+... done
+Compiling simulation...
+... done. Type './wigner' to run.
+</pre></div>
+</div>
+<p>To use multiple processors, the final program is then called using the (implementation specific) MPI wrapper:</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre>$ mpirun -np 2 ./wigner
+Planning for (distributed x, y) <span class="nt"><---></span> (distributed ky, kx) transform... done.
+Planning for (distributed x, y) <span class="nt"><---></span> (distributed ky, kx) transform... done.
+Sampled field (for moment group #1) at t = 0.000000e+00
+Current timestep: 5.908361e-06
+Sampled field (for moment group #1) at t = 1.400000e-05
+Current timestep: 4.543131e-06
+
+...
+</pre></div>
+</div>
+<p>The possible acceleration achievable when parallelising a given simulation depends on a great many things including available memory and cache.  As a general rule, it will improve as the simulation size gets larger, but the easiest way to find out is to test.  The optimum speed up is obviously proportional to the number of available processing cores.</p>
+<p>The second new feature in this simulation is the <tt class="docutils literal"><span class="pre"><arguments></span></tt> element in the <tt class="docutils literal"><span class="pre"><features></span></tt> block.  This is a way of specifying global variables with a given type that can then be input at run time.  The variables are specified in a self explanatory way</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><arguments></span>
+  <span class="nt"><argument</span> <span class="na">name=</span><span class="s">"omega"</span> <span class="na">type=</span><span class="s">"real"</span> <span class="na">default_value=</span><span class="s">"0.0"</span> <span class="nt">/></span>
+    ...
+  <span class="nt"><argument</span> <span class="na">name=</span><span class="s">"Uint_hbar"</span> <span class="na">type=</span><span class="s">"real"</span> <span class="na">default_value=</span><span class="s">"1.0"</span> <span class="nt">/></span>
+<span class="nt"></arguments></span>
+</pre></div>
+</div>
+<p>where the “default_value” is used as the valuable of the variable if no arguments are given.  In the absence of the generating script, the program can document its options with the <tt class="docutils literal"><span class="pre">--help</span></tt> argument:</p>
+<div class="highlight-none"><div class="highlight"><pre>$ ./wigner --help
+Usage: wigner --omega <real> --alpha_0 <real> --absorb <real> --width <real> --Uint_hbar <real>
+
+Details:
+Option              Type            Default value
+-o,  --omega        real            0.0
+-a,  --alpha_0      real            3.0
+-b,  --absorb       real            8.0
+-w,  --width        real            0.3
+-U,  --Uint_hbar    real            1.0
+</pre></div>
+</div>
+<p>We can change one or more of these variables’ values in the simulation by passing it at run time.</p>
+<div class="highlight-none"><div class="highlight"><pre>$ mpirun -np 2 ./wigner --omega 0.1 --alpha_0 2.5 --Uint_hbar 0
+Found enlightenment... (Importing wisdom)
+Planning for (distributed x, y) <---> (distributed ky, kx) transform... done.
+Planning for (distributed x, y) <---> (distributed ky, kx) transform... done.
+Sampled field (for moment group #1) at t = 0.000000e+00
+Current timestep: 1.916945e-04
+
+...
+</pre></div>
+</div>
+<p>The values that were used for the variables, whether default or passed in, are stored in the output file (wigner.xsil).</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><info></span>
+Script compiled with XMDS2 version 2.1 "Happy Mollusc" (r2680)
+See http://www.xmds.org for more information.
+
+Variables that can be specified on the command line:
+  Command line argument omega = 1.000000e-01
+  Command line argument alpha_0 = 2.500000e+00
+  Command line argument absorb = 8.000000e+00
+  Command line argument width = 3.000000e-01
+  Command line argument Uint_hbar = 0.000000e+00
+<span class="nt"></info></span>
+</pre></div>
+</div>
+<p>Finally, note the shorthand used in the output group</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="cp"><![CDATA[</span>
+  <span class="n">_SAMPLE_COMPLEX</span><span class="p">(</span><span class="n">W</span><span class="p">);</span>
+<span class="cp">]]></span>
+</pre></div>
+</div>
+<p>which is short for</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="cp"><![CDATA[</span>
+  <span class="n">WR</span> <span class="o">=</span> <span class="n">W</span><span class="p">.</span><span class="n">Re</span><span class="p">();</span>
+  <span class="n">WI</span> <span class="o">=</span> <span class="n">W</span><span class="p">.</span><span class="n">Im</span><span class="p">();</span>
+<span class="cp">]]></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="finding-the-ground-state-of-a-bec-continuous-renormalisation">
+<span id="groundstatebec"></span><h2>Finding the Ground State of a BEC (continuous renormalisation)<a class="headerlink" href="#finding-the-ground-state-of-a-bec-continuous-renormalisation" title="Permalink to this headline">¶</a></h2>
+<p>This simulation solves another partial differential equation, but introduces several powerful new features in XMDS2.  The nominal problem is the calculation of the lowest energy eigenstate of a non-linear Schrödinger equation:</p>
+<div class="math">
+\[\frac{\partial \phi}{\partial t} = i \left[\frac{1}{2}\frac{\partial^2}{\partial y^2} - V(y) - U_{int}|\phi|^2\right]\phi\]</div>
+<p>which can be found by evolving the above equation in imaginary time while keeping the normalisation constant.  This causes eigenstates to exponentially decay at the rate of their eigenvalue, so after a short time only the state with the lowest eigenvalue remains.  The evolution equation is straightforward:</p>
+<div class="math">
+\[\frac{\partial \phi}{\partial t} = \left[\frac{1}{2}\frac{\partial^2}{\partial y^2} - V(y) - U_{int}|\phi|^2\right]\phi\]</div>
+<p>but we will need to use new XMDS2 features to manage the normalisation of the function <span class="math">\(\phi(y,t)\)</span>.  The normalisation for a non-linear Schrödinger equation is given by <span class="math">\(\int dy |\phi(y,t)|^2 = N_{particles}\)</span>, where <span class="math">\(N_{particles}\)</span> is the number of particles described by the wavefunction.</p>
+<p>The code for this simulation can be found in <tt class="docutils literal"><span class="pre">examples/groundstate_workedexamples.xmds</span></tt>:</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+  <span class="nt"><name></span>groundstate<span class="nt"></name></span>
+  <span class="nt"><author></span>Joe Hope<span class="nt"></author></span>
+  <span class="nt"><description></span>
+    Calculate the ground state of the non-linear Schrodinger equation in a harmonic magnetic trap.
+    This is done by evolving it in imaginary time while re-normalising each timestep.
+  <span class="nt"></description></span>
+
+  <span class="nt"><features></span>
+    <span class="nt"><auto_vectorise</span> <span class="nt">/></span>
+    <span class="nt"><benchmark</span> <span class="nt">/></span>
+    <span class="nt"><bing</span> <span class="nt">/></span>
+    <span class="nt"><fftw</span> <span class="na">plan=</span><span class="s">"exhaustive"</span> <span class="nt">/></span>
+    <span class="nt"><globals></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="k">const</span> <span class="nf">real</span> <span class="n">Uint</span> <span class="o">=</span> <span class="mf">2.0</span><span class="p">;</span>
+        <span class="k">const</span> <span class="nf">real</span> <span class="n">Nparticles</span> <span class="o">=</span> <span class="mf">5.0</span><span class="p">;</span>
+      <span class="cp">]]></span>
+    <span class="nt"></globals></span>
+  <span class="nt"></features></span>
+
+  <span class="nt"><geometry></span>
+    <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+    <span class="nt"><transverse_dimensions></span>
+      <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"y"</span> <span class="na">lattice=</span><span class="s">"256"</span>  <span class="na">domain=</span><span class="s">"(-15.0, 15.0)"</span> <span class="nt">/></span>
+    <span class="nt"></transverse_dimensions></span>
+  <span class="nt"></geometry></span>
+
+  <span class="nt"><vector</span> <span class="na">name=</span><span class="s">"potential"</span> <span class="na">initial_basis=</span><span class="s">"y"</span> <span class="na">type=</span><span class="s">"real"</span><span class="nt">></span>
+    <span class="nt"><components></span> V1 <span class="nt"></components></span>
+    <span class="nt"><initialisation></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">V1</span>  <span class="o">=</span> <span class="mf">0.5</span><span class="o">*</span><span class="n">y</span><span class="o">*</span><span class="n">y</span><span class="p">;</span>
+      <span class="cp">]]></span>
+    <span class="nt"></initialisation></span>
+  <span class="nt"></vector></span>
+
+  <span class="nt"><vector</span> <span class="na">name=</span><span class="s">"wavefunction"</span> <span class="na">initial_basis=</span><span class="s">"y"</span> <span class="na">type=</span><span class="s">"complex"</span><span class="nt">></span>
+    <span class="nt"><components></span> phi <span class="nt"></components></span>
+    <span class="nt"><initialisation></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="k">if</span> <span class="p">(</span><span class="n">fabs</span><span class="p">(</span><span class="n">y</span><span class="p">)</span> <span class="o"><</span> <span class="mf">3.0</span><span class="p">)</span> <span class="p">{</span>
+          <span class="n">phi</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">;</span>
+          <span class="c1">// This will be automatically normalised later</span>
+        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
+          <span class="n">phi</span> <span class="o">=</span> <span class="mf">0.0</span><span class="p">;</span>
+        <span class="p">}</span>
+            <span class="cp">]]></span>
+    <span class="nt"></initialisation></span>
+  <span class="nt"></vector></span>
+
+  <span class="nt"><computed_vector</span> <span class="na">name=</span><span class="s">"normalisation"</span> <span class="na">dimensions=</span><span class="s">""</span> <span class="na">type=</span><span class="s">"real"</span><span class="nt">></span>
+    <span class="nt"><components></span> Ncalc <span class="nt"></components></span>
+    <span class="nt"><evaluation></span>
+      <span class="nt"><dependencies</span> <span class="na">basis=</span><span class="s">"y"</span><span class="nt">></span>wavefunction<span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="c1">// Calculate the current normalisation of the wave function.</span>
+        <span class="n">Ncalc</span> <span class="o">=</span> <span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">);</span>
+      <span class="cp">]]></span>
+    <span class="nt"></evaluation></span>
+  <span class="nt"></computed_vector></span>
+
+  <span class="nt"><sequence></span>
+      <span class="nt"><filter></span>
+        <span class="cp"><![CDATA[</span>
+          <span class="n">printf</span><span class="p">(</span><span class="s">"Hello world from a filter segment!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
+        <span class="cp">]]></span>
+      <span class="nt"></filter></span>
+
+    <span class="nt"><filter></span>
+        <span class="nt"><dependencies></span>normalisation wavefunction<span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">phi</span> <span class="o">*=</span> <span class="n">sqrt</span><span class="p">(</span><span class="n">Nparticles</span><span class="o">/</span><span class="n">Ncalc</span><span class="p">);</span>
+      <span class="cp">]]></span>
+    <span class="nt"></filter></span>
+
+    <span class="nt"><integrate</span> <span class="na">algorithm=</span><span class="s">"ARK45"</span> <span class="na">interval=</span><span class="s">"1.0"</span> <span class="na">steps=</span><span class="s">"4000"</span> <span class="na">tolerance=</span><span class="s">"1e-10"</span><span class="nt">></span>
+      <span class="nt"><samples></span>25 4000<span class="nt"></samples></span>
+      <span class="nt"><filters</span> <span class="na">where=</span><span class="s">"step end"</span><span class="nt">></span>
+        <span class="nt"><filter></span>
+          <span class="nt"><dependencies></span>wavefunction normalisation<span class="nt"></dependencies></span>
+          <span class="cp"><![CDATA[</span>
+            <span class="c1">// Correct normalisation of the wavefunction</span>
+            <span class="n">phi</span> <span class="o">*=</span> <span class="n">sqrt</span><span class="p">(</span><span class="n">Nparticles</span><span class="o">/</span><span class="n">Ncalc</span><span class="p">);</span>
+          <span class="cp">]]></span>
+        <span class="nt"></filter></span>
+      <span class="nt"></filters></span>
+      <span class="nt"><operators></span>
+        <span class="nt"><operator</span> <span class="na">kind=</span><span class="s">"ip"</span> <span class="na">constant=</span><span class="s">"yes"</span><span class="nt">></span>
+          <span class="nt"><operator_names></span>T<span class="nt"></operator_names></span>
+          <span class="cp"><![CDATA[</span>
+            <span class="n">T</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.5</span><span class="o">*</span><span class="n">ky</span><span class="o">*</span><span class="n">ky</span><span class="p">;</span>
+          <span class="cp">]]></span>
+        <span class="nt"></operator></span>
+        <span class="nt"><integration_vectors></span>wavefunction<span class="nt"></integration_vectors></span>
+        <span class="nt"><dependencies></span>potential<span class="nt"></dependencies></span>
+        <span class="cp"><![CDATA[</span>
+          <span class="n">dphi_dt</span> <span class="o">=</span> <span class="n">T</span><span class="p">[</span><span class="n">phi</span><span class="p">]</span> <span class="o">-</span> <span class="p">(</span><span class="n">V1</span> <span class="o">+</span> <span class="n">Uint</span><span class="o">*</span><span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">))</span><span class="o">*</span><span class="n">phi</span><span class="p">;</span>
+        <span class="cp">]]></span>
+      <span class="nt"></operators></span>
+    <span class="nt"></integrate></span>
+
+    <span class="nt"><breakpoint</span> <span class="na">filename=</span><span class="s">"groundstate_break.xsil"</span><span class="nt">></span>
+      <span class="nt"><dependencies</span> <span class="na">basis=</span><span class="s">"ky"</span><span class="nt">></span>wavefunction <span class="nt"></dependencies></span>
+    <span class="nt"></breakpoint></span>
+
+  <span class="nt"></sequence></span>
+
+  <span class="nt"><output></span>
+    <span class="nt"><sampling_group</span> <span class="na">basis=</span><span class="s">"y"</span> <span class="na">initial_sample=</span><span class="s">"yes"</span><span class="nt">></span>
+      <span class="nt"><moments></span>norm_dens<span class="nt"></moments></span>
+      <span class="nt"><dependencies></span>wavefunction normalisation<span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">norm_dens</span> <span class="o">=</span> <span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">);</span>
+      <span class="cp">]]></span>
+    <span class="nt"></sampling_group></span>
+
+    <span class="nt"><sampling_group</span> <span class="na">initial_sample=</span><span class="s">"yes"</span><span class="nt">></span>
+      <span class="nt"><moments></span>norm<span class="nt"></moments></span>
+      <span class="nt"><dependencies></span>normalisation<span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">norm</span> <span class="o">=</span> <span class="n">Ncalc</span><span class="p">;</span>
+      <span class="cp">]]></span>
+    <span class="nt"></sampling_group></span>
+  <span class="nt"></output></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+<p>We have used the <tt class="docutils literal"><span class="pre">plan="exhasutive"</span></tt> option in the <tt class="docutils literal"><span class="pre"><fftw></span></tt> element to ensure that the absolute fastest transform method is found.  Because the FFTW package stores the results of its tests (by default in the ~/.xmds/wisdom directory), this option does not cause significant computational overhead, except perhaps on the very first run of a new program.</p>
+<p>This simulation introduces the first example of a very powerful feature in XMDS2: the <tt class="docutils literal"><span class="pre"><computed_vector></span></tt> element.  This has syntax like any other vector, including possible dependencies on other vectors, and an ability to be used in any element that can use vectors.  The difference is that, much like noise vectors, computed vectors are recalculated each time they are required.  This means that a computed vector can never  [...]
+<p>The difference between a computed vector and a stored vector is emphasised by the replacement of the <tt class="docutils literal"><span class="pre"><initialisation></span></tt> element with an <tt class="docutils literal"><span class="pre"><evaluation></span></tt> element.  Apart from the name, they have virtually identical purpose and syntax.</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><computed_vector</span> <span class="na">name=</span><span class="s">"normalisation"</span> <span class="na">dimensions=</span><span class="s">""</span> <span class="na">type=</span><span class="s">"real"</span><span class="nt">></span>
+  <span class="nt"><components></span> Ncalc <span class="nt"></components></span>
+  <span class="nt"><evaluation></span>
+    <span class="nt"><dependencies</span> <span class="na">basis=</span><span class="s">"y"</span><span class="nt">></span>wavefunction<span class="nt"></dependencies></span>
+    <span class="cp"><![CDATA[</span>
+      <span class="c1">// Calculate the current normalisation of the wave function.</span>
+      <span class="n">Ncalc</span> <span class="o">=</span> <span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">);</span>
+    <span class="cp">]]></span>
+  <span class="nt"></evaluation></span>
+<span class="nt"></computed_vector></span>
+</pre></div>
+</div>
+<p>Here, our computed vector has no transverse dimensions and depends on the components of “wavefunction”, so the extra transverse dimensions are integrated out.  This code therefore integrates the square modulus of the field, and returns it in the variable “Ncalc”.  This will be used below to renormalise the “phi” field.  Before we examine that process, we have to introduce the <tt class="docutils literal"><span class="pre"><filter></span></tt>  [...]
+<p>The <tt class="docutils literal"><span class="pre"><filter></span></tt> element can be placed in the <tt class="docutils literal"><span class="pre"><sequence></span></tt> element, or inside <tt class="docutils literal"><span class="pre"><integrate></span></tt> elements as we will see next.  Elements placed in the <tt class="docutils literal"><span class="pre"><sequence></span></tt> element are executed in the order they are found in the .xmds file.  Filter elem [...]
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><filter></span>
+  <span class="cp"><![CDATA[</span>
+    <span class="n">printf</span><span class="p">(</span><span class="s">"Hello world from a filter segment!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
+  <span class="cp">]]></span>
+<span class="nt"></filter></span>
+</pre></div>
+</div>
+<p>This filter block merely prints a string into the output when the generated program is run.  If the <tt class="docutils literal"><span class="pre"><filter></span></tt> element contains dependencies, then the variables defined in those vectors (or computed vectors, or noise vectors) will be available, and the CDATA block will be placed inside loops that run over all the transverse dimensions used by the included vectors.  The second filter block in this example depends on both th [...]
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><filter></span>
+    <span class="nt"><dependencies></span>normalisation wavefunction<span class="nt"></dependencies></span>
+  <span class="cp"><![CDATA[</span>
+    <span class="n">phi</span> <span class="o">*=</span> <span class="n">sqrt</span><span class="p">(</span><span class="n">Nparticles</span><span class="o">/</span><span class="n">Ncalc</span><span class="p">);</span>
+  <span class="cp">]]></span>
+<span class="nt"></filter></span>
+</pre></div>
+</div>
+<p>Since this filter depends on a vector with the transverse dimension “y”, this filter will execute for each point in “y”.  This code multiplies the value of the field “phi” by the factor required to produce a normalised function in the sense that  <span class="math">\(\int dy |\phi(y,t)|^2 = N_{particles}\)</span>.</p>
+<p>The next usage of a <tt class="docutils literal"><span class="pre"><filter></span></tt> element in this program is inside the <tt class="docutils literal"><span class="pre"><integrate></span></tt> element, where all filters are placed inside a <tt class="docutils literal"><span class="pre"><filters></span></tt> element.</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><filters</span> <span class="na">where=</span><span class="s">"step end"</span><span class="nt">></span>
+  <span class="nt"><filter></span>
+    <span class="nt"><dependencies></span>wavefunction normalisation<span class="nt"></dependencies></span>
+    <span class="cp"><![CDATA[</span>
+      <span class="c1">// Correct normalisation of the wavefunction</span>
+      <span class="n">phi</span> <span class="o">*=</span> <span class="n">sqrt</span><span class="p">(</span><span class="n">Nparticles</span><span class="o">/</span><span class="n">Ncalc</span><span class="p">);</span>
+    <span class="cp">]]></span>
+  <span class="nt"></filter></span>
+<span class="nt"></filters></span>
+</pre></div>
+</div>
+<p>Filters placed in an integration block are applied each integration step.  The “where” flag is used to determine whether the filter should be applied directly before or directly after each integration step.  The default value for the where flag is <tt class="docutils literal"><span class="pre">where="step</span> <span class="pre">start"</span></tt>, but in this case we chose “step end” to make sure that the final output was normalised after the last i [...]
+<p>At the end of the sequence element we introduce the <tt class="docutils literal"><span class="pre"><breakpoint></span></tt> element.  This serves two purposes.  The first is a simple matter of convenience.  Often when we manage our input and output from a simulation, we are interested solely in storing the exact state of our integration vectors.  A breakpoint element does exactly that, storing the components of any vectors contained within, taking all the normal options of the < [...]
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><breakpoint</span> <span class="na">filename=</span><span class="s">"groundstate_break.xsil"</span><span class="nt">></span>
+  <span class="nt"><dependencies</span> <span class="na">basis=</span><span class="s">"ky"</span><span class="nt">></span>wavefunction<span class="nt"></dependencies></span>
+<span class="nt"></breakpoint></span>
+</pre></div>
+</div>
+<p>If the filename argument is omitted, the output filenames are numbered sequentially.  Any given <tt class="docutils literal"><span class="pre"><breakpoint></span></tt> element must only depend on vectors with identical dimensions.</p>
+<p>This program begins with a very crude guess to the ground state, but it rapidly converges to the lowest eigenstate.</p>
+<div class="figure align-center">
+<img alt="_images/groundstateU2.png" src="_images/groundstateU2.png" />
+<p class="caption">The shape of the ground state rapidly approaches the lowest eigenstate.  For weak nonlinearities, it is nearly Gaussian.</p>
+</div>
+<div class="figure align-center">
+<img alt="_images/groundstateU20.png" src="_images/groundstateU20.png" />
+<p class="caption">When the nonlinear term is larger (<span class="math">\(U=20\)</span>), the ground state is wider and more parabolic.</p>
+</div>
+</div>
+<div class="section" id="finding-the-ground-state-of-a-bec-again">
+<span id="hermitegaussgroundstatebec"></span><h2>Finding the Ground State of a BEC again<a class="headerlink" href="#finding-the-ground-state-of-a-bec-again" title="Permalink to this headline">¶</a></h2>
+<p>Here we repeat the same simulation as in the <a class="reference internal" href="#groundstatebec"><em>Finding the Ground State of a BEC (continuous renormalisation)</em></a> example, using a different transform basis.  While spectral methods are very effective, and Fourier transforms are typically very efficient due to the Fast Fourier transform algorithm, it is often desirable to describe nonlocal evolution in bases other than the Fourier basis.  The previous calculation was the Schr [...]
+<div class="math">
+\[\left[-\frac{\hbar}{2 m}\frac{\partial^2}{\partial x^2} + \frac{1}{2}\omega^2 x^2\right]\phi_n(x) = E_n \phi_n(x)\]</div>
+<p>where</p>
+<div class="math">
+\[\phi_n(x,t) = \sqrt{\frac{1}{2^n n!}} \left(\frac{m \omega}{\hbar \pi}\right)^\frac{1}{4} e^{-\frac{m \omega x^2}{2\hbar}} H_n\left(\sqrt{\frac{m \omega}{\hbar}x}\right),\;\;\;\;\;\;E_n = \left(n+\frac{1}{2}\right) \omega\]</div>
+<p>where <span class="math">\(H_n(u)\)</span> are the physicist’s version of the Hermite polynomials.  Rather than describing the derivatives as diagonal terms in Fourier space, we therefore have the option of describing the entire <span class="math">\(-\frac{\hbar}{2 m}\frac{\partial^2}{\partial x^2} + \frac{1}{2}\omega^2 x^2\)</span> term as a diagonal term in the hermite-Gaussian basis.  Here is an XMDS2 simulation that performs the integration in this basis. The following is a  [...]
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+  <span class="nt"><name></span>hermitegauss_groundstate<span class="nt"></name></span>
+  <span class="nt"><author></span>Graham Dennis<span class="nt"></author></span>
+  <span class="nt"><description></span>
+    Solve for the groundstate of the Gross-Pitaevskii equation using the hermite-Gauss basis.
+  <span class="nt"></description></span>
+
+  <span class="nt"><features></span>
+    <span class="nt"><benchmark</span> <span class="nt">/></span>
+    <span class="nt"><bing</span> <span class="nt">/></span>
+    <span class="nt"><validation</span> <span class="na">kind=</span><span class="s">"run-time"</span> <span class="nt">/></span>
+    <span class="nt"><globals></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="k">const</span> <span class="nf">real</span> <span class="n">omegaz</span> <span class="o">=</span> <span class="mi">2</span><span class="o">*</span><span class="n">M_PI</span><span class="o">*</span><span class="mi">20</span><span class="p">;</span>
+        <span class="k">const</span> <span class="nf">real</span> <span class="n">omegarho</span> <span class="o">=</span> <span class="mi">2</span><span class="o">*</span><span class="n">M_PI</span><span class="o">*</span><span class="mi">200</span><span class="p">;</span>
+        <span class="k">const</span> <span class="nf">real</span> <span class="n">hbar</span> <span class="o">=</span> <span class="mf">1.05457148e-34</span><span class="p">;</span>
+        <span class="k">const</span> <span class="nf">real</span> <span class="n">M</span> <span class="o">=</span> <span class="mf">1.409539200000000e-25</span><span class="p">;</span>
+        <span class="k">const</span> <span class="nf">real</span> <span class="n">g</span> <span class="o">=</span> <span class="mf">9.8</span><span class="p">;</span>
+        <span class="k">const</span> <span class="nf">real</span> <span class="n">scatteringLength</span> <span class="o">=</span> <span class="mf">5.57e-9</span><span class="p">;</span>
+        <span class="k">const</span> <span class="nf">real</span> <span class="n">transverseLength</span> <span class="o">=</span> <span class="mf">1e-5</span><span class="p">;</span>
+        <span class="k">const</span> <span class="nf">real</span> <span class="n">Uint</span> <span class="o">=</span> <span class="mf">4.0</span><span class="o">*</span><span class="n">M_PI</span><span class="o">*</span><span class="n">hbar</span><span class="o">*</span><span class="n">hbar</span><span class="o">*</span><span class="n">scatteringLength</span><span class="o">/</span><span class="n">M</span><span class="o">/</span><span class="n">transverseLength</span><span class="o">/</ [...]
+        <span class="k">const</span> <span class="nf">real</span> <span class="n">Nparticles</span> <span class="o">=</span> <span class="mf">5.0e5</span><span class="p">;</span>
+
+        <span class="cm">/* offset constants */</span>
+        <span class="k">const</span> <span class="nf">real</span> <span class="n">EnergyOffset</span> <span class="o">=</span> <span class="mf">0.3</span><span class="o">*</span><span class="n">pow</span><span class="p">(</span><span class="n">pow</span><span class="p">(</span><span class="mf">3.0</span><span class="o">*</span><span class="n">Nparticles</span><span class="o">/</span><span class="mi">4</span><span class="o">*</span><span class="n">omegarho</span><span class="o">*</span><s [...]
+      <span class="cp">]]></span>
+    <span class="nt"></globals></span>
+  <span class="nt"></features></span>
+
+  <span class="nt"><geometry></span>
+    <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+    <span class="nt"><transverse_dimensions></span>
+      <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"x"</span> <span class="na">lattice=</span><span class="s">"100"</span> <span class="na">length_scale=</span><span class="s">"sqrt(hbar/(M*omegarho))"</span> <span class="na">transform=</span><span class="s">"hermite-gauss"</span> <span class="nt">/></span>
+    <span class="nt"></transverse_dimensions></span>
+  <span class="nt"></geometry></span>
+
+  <span class="nt"><vector</span> <span class="na">name=</span><span class="s">"wavefunction"</span> <span class="na">initial_basis=</span><span class="s">"x"</span> <span class="na">type=</span><span class="s">"complex"</span><span class="nt">></span>
+    <span class="nt"><components></span> phi <span class="nt"></components></span>
+    <span class="nt"><initialisation></span>
+      <span class="cp"><![CDATA[</span>
+      <span class="n">phi</span> <span class="o">=</span> <span class="n">sqrt</span><span class="p">(</span><span class="n">Nparticles</span><span class="p">)</span> <span class="o">*</span> <span class="n">pow</span><span class="p">(</span><span class="n">M</span><span class="o">*</span><span class="n">omegarho</span><span class="o">/</span><span class="p">(</span><span class="n">hbar</span><span class="o">*</span><span class="n">M_PI</span><span class="p">),</span> <span class="mf">0. [...]
+      <span class="cp">]]></span>
+    <span class="nt"></initialisation></span>
+  <span class="nt"></vector></span>
+
+  <span class="nt"><computed_vector</span> <span class="na">name=</span><span class="s">"normalisation"</span> <span class="na">dimensions=</span><span class="s">""</span> <span class="na">type=</span><span class="s">"real"</span><span class="nt">></span>
+    <span class="nt"><components></span> Ncalc <span class="nt"></components></span>
+    <span class="nt"><evaluation></span>
+      <span class="nt"><dependencies</span> <span class="na">basis=</span><span class="s">"x"</span><span class="nt">></span>wavefunction<span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="c1">// Calculate the current normalisation of the wave function.</span>
+        <span class="n">Ncalc</span> <span class="o">=</span> <span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">);</span>
+      <span class="cp">]]></span>
+    <span class="nt"></evaluation></span>
+  <span class="nt"></computed_vector></span>
+
+  <span class="nt"><sequence></span>
+    <span class="nt"><integrate</span> <span class="na">algorithm=</span><span class="s">"ARK45"</span> <span class="na">interval=</span><span class="s">"1.0e-2"</span> <span class="na">steps=</span><span class="s">"4000"</span>  <span class="na">tolerance=</span><span class="s">"1e-10"</span><span class="nt">></span>
+      <span class="nt"><samples></span>100 100<span class="nt"></samples></span>
+      <span class="nt"><filters></span>
+        <span class="nt"><filter></span>
+          <span class="nt"><dependencies></span>wavefunction normalisation<span class="nt"></dependencies></span>
+          <span class="cp"><![CDATA[</span>
+            <span class="c1">// Correct normalisation of the wavefunction</span>
+            <span class="n">phi</span> <span class="o">*=</span> <span class="n">sqrt</span><span class="p">(</span><span class="n">Nparticles</span><span class="o">/</span><span class="n">Ncalc</span><span class="p">);</span>
+          <span class="cp">]]></span>
+        <span class="nt"></filter></span>
+      <span class="nt"></filters></span>
+      <span class="nt"><operators></span>
+        <span class="nt"><operator</span> <span class="na">kind=</span><span class="s">"ip"</span> <span class="na">constant=</span><span class="s">"yes"</span> <span class="na">type=</span><span class="s">"real"</span><span class="nt">></span>
+          <span class="nt"><operator_names></span>L<span class="nt"></operator_names></span>
+          <span class="cp"><![CDATA[</span>
+            <span class="n">L</span> <span class="o">=</span> <span class="n">EnergyOffset</span><span class="o">/</span><span class="n">hbar</span> <span class="o">-</span> <span class="p">(</span><span class="n">nx</span> <span class="o">+</span> <span class="mf">0.5</span><span class="p">)</span><span class="o">*</span><span class="n">omegarho</span><span class="p">;</span>
+          <span class="cp">]]></span>
+        <span class="nt"></operator></span>
+        <span class="nt"><integration_vectors></span>wavefunction<span class="nt"></integration_vectors></span>
+        <span class="cp"><![CDATA[</span>
+          <span class="n">dphi_dt</span> <span class="o">=</span> <span class="n">L</span><span class="p">[</span><span class="n">phi</span><span class="p">]</span> <span class="o">-</span> <span class="n">Uint</span><span class="o">/</span><span class="n">hbar</span><span class="o">*</span><span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">)</span><span class="o">*</span><span class="n">phi</span><span class="p">;</span>
+        <span class="cp">]]></span>
+      <span class="nt"></operators></span>
+    <span class="nt"></integrate></span>
+
+    <span class="nt"><filter></span>
+        <span class="nt"><dependencies></span>normalisation wavefunction<span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">phi</span> <span class="o">*=</span> <span class="n">sqrt</span><span class="p">(</span><span class="n">Nparticles</span><span class="o">/</span><span class="n">Ncalc</span><span class="p">);</span>
+      <span class="cp">]]></span>
+    <span class="nt"></filter></span>
+
+    <span class="nt"><breakpoint</span> <span class="na">filename=</span><span class="s">"hermitegauss_groundstate_break.xsil"</span> <span class="na">format=</span><span class="s">"ascii"</span><span class="nt">></span>
+      <span class="nt"><dependencies</span> <span class="na">basis=</span><span class="s">"nx"</span><span class="nt">></span>wavefunction<span class="nt"></dependencies></span>
+    <span class="nt"></breakpoint></span>
+  <span class="nt"></sequence></span>
+
+  <span class="nt"><output></span>
+    <span class="nt"><sampling_group</span> <span class="na">basis=</span><span class="s">"x"</span> <span class="na">initial_sample=</span><span class="s">"yes"</span><span class="nt">></span>
+      <span class="nt"><moments></span>dens<span class="nt"></moments></span>
+      <span class="nt"><dependencies></span>wavefunction<span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">dens</span> <span class="o">=</span> <span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">);</span>
+      <span class="cp">]]></span>
+    <span class="nt"></sampling_group></span>
+    <span class="nt"><sampling_group</span> <span class="na">basis=</span><span class="s">"kx"</span> <span class="na">initial_sample=</span><span class="s">"yes"</span><span class="nt">></span>
+      <span class="nt"><moments></span>dens<span class="nt"></moments></span>
+      <span class="nt"><dependencies></span>wavefunction<span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">dens</span> <span class="o">=</span> <span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">);</span>
+      <span class="cp">]]></span>
+    <span class="nt"></sampling_group></span>
+  <span class="nt"></output></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+<p>The major difference in this simulation code, aside from the switch back from dimensionless units, is the new transverse dimension type in the <tt class="docutils literal"><span class="pre"><geometry></span></tt> element.</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"x"</span> <span class="na">lattice=</span><span class="s">"100"</span> <span class="na">length_scale=</span><span class="s">"sqrt(hbar/(M*omegarho))"</span> <span class="na">transform=</span><span class="s">"hermite-gauss"</span> <span class="nt">/></span>
+</pre></div>
+</div>
+<p>We have explicitly defined the “transform” option, which by defaults expects the Fourier transform.  The <tt class="docutils literal"><span class="pre">transform="hermite-gauss"</span></tt> option requires the ‘mpmath’ package installed, just as Fourier transforms require the FFTW package to be installed.  The “lattice” option details the number of hermite-Gaussian eigenstates to include, and automatically starts from the zeroth order poly [...]
+<p>The <tt class="docutils literal"><span class="pre">length_scale="sqrt(hbar/(M*omegarho))"</span></tt> option requires a real number, but since this script defines it in terms of variables, XMDS2 is unable to verify that the resulting function is real-valued at the time of generating the code.  XMDS2 will therefore fail to compile this program without the feature:</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><validation</span> <span class="na">kind=</span><span class="s">"run-time"</span> <span class="nt">/></span>
+</pre></div>
+</div>
+<p>which disables many of these checks at the time of writing the C-code.</p>
+</div>
+<div class="section" id="multi-component-schrodinger-equation">
+<span id="dmultistatese"></span><h2>Multi-component Schrödinger equation<a class="headerlink" href="#multi-component-schrodinger-equation" title="Permalink to this headline">¶</a></h2>
+<p>This example demonstrates a simple method for doing matrix calculations in XMDS2.  We are solving the multi-component PDE</p>
+<div class="math">
+\[\frac{\partial \phi_j(x,y)}{\partial t} = \frac{i}{2}\left(\frac{\partial^2}{\partial x^2}+\frac{\partial^2}{\partial y^2}\right)\phi_j(x,y) - i U(x,y) \sum_k V_{j k}\phi_k(x,y)\]</div>
+<p>where the last term is more commonly written as a matrix multiplication.  Writing this term out explicitly is feasible for a small number of components, but when the number of components becomes large, or perhaps <span class="math">\(V_{j k}\)</span> should be precomputed for efficiency reasons, it is useful to be able to perform this sum over the integer dimensions automatically.  This example show how this can be done naturally using a computed vector.  The XMDS2 script is as follows:</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><simulation</span> <span class="na">xmds-version=</span><span class="s">"2"</span><span class="nt">></span>
+  <span class="nt"><name></span>2DMSse<span class="nt"></name></span>
+
+  <span class="nt"><author></span>Joe Hope<span class="nt"></author></span>
+  <span class="nt"><description></span>
+    Schroedinger equation for multiple internal states in two spatial dimensions.
+  <span class="nt"></description></span>
+
+  <span class="nt"><features></span>
+      <span class="nt"><benchmark</span> <span class="nt">/></span>
+      <span class="nt"><bing</span> <span class="nt">/></span>
+      <span class="nt"><fftw</span> <span class="na">plan=</span><span class="s">"patient"</span> <span class="nt">/></span>
+      <span class="nt"><openmp</span> <span class="nt">/></span>
+      <span class="nt"><auto_vectorise</span> <span class="nt">/></span>
+     <span class="nt"></features></span>
+
+  <span class="nt"><geometry></span>
+      <span class="nt"><propagation_dimension></span> t <span class="nt"></propagation_dimension></span>
+      <span class="nt"><transverse_dimensions></span>
+          <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"x"</span> <span class="na">lattice=</span><span class="s">"32"</span>  <span class="na">domain=</span><span class="s">"(-6, 6)"</span> <span class="nt">/></span>
+          <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"y"</span> <span class="na">lattice=</span><span class="s">"32"</span>  <span class="na">domain=</span><span class="s">"(-6, 6)"</span> <span class="nt">/></span>
+          <span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"j"</span> <span class="na">type=</span><span class="s">"integer"</span> <span class="na">lattice=</span><span class="s">"2"</span> <span class="na">domain=</span><span class="s">"(0,1)"</span> <span class="na">aliases=</span><span class="s">"k"</span><span class="nt">/></span>
+      <span class="nt"></transverse_dimensions></span>
+   <span class="nt"></geometry></span>
+
+  <span class="nt"><vector</span> <span class="na">name=</span><span class="s">"wavefunction"</span> <span class="na">type=</span><span class="s">"complex"</span> <span class="na">dimensions=</span><span class="s">"x y j"</span><span class="nt">></span>
+    <span class="nt"><components></span> phi <span class="nt"></components></span>
+    <span class="nt"><initialisation></span>
+      <span class="cp"><![CDATA[</span>
+      <span class="n">phi</span> <span class="o">=</span> <span class="n">j</span><span class="o">*</span><span class="n">sqrt</span><span class="p">(</span><span class="mi">2</span><span class="o">/</span><span class="n">sqrt</span><span class="p">(</span><span class="n">M_PI</span><span class="o">/</span><span class="mi">2</span><span class="p">))</span><span class="o">*</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="p">(</span><span class= [...]
+      <span class="cp">]]></span>
+    <span class="nt"></initialisation></span>
+  <span class="nt"></vector></span>
+
+  <span class="nt"><vector</span> <span class="na">name=</span><span class="s">"spatialInteraction"</span> <span class="na">type=</span><span class="s">"real"</span> <span class="na">dimensions=</span><span class="s">"x y"</span><span class="nt">></span>
+    <span class="nt"><components></span> U <span class="nt"></components></span>
+    <span class="nt"><initialisation></span>
+      <span class="cp"><![CDATA[</span>
+      <span class="n">U</span><span class="o">=</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="p">(</span><span class="n">x</span><span class="o">*</span><span class="n">x</span><span class="o">+</span><span class="n">y</span><span class="o">*</span><span class="n">y</span><span class="p">)</span><span class="o">/</span><span class="mi">4</span><span class="p">);</span>
+      <span class="cp">]]></span>
+    <span class="nt"></initialisation></span>
+  <span class="nt"></vector></span>
+
+  <span class="nt"><vector</span> <span class="na">name=</span><span class="s">"internalInteraction"</span> <span class="na">type=</span><span class="s">"real"</span> <span class="na">dimensions=</span><span class="s">"j k"</span><span class="nt">></span>
+    <span class="nt"><components></span> V <span class="nt"></components></span>
+    <span class="nt"><initialisation></span>
+      <span class="cp"><![CDATA[</span>
+      <span class="n">V</span><span class="o">=</span><span class="mi">3</span><span class="o">*</span><span class="p">(</span><span class="n">j</span><span class="o">*</span><span class="p">(</span><span class="mi">1</span><span class="o">-</span><span class="n">k</span><span class="p">)</span><span class="o">+</span><span class="p">(</span><span class="mi">1</span><span class="o">-</span><span class="n">j</span><span class="p">)</span><span class="o">*</span><span class="n">k</span><sp [...]
+      <span class="cp">]]></span>
+    <span class="nt"></initialisation></span>
+  <span class="nt"></vector></span>
+
+  <span class="nt"><computed_vector</span> <span class="na">name=</span><span class="s">"coupling"</span> <span class="na">dimensions=</span><span class="s">"x y j"</span> <span class="na">type=</span><span class="s">"complex"</span><span class="nt">></span>
+    <span class="nt"><components></span>
+      VPhi
+    <span class="nt"></components></span>
+    <span class="nt"><evaluation></span>
+      <span class="nt"><dependencies</span> <span class="na">basis=</span><span class="s">"x y j k"</span><span class="nt">></span>internalInteraction wavefunction<span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="c1">// Calculate the current normalisation of the wave function.</span>
+        <span class="n">VPhi</span> <span class="o">=</span> <span class="n">V</span><span class="o">*</span><span class="n">phi</span><span class="p">(</span><span class="n">j</span> <span class="o">=></span> <span class="n">k</span><span class="p">);</span>
+      <span class="cp">]]></span>
+    <span class="nt"></evaluation></span>
+  <span class="nt"></computed_vector></span>
+
+  <span class="nt"><sequence></span>
+    <span class="nt"><integrate</span> <span class="na">algorithm=</span><span class="s">"ARK45"</span> <span class="na">interval=</span><span class="s">"2.0"</span> <span class="na">tolerance=</span><span class="s">"1e-7"</span><span class="nt">></span>
+      <span class="nt"><samples></span>20 100<span class="nt"></samples></span>
+      <span class="nt"><operators></span>
+        <span class="nt"><integration_vectors></span>wavefunction<span class="nt"></integration_vectors></span>
+        <span class="nt"><operator</span> <span class="na">kind=</span><span class="s">"ex"</span> <span class="na">constant=</span><span class="s">"yes"</span><span class="nt">></span>
+          <span class="nt"><operator_names></span>Ltt<span class="nt"></operator_names></span>
+          <span class="cp"><![CDATA[</span>
+            <span class="n">Ltt</span> <span class="o">=</span> <span class="o">-</span><span class="kc">i</span><span class="o">*</span><span class="p">(</span><span class="n">kx</span><span class="o">*</span><span class="n">kx</span><span class="o">+</span><span class="n">ky</span><span class="o">*</span><span class="n">ky</span><span class="p">)</span><span class="o">*</span><span class="mf">0.5</span><span class="p">;</span>
+          <span class="cp">]]></span>
+        <span class="nt"></operator></span>
+        <span class="cp"><![CDATA[</span>
+        <span class="n">dphi_dt</span> <span class="o">=</span> <span class="n">Ltt</span><span class="p">[</span><span class="n">phi</span><span class="p">]</span> <span class="o">-</span><span class="kc">i</span><span class="o">*</span><span class="n">U</span><span class="o">*</span><span class="n">VPhi</span><span class="p">;</span>
+        <span class="cp">]]></span>
+        <span class="nt"><dependencies></span>spatialInteraction coupling<span class="nt"></dependencies></span>
+      <span class="nt"></operators></span>
+    <span class="nt"></integrate></span>
+  <span class="nt"></sequence></span>
+
+  <span class="nt"><output></span>
+    <span class="nt"><sampling_group</span> <span class="na">basis=</span><span class="s">"x y j"</span> <span class="na">initial_sample=</span><span class="s">"yes"</span><span class="nt">></span>
+      <span class="nt"><moments></span>density<span class="nt"></moments></span>
+      <span class="nt"><dependencies></span>wavefunction<span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">density</span> <span class="o">=</span> <span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">);</span>
+      <span class="cp">]]></span>
+    <span class="nt"></sampling_group></span>
+    <span class="nt"><sampling_group</span> <span class="na">basis=</span><span class="s">"x(0) y(0) j"</span> <span class="na">initial_sample=</span><span class="s">"yes"</span><span class="nt">></span>
+      <span class="nt"><moments></span>normalisation<span class="nt"></moments></span>
+      <span class="nt"><dependencies></span>wavefunction<span class="nt"></dependencies></span>
+      <span class="cp"><![CDATA[</span>
+        <span class="n">normalisation</span> <span class="o">=</span> <span class="nf">mod2</span><span class="p">(</span><span class="n">phi</span><span class="p">);</span>
+      <span class="cp">]]></span>
+    <span class="nt"></sampling_group></span>
+  <span class="nt"></output></span>
+<span class="nt"></simulation></span>
+</pre></div>
+</div>
+<p>The only truly new feature in this script is the “aliases” option on a dimension.  The integer-valued dimension in this script indexes the components of the PDE (in this case only two).  The  <span class="math">\(V_{j k}\)</span> term is required to be a square array of dimension of this number of components.  If we wrote the k-index of <span class="math">\(V_{j k}\)</span> using a separate <tt class="docutils literal"><span class="pre"><dimension></span></tt> elemen [...]
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><dimension</span> <span class="na">name=</span><span class="s">"j"</span> <span class="na">type=</span><span class="s">"integer"</span> <span class="na">lattice=</span><span class="s">"2"</span> <span class="na">domain=</span><span class="s">"(0,1)"</span> <span class="na">aliases=</span><span class="s">"k"</span><span class="nt">/></span>
+</pre></div>
+</div>
+<p>This means that we can use the index “k”, which will have exactly the same properties as the “j” index.  This is used to define the “V” function in the “internalInteraction” vector.  Now, just as we use a computed vector to perform an integration over our fields, we use a computed vector to calculate the sum.</p>
+<div class="highlight-xpdeint"><div class="highlight"><pre><span class="nt"><computed_vector</span> <span class="na">name=</span><span class="s">"coupling"</span> <span class="na">dimensions=</span><span class="s">"x y j"</span> <span class="na">type=</span><span class="s">"complex"</span><span class="nt">></span>
+  <span class="nt"><components></span>
+    VPhi
+  <span class="nt"></components></span>
+  <span class="nt"><evaluation></span>
+    <span class="nt"><dependencies</span> <span class="na">basis=</span><span class="s">"x y j k"</span><span class="nt">></span>internalInteraction wavefunction<span class="nt"></dependencies></span>
+    <span class="cp"><![CDATA[</span>
+      <span class="c1">// Calculate the current normalisation of the wave function.</span>
+      <span class="n">VPhi</span> <span class="o">=</span> <span class="n">V</span><span class="o">*</span><span class="n">phi</span><span class="p">(</span><span class="n">j</span> <span class="o">=></span> <span class="n">k</span><span class="p">);</span>
+    <span class="cp">]]></span>
+  <span class="nt"></evaluation></span>
+<span class="nt"></computed_vector></span>
+</pre></div>
+</div>
+<p>Since the output dimensions of the computed vector do not include a “k” index, this index is integrated.  The volume element for this summation is the spacing between neighbouring values of “j”, and since this spacing is one, this integration is just a sum over k, as required.</p>
+<p>By this point, we have introduced most of the important features in XMDS2.  More details on other transform options and rarely used features can be found in the <a class="reference internal" href="advanced_topics.html#advancedtopics"><em>Advanced Topics</em></a> section.</p>
+</div>
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="index.html">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+  <h3><a href="index.html">Table Of Contents</a></h3>
+  <ul>
+<li><a class="reference internal" href="#">Worked Examples</a><ul>
+<li><a class="reference internal" href="#the-nonlinear-schrodinger-equation">The nonlinear Schrödinger equation</a></li>
+<li><a class="reference internal" href="#kubo-oscillator">Kubo Oscillator</a></li>
+<li><a class="reference internal" href="#fibre-noise">Fibre Noise</a></li>
+<li><a class="reference internal" href="#integer-dimensions">Integer Dimensions</a></li>
+<li><a class="reference internal" href="#wigner-function">Wigner Function</a></li>
+<li><a class="reference internal" href="#finding-the-ground-state-of-a-bec-continuous-renormalisation">Finding the Ground State of a BEC (continuous renormalisation)</a></li>
+<li><a class="reference internal" href="#finding-the-ground-state-of-a-bec-again">Finding the Ground State of a BEC again</a></li>
+<li><a class="reference internal" href="#multi-component-schrodinger-equation">Multi-component Schrödinger equation</a></li>
+</ul>
+</li>
+</ul>
+
+<div id="searchbox" style="display: none">
+  <h3>Quick search</h3>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" />
+      <input type="submit" value="Go" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    <p class="searchtip" style="font-size: 90%">
+    Enter search terms or a module, class or function name.
+    </p>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/documentation/xsil2graphics2.html b/documentation/xsil2graphics2.html
new file mode 100644
index 0000000..30ba19d
--- /dev/null
+++ b/documentation/xsil2graphics2.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>xsil2graphics2 — XMDS2 2.1.4 documentation</title>
+    
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '2.1.4',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML,http://www.xmds.org/_static/mathjax-use-tex-fonts.js"></script>
+    <link rel="shortcut icon" href="_static/xmds_favicon.ico"/>
+    <link rel="top" title="XMDS2 2.1.4 documentation" href="index.html" /> 
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>  
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+            
+  <div class="section" id="xsil2graphics2">
+<span id="id1"></span><h1>xsil2graphics2<a class="headerlink" href="#xsil2graphics2" title="Permalink to this headline">¶</a></h1>
+<p><strong>xsil2graphics2</strong> is a way of converting ”.xsil” files to formats that other programs can read.  The syntax is described in the <a class="reference internal" href="tutorial.html#quickstarttutorial"><em>Quickstart Tutorial</em></a>, and by using the <tt class="docutils literal"><span class="pre">xsil2graphics2</span> <span class="pre">--help</span></tt> option.  It currently can covert any output format for use by Mathematica.</p>
+<p>We recommend HDF5 format instead of the binary format for output and input, as many visualisation tools can already read/write to this format directly.</p>
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <p class="logo"><a href="index.html">
+              <img class="logo" src="_static/xmds_logo.png" alt="Logo"/>
+            </a></p>
+<div id="searchbox" style="display: none">
+  <h3>Quick search</h3>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" />
+      <input type="submit" value="Go" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    <p class="searchtip" style="font-size: 90%">
+    Enter search terms or a module, class or function name.
+    </p>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li><a href="index.html">XMDS2 2.1.4 documentation</a> »</li> 
+      </ul>
+    </div>
+    <div class="footer">
+        © Copyright 2008-2013, Graham Dennis, Joe Hope and Mattias Johnsson.
+      Last updated on Sep 28, 2013.
+      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2b2.
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/examples/2DMultistateSE.xmds b/examples/2DMultistateSE.xmds
new file mode 100644
index 0000000..627a6d6
--- /dev/null
+++ b/examples/2DMultistateSE.xmds
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>TwoDMSse</name>
+
+  <author>Joe Hope</author>
+  <description>
+    Schroedinger equation for multiple internal states in two spatial dimensions.
+  </description>
+
+  <features>
+      <benchmark />
+      <bing />
+      <fftw plan="patient" />
+      <auto_vectorise />
+     </features>
+
+  <geometry>
+      <propagation_dimension> t </propagation_dimension>
+      <transverse_dimensions>
+          <dimension name="x" lattice="32"  domain="(-6, 6)" />
+          <dimension name="y" lattice="32"  domain="(-6, 6)" />
+          <dimension name="j" type="integer" lattice="2" domain="(0,1)" aliases="k"/>
+      </transverse_dimensions>
+   </geometry>
+
+  <vector name="wavefunction" type="complex" dimensions="x y j">
+    <components> phi </components>
+    <initialisation>
+      <![CDATA[
+      phi = j*sqrt(2/sqrt(M_PI/2))*exp(-(x*x+y*y)/4)*exp(i*0.1*x);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <vector name="spatialInteraction" type="real" dimensions="x y">
+    <components> U </components>
+    <initialisation>
+      <![CDATA[
+      U=exp(-(x*x+y*y)/4);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <vector name="internalInteraction" type="real" dimensions="j k">
+    <components> V </components>
+    <initialisation>
+      <![CDATA[
+      V=3*(j*(1-k)+(1-j)*k);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <computed_vector name="coupling" dimensions="x y j" type="complex">
+    <components>
+      VPhi
+    </components>
+    <evaluation>
+      <dependencies basis="x y j k">internalInteraction wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        VPhi = V*phi(j => k);
+      ]]>
+    </evaluation>
+  </computed_vector>
+
+  <sequence>
+    <integrate algorithm="ARK45" interval="2.0" tolerance="1e-7">
+      <samples>20 100</samples>
+      <operators>
+        <integration_vectors>wavefunction</integration_vectors>
+        <operator kind="ex" constant="yes">
+          <operator_names>Ltt</operator_names>
+          <![CDATA[
+            Ltt = -i*(kx*kx+ky*ky)*0.5;
+          ]]>
+        </operator>
+        <![CDATA[
+        dphi_dt = Ltt[phi] -i*U*VPhi;
+        ]]>
+        <dependencies>spatialInteraction coupling</dependencies>
+      </operators>
+    </integrate>
+  </sequence>
+
+  <output>
+    <sampling_group basis="x y j" initial_sample="yes">
+        <moments>density</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          density = mod2(phi);
+        ]]>
+    </sampling_group>
+    <sampling_group basis="x(0) y(0) j" initial_sample="yes">
+        <moments>normalisation</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          normalisation = mod2(phi);
+        ]]>
+    </sampling_group>
+  </output>
+</simulation>
+
+
diff --git a/examples/NLProjection.xmds b/examples/NLProjection.xmds
new file mode 100644
index 0000000..71d3288
--- /dev/null
+++ b/examples/NLProjection.xmds
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>nlprojection</name>
+  <author>Graham Dennis</author>
+  <description>
+    Project |psi|^2 psi where psi is the harmonic oscillator groundstate
+    onto the harmonic oscillator basis for a three-dimensional trap.
+  </description>
+  
+  <!-- 'features' describes various optional extras that can be plugged into the simulation -->
+  <features>
+    <auto_vectorise />
+    <benchmark />
+  </features>
+  
+  <!-- This is where the geometry of the simulation is defined -->
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="7" spectral_lattice="3" length_scale="1.0" transform="hermite-gauss" />
+      <dimension name="y" lattice="7" spectral_lattice="3" length_scale="1.0" transform="hermite-gauss" />
+      <dimension name="z" lattice="7" spectral_lattice="3" length_scale="1.0" transform="hermite-gauss" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <!-- A vector is a set of variables that can be evolved. -->
+  <vector name="wavefunction" initial_basis="nx ny nz" type="real">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+      if (nx == 0 && ny == 0 && nz == 0)
+        phi = 1.0;
+      else
+        phi = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <!-- This is a dodgy method of evaluating the nonlinear term. 
+       It uses the two-field quadrature, and so the result isn't quite right.
+  -->
+  <computed_vector name="nlterm" dimensions="x y z" type="real">
+    <components>
+      nl
+    </components>
+    <evaluation>
+      <dependencies basis="x y z">wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the nonlinear term.
+        nl = mod2(phi)*phi;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <!-- 
+    This is the correct method to evaluate the nonlinear term.
+    This uses the four-field quadrature, and so is evaluated to high precision
+    even with comparatively few points. The correct result for
+    nl(nx => 0,ny => 0, nz => 0) is 6.34936359e-2
+   -->
+  <computed_vector name="nlterm_4f" dimensions="x y z" type="real">
+    <components>
+      nl_4f
+    </components>
+    <evaluation>
+      <dependencies basis="x_4f y_4f z_4f">wavefunction</dependencies>
+      <![CDATA[
+        // Compute nonlinear term
+        nl_4f = mod2(phi) * phi;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <!-- This is where the evolution of the simulation would go.
+         An 'integrate' block here would describe how to evolve some of the vectors
+         defined previously. -->
+    <!-- In this case, we have no evolution, all we need to do is save the nonlinear term
+         in the harmonic oscillator basis to a file. -->
+    <breakpoint filename="nlbreak.xsil" format="hdf5">
+      <dependencies basis="nx ny nz">nlterm nlterm_4f</dependencies>
+    </breakpoint>
+  </sequence>
+  <output />
+</simulation>
diff --git a/examples/bessel_cosine_groundstate.xmds b/examples/bessel_cosine_groundstate.xmds
new file mode 100644
index 0000000..e9ba6de
--- /dev/null
+++ b/examples/bessel_cosine_groundstate.xmds
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>bessel_cosine_groundstate</name>
+  <author>Graham Dennis</author>
+  <description>
+    Calculate the 3D ground state of a Rubidium BEC in a harmonic magnetic trap assuming
+    cylindrical symmetry about the z axis and reflection symmetry about z=0.
+    This permits us to use the cylindrical Bessel functions to expand the solution transverse
+    to z and a cosine series to expand the solution along z.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <chunked_output size="10KB" />
+    <globals>
+      <![CDATA[
+        const real omegaz = 2*M_PI*20;
+        const real omegarho = 2*M_PI*200;
+        const real hbar = 1.05457148e-34;
+        const real M = 1.409539200000000e-25;
+        const real g = 9.8;
+        const real scatteringLength = 5.57e-9;
+        const real Uint = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+        const real Nparticles = 5.0e5;
+
+        /* offset constants */
+        const real EnergyOffset = pow(15.0*Nparticles*Uint*omegaz*omegarho*omegarho/(8*M_PI), 2.0/5.0)
+                                    * pow(M/2.0, 3.0/5.0);
+
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <!-- Volume prefactor = 2\pi is to cover the integration over \theta -->
+      <dimension name="r" lattice="32"  domain="(0.0, 1.0e-5)" transform="bessel" volume_prefactor="2.0 * M_PI" />
+
+      <!-- Volume prefactor = 2 is so that integration effectively runs from -1.0e-4 to +1.0e-4 -->
+      <dimension name="z" lattice="32"  domain="(0.0, 1.0e-4)" transform="dct" volume_prefactor="2.0"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" type="complex">
+    <components>
+      V1
+    </components>
+    <initialisation>
+      <![CDATA[
+        real Vtrap = 0.5*M*(omegarho*omegarho*r*r + omegaz*omegaz*z*z);
+      
+        V1  = -i/hbar*(Vtrap - EnergyOffset);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+      
+        if ((abs(r) < 0.9e-5) && abs(z) < 0.9e-4) {
+          phi = 1.0; //sqrt(Nparticles/2.0e-5);
+          // This will be automatically normalised later
+        } else {
+          phi = 0.0;
+        }
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>
+      Ncalc
+    </components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="1e-4" steps="1000">
+      <samples>100</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi *= sqrt(Nparticles/Ncalc);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*hbar/M*(kr*kr + kz*kz);
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] - (i*V1 + Uint/hbar*mod2(phi))*phi;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output filename="bc_groundstate.xsil">
+    <sampling_group basis="r z" initial_sample="no">
+        <moments>norm_dens</moments>
+        <dependencies>wavefunction normalisation</dependencies>
+        <![CDATA[
+          norm_dens = mod2(phi)/Ncalc;
+        ]]>
+    </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/examples/bessel_cosine_stochastic_groundstate.xmds b/examples/bessel_cosine_stochastic_groundstate.xmds
new file mode 100644
index 0000000..06f75ff
--- /dev/null
+++ b/examples/bessel_cosine_stochastic_groundstate.xmds
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <author>Graham Dennis</author>
+  <description>
+    Calculate the 3D ground state of a Rubidium BEC in a harmonic magnetic trap assuming
+    cylindrical symmetry about the z axis and reflection symmetry about z=0.
+    This permits us to use the cylindrical bessel functions to expand the solution transverse
+    to z and a cosine series to expand the solution along z.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <chunked_output size="100KB" />
+    <globals>
+      <![CDATA[
+        const real omegaz = 2*M_PI*20;
+        const real omegarho = 2*M_PI*200;
+        const real hbar = 1.05457148e-34;
+        const real M = 1.409539200000000e-25;
+        const real g = 9.8;
+        const real scatteringLength = 5.57e-9;
+        const real Uint = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+        const real Nparticles = 5.0e5;
+
+        /* offset constants */
+        const real EnergyOffset = pow(15.0*Nparticles*Uint*omegaz*omegarho*omegarho/(8*M_PI), 2.0/5.0)
+                                    * pow(M/2.0, 3.0/5.0);
+
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <!-- Volume prefactor = 2\pi is to cover the integration over \theta -->
+      <dimension name="r" lattice="32"  domain="(0.0, 1.0e-5)" transform="bessel" volume_prefactor="2.0 * M_PI" />
+
+      <!-- Volume prefactor = 2 is so that integration effectively runs from -1.0e-4 to +1.0e-4 -->
+      <dimension name="z" lattice="32"  domain="(0.0, 1.0e-4)" transform="dct" volume_prefactor="2.0"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" type="complex">
+    <components>
+      V1
+    </components>
+    <initialisation>
+      <![CDATA[
+        real Vtrap = 0.5*M*(omegarho*omegarho*r*r + omegaz*omegaz*z*z);
+      
+        V1  = -i/hbar*(Vtrap - EnergyOffset);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <noise_vector name="noise" kind="gaussian" method="solirte" type="complex">
+    <components>eta</components>
+  </noise_vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <dependencies>noise</dependencies>
+      <![CDATA[
+      
+        if ((abs(r) < 0.9e-5) && abs(z) < 0.9e-4) {
+          phi = eta;
+          // This will be automatically normalised later
+        } else {
+          phi = 0.0;
+        }
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>
+      Ncalc
+    </components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="3e-3" steps="30000">
+      <samples>300</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi *= sqrt(Nparticles/Ncalc);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*hbar/M*(kr*kr + kz*kz);
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] - (i*V1 + Uint/hbar*mod2(phi))*phi;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output>
+      <sampling_group basis="r z" initial_sample="no">
+        <moments>norm_dens</moments>
+        <dependencies>wavefunction normalisation</dependencies>
+        <![CDATA[
+          norm_dens = mod2(phi)/Ncalc;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/examples/bessel_transform.xmds b/examples/bessel_transform.xmds
new file mode 100644
index 0000000..a63d4a5
--- /dev/null
+++ b/examples/bessel_transform.xmds
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>bessel_transform</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the wave equation on a sphere of radius 1 utilising spherical symmetry
+    by using the Spherical Bessel function transform.
+  </description>
+  
+  <features>
+    <benchmark />
+    <!-- <error_check /> -->
+    <bing />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <!-- Volume prefactor = 4\pi is to cover the suppressed integration over \theta and \phi -->
+      <dimension name="x" lattice="100" spectral_lattice="50" domain="(0, 1)" transform="spherical-bessel" volume_prefactor="4.0*M_PI"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.25)*(x-0.25));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-6" interval="4e-3" steps="400">
+      <samples>100 100</samples>
+      <operators>
+        <operator kind="ex" constant="yes" basis="kx" type="real">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output>
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx" initial_sample="no">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();   
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/bessel_transform2.xmds b/examples/bessel_transform2.xmds
new file mode 100644
index 0000000..c0ba5b6
--- /dev/null
+++ b/examples/bessel_transform2.xmds
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>bessel_transform2</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the wave equation on a disk of radius 1 utilising cylindrical symmetry
+    by using the Bessel function transform.
+  </description>
+  
+  <features>
+    <benchmark />
+    <!-- <error_check /> -->
+    <bing />
+    <validation kind="run-time" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <!-- Volume prefactor = 2 \pi is to cover the suppressed integration over \theta -->
+      <dimension name="x" lattice="100"  domain="(0, 1)" transform="bessel" order="3" volume_prefactor="2.0*M_PI"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.25)*(x-0.25));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-6" interval="40e-3" steps="400">
+      <samples>100 100</samples>
+      <operators>
+        <operator kind="ex" constant="yes" basis="kx" type="real">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output>
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx" initial_sample="no">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/cpc_ex_scaling.xmds b/examples/cpc_ex_scaling.xmds
new file mode 100644
index 0000000..1a99d4b
--- /dev/null
+++ b/examples/cpc_ex_scaling.xmds
@@ -0,0 +1,75 @@
+<simulation xmds-version="2">
+  <name> cpc_ex_scaling </name>
+  
+  <features>
+    <benchmark />
+    <auto_vectorise />
+    <globals>
+      <![CDATA[
+        real N = 10.0; // number of atoms
+        real g = 1.0;  // nonlinear coupling
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="256"
+                 domain="(-7, 7)" />
+    </transverse_dimensions>
+  </geometry>
+
+  <vector name="potential" type="real">
+    <components> V </components>
+    <initialisation>
+      <![CDATA[
+        V = 0.5*x*x;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components> psi </components>
+    <initialisation>
+      <![CDATA[
+        psi = sqrt(N) * pow(M_PI, -0.25) * exp(-x*x/2);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <integrate algorithm="ARK45" interval="6.28" 
+               tolerance="1e-5" steps="50">
+      <samples> 0 </samples>
+      <operators>
+
+        <operator kind="ex" constant="yes">
+          <operator_names> T </operator_names>
+          <![CDATA[
+            T = -i * 0.5 * kx * kx;
+          ]]>
+        </operator>
+
+        <integration_vectors>
+          wavefunction
+        </integration_vectors> 
+        <dependencies> potential </dependencies>
+        <![CDATA[
+          dpsi_dt = T[psi] - i * (V + g * mod2(psi)) * psi;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+
+  <output format="hdf5">
+    <sampling_group initial_sample="yes" basis="x">
+      <dependencies> wavefunction </dependencies>
+      <moments> psireal psiimag </moments>
+      <![CDATA[
+        psireal = Re(psi);
+        psiimag = Im(psi);
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/cpc_example1.xmds b/examples/cpc_example1.xmds
new file mode 100644
index 0000000..153e697
--- /dev/null
+++ b/examples/cpc_example1.xmds
@@ -0,0 +1,75 @@
+<simulation xmds-version="2">
+  <name> nonlinear_SE </name>
+  
+  <features>
+    <benchmark />
+    <auto_vectorise />
+    <globals>
+      <![CDATA[
+        real N = 10.0; // number of atoms
+        real g = 1.0;  // nonlinear coupling
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="512"
+                 domain="(-7, 7)" />
+    </transverse_dimensions>
+  </geometry>
+
+  <vector name="potential" type="real">
+    <components> V </components>
+    <initialisation>
+      <![CDATA[
+        V = 0.5*x*x;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components> psi </components>
+    <initialisation>
+      <![CDATA[
+        psi = sqrt(N) * pow(M_PI, -0.25) * exp(-x*x/2);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <integrate algorithm="ARK45" interval="6.28" 
+                                 tolerance="1e-5">
+      <samples> 50 </samples>
+      <operators>
+
+        <operator kind="ip" constant="yes">
+          <operator_names> T </operator_names>
+          <![CDATA[
+            T = -i * 0.5 * kx * kx;
+          ]]>
+        </operator>
+
+        <integration_vectors>
+          wavefunction
+        </integration_vectors> 
+        <dependencies> potential </dependencies>
+        <![CDATA[
+          dpsi_dt = T[psi] - i * (V + g * mod2(psi)) * psi;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+
+  <output format="hdf5">
+    <sampling_group initial_sample="yes" basis="x">
+      <dependencies> wavefunction </dependencies>
+      <moments> psireal psiimag </moments>
+      <![CDATA[
+        psireal = Re(psi);
+        psiimag = Im(psi);
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/cpc_example2.xmds b/examples/cpc_example2.xmds
new file mode 100644
index 0000000..72c69ec
--- /dev/null
+++ b/examples/cpc_example2.xmds
@@ -0,0 +1,77 @@
+<simulation xmds-version="2">
+  <name> nonlinear_SE </name>
+  
+  <features>
+    <benchmark />
+    <auto_vectorise />
+    <globals>
+      <![CDATA[
+        real N = 10.0; // number of atoms
+        real g = 1.0;  // nonlinear coupling
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="512"
+                 domain="(-7, 7)" />
+	  <dimension name="y" lattice="512"
+		  	 	 domain="(-7, 7)" />	
+    </transverse_dimensions>
+  </geometry>
+
+  <vector name="potential" type="real">
+    <components> V </components>
+    <initialisation>
+      <![CDATA[
+        V = 0.5*(x*x + y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components> psi </components>
+    <initialisation>
+      <![CDATA[
+        psi = sqrt(N) * pow(M_PI, -0.25) * exp(-(x*x + y*y)/2);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <integrate algorithm="ARK45" interval="6.28" 
+                                 tolerance="1e-5">
+      <samples> 50 </samples>
+      <operators>
+
+        <operator kind="ip" constant="yes">
+          <operator_names> T </operator_names>
+          <![CDATA[
+            T = -i * 0.5 * (kx * kx + ky * ky);
+          ]]>
+        </operator>
+
+        <integration_vectors>
+          wavefunction
+        </integration_vectors> 
+        <dependencies> potential </dependencies>
+        <![CDATA[
+          dpsi_dt = T[psi] - i * (V + g * mod2(psi)) * psi;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+
+  <output format="hdf5">
+    <sampling_group initial_sample="yes" basis="x y">
+      <dependencies> wavefunction </dependencies>
+      <moments> psireal psiimag </moments>
+      <![CDATA[
+        psireal = Re(psi);
+        psiimag = Im(psi);
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/cpc_example3.xmds b/examples/cpc_example3.xmds
new file mode 100644
index 0000000..0337827
--- /dev/null
+++ b/examples/cpc_example3.xmds
@@ -0,0 +1,75 @@
+<simulation xmds-version="2">
+  <name> nonlinear_SE </name>
+  
+  <features>
+    <benchmark />
+    <auto_vectorise />
+    <globals>
+      <![CDATA[
+        real N = 10.0; // number of atoms
+        real g = 1.0;  // nonlinear coupling
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="512"
+                 domain="(0, 7)" transform="dct"/>
+    </transverse_dimensions>
+  </geometry>
+
+  <vector name="potential" type="real">
+    <components> V </components>
+    <initialisation>
+      <![CDATA[
+        V = 0.5*x*x;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components> psi </components>
+    <initialisation>
+      <![CDATA[
+        psi = sqrt(N) * pow(M_PI, -0.25) * exp(-x*x/2);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <integrate algorithm="ARK45" interval="6.28" 
+                                 tolerance="1e-5">
+      <samples> 50 </samples>
+      <operators>
+
+        <operator kind="ip" constant="yes">
+          <operator_names> T </operator_names>
+          <![CDATA[
+            T = -i * 0.5 * kx * kx;
+          ]]>
+        </operator>
+
+        <integration_vectors>
+          wavefunction
+        </integration_vectors> 
+        <dependencies> potential </dependencies>
+        <![CDATA[
+          dpsi_dt = T[psi] - i * (V + g * mod2(psi)) * psi;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+
+  <output format="hdf5">
+    <sampling_group initial_sample="yes" basis="x">
+      <dependencies> wavefunction </dependencies>
+      <moments> psireal psiimag </moments>
+      <![CDATA[
+        psireal = Re(psi);
+        psiimag = Im(psi);
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/cpc_example4.xmds b/examples/cpc_example4.xmds
new file mode 100644
index 0000000..9e5df14
--- /dev/null
+++ b/examples/cpc_example4.xmds
@@ -0,0 +1,79 @@
+<simulation xmds-version="2">
+  <name> nonlinear_SE </name>
+  
+  <features>
+    <benchmark />
+    <auto_vectorise />
+    <globals>
+      <![CDATA[
+        real N = 10.0; // number of atoms
+        real g = 1.0;  // nonlinear coupling
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="256"
+                 domain="(-7, 7)" />
+	  <dimension name="y" lattice="256"
+		  	 	 domain="(-7, 7)" />	
+    </transverse_dimensions>
+  </geometry>
+
+  <driver name="distributed-mpi" />
+
+  <vector name="potential" type="real">
+    <components> V </components>
+    <initialisation>
+      <![CDATA[
+        V = 0.5*(x*x + y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components> psi </components>
+    <initialisation>
+      <![CDATA[
+        psi = sqrt(N) * pow(M_PI, -0.25) * exp(-(x*x + y*y)/2);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <integrate algorithm="ARK45" interval="6.28" 
+                                 tolerance="1e-5">
+      <samples> 50 </samples>
+      <operators>
+
+        <operator kind="ip" constant="yes">
+          <operator_names> T </operator_names>
+          <![CDATA[
+            T = -i * 0.5 * (kx * kx + ky * ky);
+          ]]>
+        </operator>
+
+        <integration_vectors>
+          wavefunction
+        </integration_vectors> 
+        <dependencies> potential </dependencies>
+        <![CDATA[
+          dpsi_dt = T[psi] - i * (V + g * mod2(psi)) * psi;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+
+  <output format="hdf5">
+    <sampling_group initial_sample="yes" basis="x y">
+      <dependencies> wavefunction </dependencies>
+      <moments> psireal psiimag </moments>
+      <![CDATA[
+        psireal = Re(psi);
+        psiimag = Im(psi);
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/cpc_example4_3d.xmds b/examples/cpc_example4_3d.xmds
new file mode 100644
index 0000000..d4abde4
--- /dev/null
+++ b/examples/cpc_example4_3d.xmds
@@ -0,0 +1,81 @@
+<simulation xmds-version="2">
+  <name> nonlinear_SE </name>
+  
+  <features>
+    <benchmark />
+    <auto_vectorise />
+    <globals>
+      <![CDATA[
+        real N = 10.0; // number of atoms
+        real g = 1.0;  // nonlinear coupling
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="256"
+                 domain="(-7, 7)" />
+	  <dimension name="y" lattice="256"
+		  	 	 domain="(-7, 7)" />	
+	  <dimension name="z" lattice="256"
+		  	 	 domain="(-7, 7)" />	
+    </transverse_dimensions>
+  </geometry>
+
+  <driver name="distributed-mpi" />
+
+  <vector name="potential" type="real">
+    <components> V </components>
+    <initialisation>
+      <![CDATA[
+        V = 0.5*(x*x + y*y + z*z);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components> psi </components>
+    <initialisation>
+      <![CDATA[
+        psi = sqrt(N) * pow(M_PI, -0.25) * exp(-(x*x + y*y + z*z)/2);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <integrate algorithm="ARK45" interval="6.28" 
+                                 tolerance="1e-5">
+      <samples> 0 </samples>
+      <operators>
+
+        <operator kind="ip" constant="yes">
+          <operator_names> T </operator_names>
+          <![CDATA[
+            T = -i * 0.5 * (kx * kx + ky * ky + kz*kz);
+          ]]>
+        </operator>
+
+        <integration_vectors>
+          wavefunction
+        </integration_vectors> 
+        <dependencies> potential </dependencies>
+        <![CDATA[
+          dpsi_dt = T[psi] - i * (V + g * mod2(psi)) * psi;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+
+  <output format="hdf5">
+    <sampling_group initial_sample="yes" basis="x y z">
+      <dependencies> wavefunction </dependencies>
+      <moments> psireal psiimag </moments>
+      <![CDATA[
+        psireal = Re(psi);
+        psiimag = Im(psi);
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/cpc_example5.xmds b/examples/cpc_example5.xmds
new file mode 100644
index 0000000..568b6ae
--- /dev/null
+++ b/examples/cpc_example5.xmds
@@ -0,0 +1,112 @@
+<simulation xmds-version="2">
+  <name> nonlinear_SE </name>
+  
+  <features>
+    <benchmark />
+    <auto_vectorise />
+    <globals>
+      <![CDATA[
+        real N = 10.0; // number of atoms
+        real g = 1.0;  // nonlinear coupling
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="512"
+                 domain="(-7, 7)" />
+    </transverse_dimensions>
+  </geometry>
+
+  <vector name="potential" type="real">
+    <components> V </components>
+    <initialisation>
+      <![CDATA[
+        V = 0.5*x*x;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <!-- Although the density is real, we need to Fourier transform it, so it must be complex -->
+  <computed_vector name="density" type="complex">
+  	<components>dens</components>
+	<evaluation>
+		<dependencies>wavefunction</dependencies>
+		<![CDATA[
+			dens = mod2(psi);
+		]]>
+	</evaluation>
+  </computed_vector>
+  
+  <computed_vector name="electrostatic" type="complex">
+  	<components> V_E </components>
+	<evaluation>
+		<!-- 
+		We compute the electrostatic self-potential in fourier space where the convolution
+		is simply a local multiplication.  We've taken the analytical fourier transform of 1/r in 3D
+		here, but we've needed to truncate the upper limit of the integral to keep it finite.
+		This is simply because if the system is assumed to be periodic, then it will be everywhere in space,
+		not just the place we think of it.  Truncating the integral corresponds to not considering the
+		electrostatic potential due to the other copies (which we obviously don't want to include).
+		
+		If the BEC is kept to the inner half of the domain, the correct truncation of the integral will be
+		half the width of the domain (the minimum separation between copies).
+		-->
+		<dependencies basis="kx">density</dependencies>
+		<![CDATA[
+				  // The analytic term is (1/(kx*kx) * (1 - cos(kx * R))) where R is the upper limit on the
+				  // Fourier transform.  This has zero limit near kx = 0 analytically, but the computer
+				  // won't know that when it tries to divide by zero.
+				  V_E = +1e-1 * dens * 2 / (kx * kx) * (1.0 - cos(kx * 0.5* (_max_x - _min_x)));
+		if (kx == 0.0)
+			V_E = 0.0;
+		]]>
+	</evaluation>
+  </computed_vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components> psi </components>
+    <initialisation>
+      <![CDATA[
+        psi = sqrt(N) * pow(M_PI, -0.25) * exp(-x*x/2);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <integrate algorithm="ARK45" interval="6.28" 
+                                 tolerance="1e-5">
+      <samples> 50 </samples>
+      <operators>
+
+        <operator kind="ip" constant="yes">
+          <operator_names> T </operator_names>
+          <![CDATA[
+            T = -i * 0.5 * kx * kx;
+          ]]>
+        </operator>
+
+        <integration_vectors>
+          wavefunction
+        </integration_vectors> 
+        <dependencies> potential electrostatic </dependencies>
+        <![CDATA[
+          dpsi_dt = T[psi] - i * (V + V_E + g * mod2(psi)) * psi;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+
+  <output format="hdf5">
+    <sampling_group initial_sample="yes" basis="x">
+      <dependencies> wavefunction </dependencies>
+      <moments> psireal psiimag </moments>
+      <![CDATA[
+        psireal = Re(psi);
+        psiimag = Im(psi);
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/cpc_example6.xmds b/examples/cpc_example6.xmds
new file mode 100644
index 0000000..4c7fb97
--- /dev/null
+++ b/examples/cpc_example6.xmds
@@ -0,0 +1,83 @@
+<simulation xmds-version="2">
+  <name> nonlinear_SE </name>
+  
+  <features>
+    <benchmark />
+    <auto_vectorise />
+    <globals>
+      <![CDATA[
+        real N = 10.0; // number of atoms
+        real g = 1.0;  // nonlinear coupling
+		real alpha = 1e-3; // trap noise scale factor
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="512"
+                 domain="(-7, 7)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="mpi-multi-path" paths="100" />
+
+  <vector name="potential" type="real">
+    <components> V </components>
+    <initialisation>
+      <![CDATA[
+        V = 0.5*x*x;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components> psi </components>
+    <initialisation>
+      <![CDATA[
+        psi = sqrt(N) * pow(M_PI, -0.25) * exp(-x*x/2);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <noise_vector name="trapNoise" kind="wiener"
+                type="real" method="dsfmt">
+    <components> noise_x </components>
+  </noise_vector>
+
+  <sequence>
+    <integrate algorithm="ARK45" interval="6.28" 
+                                 tolerance="1e-5">
+      <samples> 50 </samples>
+      <operators>
+
+        <operator kind="ip" constant="yes">
+          <operator_names> T </operator_names>
+          <![CDATA[
+            T = -i * 0.5 * kx * kx;
+          ]]>
+        </operator>
+
+        <integration_vectors>
+          wavefunction
+        </integration_vectors> 
+        <dependencies> potential trapNoise </dependencies>
+        <![CDATA[
+          dpsi_dt = T[psi] - i * (V + g * mod2(psi) + alpha * noise_x) * psi;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+
+  <output format="hdf5">
+    <sampling_group initial_sample="yes" basis="x">
+      <dependencies> wavefunction </dependencies>
+      <moments> psireal psiimag </moments>
+      <![CDATA[
+        psireal = Re(psi);
+        psiimag = Im(psi);
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/cpc_ip_scaling.xmds b/examples/cpc_ip_scaling.xmds
new file mode 100644
index 0000000..ecfc667
--- /dev/null
+++ b/examples/cpc_ip_scaling.xmds
@@ -0,0 +1,75 @@
+<simulation xmds-version="2">
+  <name> cpc_ip_scaling </name>
+  
+  <features>
+    <benchmark />
+    <auto_vectorise />
+    <globals>
+      <![CDATA[
+        real N = 10.0; // number of atoms
+        real g = 1.0;  // nonlinear coupling
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="256"
+                 domain="(-7, 7)" />
+    </transverse_dimensions>
+  </geometry>
+
+  <vector name="potential" type="real">
+    <components> V </components>
+    <initialisation>
+      <![CDATA[
+        V = 0.5*x*x;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components> psi </components>
+    <initialisation>
+      <![CDATA[
+        psi = sqrt(N) * pow(M_PI, -0.25) * exp(-x*x/2);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <integrate algorithm="ARK45" interval="6.28" 
+               tolerance="1e-5" steps="50">
+      <samples> 0 </samples>
+      <operators>
+
+        <operator kind="ip" constant="yes">
+          <operator_names> T </operator_names>
+          <![CDATA[
+            T = -i * 0.5 * kx * kx;
+          ]]>
+        </operator>
+
+        <integration_vectors>
+          wavefunction
+        </integration_vectors> 
+        <dependencies> potential </dependencies>
+        <![CDATA[
+          dpsi_dt = T[psi] - i * (V + g * mod2(psi)) * psi;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+
+  <output format="hdf5">
+    <sampling_group initial_sample="yes" basis="x">
+      <dependencies> wavefunction </dependencies>
+      <moments> psireal psiimag </moments>
+      <![CDATA[
+        psireal = Re(psi);
+        psiimag = Im(psi);
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/diffusion.xmds b/examples/diffusion.xmds
new file mode 100644
index 0000000..749e3e3
--- /dev/null
+++ b/examples/diffusion.xmds
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>diffusion</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion with a pointless second dimension thrown in for fun
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw plan="exhaustive" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="32"  domain="(-10.0, 10.0)" />
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="10.0" steps="2400" tolerance="1e-5">
+      <samples>24</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="x ky" type="real">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output>
+      <sampling_group basis="x(4) y(8)" initial_sample="yes">
+        <moments>dens empty</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+          empty = x+100*y;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/diffusion_arguments.xmds b/examples/diffusion_arguments.xmds
new file mode 100644
index 0000000..90b266f
--- /dev/null
+++ b/examples/diffusion_arguments.xmds
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>diffusion_arguments</name>
+  <author>Andy Ferris</author>
+  <description>
+    Simple one-dimensional diffusion with a pointless second dimension thrown in for fun.
+    Uses arguments and argument preprocessing. Essentially the simulation "looks" the
+    same for any given "size", as the interval/etc is scaled to fit the interesting region.
+    The user may use width_scale, time_scale and ratio to zoom out and in...
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="exhaustive" />
+    <validation kind="run-time"/>
+    <globals>
+      <![CDATA[
+      real minx;
+      real maxx;
+      real miny;
+      real maxy;
+      real width;
+      real time_interval;
+      ]]>
+    </globals>
+    <arguments>
+      <argument name="size" type="real" default_value="20.0"/>
+      <argument name="ratio" type="real" default_value="0.1"/>
+      <argument name="width_factor" type="real" default_value="1.0"/>
+      <argument name="time_factor" type="real" default_value="1.0"/>
+      <![CDATA[
+      minx = -0.5*size;
+      maxx = 0.5*size;
+      miny = -0.5*size*ratio;
+      maxy = 0.5*size*ratio;
+      width = 0.5*sqrt(0.5)*size*ratio*width_factor; // half the simulation size
+      // The time intersting stuff happens scales as width^2
+      time_interval = 20.0 * width*width * time_factor;
+      ]]>
+    </arguments>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="32"  domain="(minx, maxx)" />
+      <dimension name="y" lattice="128" domain="(miny, maxy)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y/(2*width*width));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <!-- This is an interesting simulation because using IP operators means there is NO error due to the algorithm (though there may be numerical error) -->
+    <integrate algorithm="RK4" interval="time_interval" steps="24">
+      <samples>24</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="x ky">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output>
+      <sampling_group basis="x(0) y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/diffusion_dst.xmds b/examples/diffusion_dst.xmds
new file mode 100644
index 0000000..17163e9
--- /dev/null
+++ b/examples/diffusion_dst.xmds
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>diffusion_dst</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion solved using a Discrete Sine Transform (odd boundary conditions at both ends)
+    Odd boundary conditions essentially mimics zero Dirichlet boundary conditions for linear problems.
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw plan="exhaustive" />
+
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" transform="dst" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="y" type="real">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-3*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="20.0" steps="2400" tolerance="1e-5">
+      <samples>48</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="ky">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output>
+      <sampling_group basis="y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/diffusion_mpi.xmds b/examples/diffusion_mpi.xmds
new file mode 100644
index 0000000..593c8a6
--- /dev/null
+++ b/examples/diffusion_mpi.xmds
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>diffusion_mpi</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion with a pointless second dimension thrown in for fun
+  </description>
+  
+  <features>
+    <benchmark />
+    <!-- <error_check /> -->
+    <bing />
+    <fftw plan="measure" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+      <dimension name="x" lattice="256"  domain="(-10.0, 10.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="10.0" steps="2400" tolerance="1e-5">
+      <samples>24 4</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="x ky">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output>
+      <sampling_group basis="y x(0)" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="y x" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/diffusion_openmp.xmds b/examples/diffusion_openmp.xmds
new file mode 100644
index 0000000..710153b
--- /dev/null
+++ b/examples/diffusion_openmp.xmds
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>diffusion_mpi</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion with a pointless second dimension thrown in for fun
+  </description>
+  
+  <features>
+    <benchmark />
+    <!-- <error_check /> -->
+    <bing />
+    <fftw plan="measure" threads="4" />
+    <openmp />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+      <dimension name="x" lattice="256"  domain="(-10.0, 10.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK9" interval="10.0" steps="2400" tolerance="1e-5">
+      <samples>24 4</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="x ky" type="real">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output>
+      <sampling_group basis="y x(0)" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="y x" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/diffusion_win.xmds b/examples/diffusion_win.xmds
new file mode 100644
index 0000000..6a012b9
--- /dev/null
+++ b/examples/diffusion_win.xmds
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>diffusion_win</name>
+  <author>Andy Ferris</author>
+  <description>
+    Simple one-dimensional diffusion with a pointless second dimension thrown in for fun. Windows version.
+  </description>
+  
+  <features>
+    <!--<benchmark /> -->
+    <error_check />
+    <bing />
+    <fftw plan="exhaustive"/>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="32"  domain="(-10.0, 10.0)" />
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="10.0" steps="2400" tolerance="1e-5">
+      <samples>24</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="x ky">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="ascii" filename="diffusion.xsil">
+      <sampling_group basis="x(0) y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/excitedstate_gaussian.xmds b/examples/excitedstate_gaussian.xmds
new file mode 100644
index 0000000..da89d7f
--- /dev/null
+++ b/examples/excitedstate_gaussian.xmds
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>excitedstate_gaussian</name>
+  <author>Graham Dennis</author>
+  <description>
+    Calculate the first excited state of a negative gaussian potential.
+    
+    The idea here is to use the imaginary time algorithm but at each step
+    to project out the ground state that was calculated with the 
+    groundstate_gaussian.xmds script.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="1024"  domain="(-12.0, 12.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" initial_basis="y" type="complex">
+    <components>
+      V1
+    </components>
+    <initialisation kind="hdf5">
+      <!-- Use the same potential as the previous simulation -->
+      <filename>groundstate_gaussian_break.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" initial_basis="y" type="complex">
+    <components>
+      phi1
+    </components>
+    <initialisation>
+      <![CDATA[
+      
+      // This will be automatically normalised later
+      // The extra 'y' is there to make the wavefunction asymmetric
+      phi1 = y*exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="groundstate" initial_basis="y" type="complex">
+    <components>phi</components>
+    <initialisation kind="hdf5">
+      <filename>groundstate_gaussian_break.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>
+      Ncalc
+    </components>
+    <evaluation>
+      <dependencies basis="y">wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi1);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <computed_vector name="groundstate_overlap" dimensions="" type="complex">
+    <components>overlap</components>
+    <evaluation>
+      <dependencies>groundstate wavefunction</dependencies>
+      <![CDATA[
+        overlap = phi1*conj(phi);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK9" interval="10.0" steps="10000" tolerance="1e-8">
+      <samples>500 500</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction groundstate_overlap groundstate</dependencies>
+          <![CDATA[
+            // Subtract out the projection of the groundstate
+            phi1 -= overlap * phi;
+          ]]>
+        </filter>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi1 *= sqrt(1.0/Ncalc);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="no">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi1_dt = T[phi1] - (i*V1)*phi1;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="excitedstate_gaussian_break.xsil" format="hdf5">
+      <dependencies>wavefunction</dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output>
+      <sampling_group basis="y" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens = mod2(phi1);
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="no">
+        <moments>N</moments>
+        <dependencies>normalisation</dependencies>
+        <![CDATA[
+          N = Ncalc;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/examples/fibre.xmds b/examples/fibre.xmds
new file mode 100644
index 0000000..a39aa35
--- /dev/null
+++ b/examples/fibre.xmds
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>fibre</name>
+  <author>Joe Hope and Graham Dennis</author>
+  <description>
+    Example fibre noise simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="64"  domain="(-5, 5)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="mpi-multi-path" paths="1024" />
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <error_check />
+    <bing />
+    <globals>
+      <![CDATA[
+      const real ggamma = 1.0;
+      const real beta = sqrt(M_PI*ggamma/10.0);
+      ]]>
+    </globals>
+  </features>
+  
+  <noise_vector name="drivingNoise" dimensions="x" kind="wiener" type="complex" method="dsfmt" seed="314 159 276">
+    <components>Eta</components>
+  </noise_vector>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>phi</components>
+    <initialisation>
+      <![CDATA[
+        phi = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="SI" iterations="3" interval="2.5" steps="200000">
+      <samples>50</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*kx*kx;
+          ]]>
+        </operator>
+        <dependencies>drivingNoise</dependencies>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi] - ggamma*phi + beta*Eta;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output>
+      <sampling_group basis="kx" initial_sample="yes">
+        <moments>pow_dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          pow_dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/fibre_noisevectors.xmds b/examples/fibre_noisevectors.xmds
new file mode 100644
index 0000000..2cca223
--- /dev/null
+++ b/examples/fibre_noisevectors.xmds
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>fibre_noisevectors</name>
+  <author>Joe Hope</author>
+  <description>
+    Example fibre noise simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="64"  domain="(-5, 5)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="mpi-multi-path" paths="2" />
+  
+  <features>
+    <auto_vectorise />
+    <validation kind="none"/>
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw />
+    <globals>
+      <![CDATA[
+      const real ggamma = 1.0;
+      const real beta = sqrt(2.0*M_PI*ggamma/10.0);
+      ]]>
+    </globals>
+  </features>
+  
+  <noise_vector name="fuzzyInitial" dimensions="x" kind="gaussian" type="real" method="dsfmt" seed="314 159 276">
+    <components>nn_1 nn_2</components>
+  </noise_vector>
+
+  <noise_vector name="noiseEvolution" dimensions="x" kind="wiener" type="real" method="dsfmt" seed="314 159 276">
+    <components>p_1 p_2</components>
+  </noise_vector>
+
+  <vector name="main" initial_basis="x" type="complex">
+    <components>phi psi</components>
+    <initialisation>
+        <dependencies>fuzzyInitial</dependencies>
+      <![CDATA[
+        phi = exp(-x*x)+nn_1;
+        psi = exp(-x*x)+nn_2;
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <integrate algorithm="SI" iterations="3" interval="0.25" steps="200000">
+      <samples>50</samples>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*kx*kx;
+          ]]>
+        </operator>
+        <dependencies>noiseEvolution</dependencies>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+         dphi_dt = L[phi] - ggamma*phi;
+         dpsi_dt = L[psi] - ggamma*psi + psi*complex(p_1,p_2);
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output>
+      <sampling_group basis="kx" initial_sample="yes">
+        <moments>kdensphi kdenspsi</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          kdensphi = mod2(phi);
+          kdenspsi = mod2(psi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/gravity.xmds b/examples/gravity.xmds
new file mode 100644
index 0000000..7f9ce1c
--- /dev/null
+++ b/examples/gravity.xmds
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>gravity</name>
+  <author>Graham Dennis</author>
+  <description>
+    Example system of gravitationally-attracted particles
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <!-- <fftw /> -->
+
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <!-- Dimension for particle number -->
+      <dimension name="j" type="integer" lattice="4" domain="(0, 3)" />
+    </transverse_dimensions>
+  </geometry>
+
+  <noise_vector name="initialMassNoises" kind="poissonian" type="real" mean="4.0" method="posix" seed="157 9348 234">
+        <components>q</components>
+  </noise_vector>
+    
+  <noise_vector name="initialMomentaNoises" kind="gaussian" type="real" method="posix" seed="17 948 2341">
+        <components>p_1 p_2 p_3 p_4</components>
+  </noise_vector>    
+  
+  <vector name="motion" type="real">
+    <components> x y vx vy </components>
+    <initialisation>
+    <dependencies>initialMomentaNoises</dependencies>
+      <![CDATA[
+        x = 2.0*p_1;
+        y = 2.0*p_2;
+        vx = 0.1*p_3;
+        vy = 0.1*p_4;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="mass" type="real">
+    <components> m </components>
+    <initialisation>
+    <dependencies>initialMassNoises</dependencies>
+      <![CDATA[
+      // Set the mass equal to a poissonian noise.
+      // but don't let the mass be zero
+      m = q;
+      if (m < 0.01) m = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" interval="100" steps="1000" tolerance="1e-8">
+      <samples>1000 100</samples>
+      <operators>
+        <integration_vectors>motion</integration_vectors>
+        <dependencies>mass</dependencies>
+        <![CDATA[
+          dx_dt = vx;
+          dy_dt = vy;
+          for (long k = 0; k < j; k++) {
+            real inverseSeparationCubed = pow((x(j => k) - x(j => j))*(x(j => k) - x(j => j)) + (y(j => k) - y(j => j))*(y(j => k) - y(j => j)), -3.0/2.0);
+            // printf("j: %li k: %li    x[j]: %e x[k]: %e  y[j]: %e y[k]: %e\n", j, k, x[j], x[k], y[j], y[k]);
+            // printf("separationSquared: %e inverseSeparationCubed: %e\n", (x[k] - x[j])*(x[k] - x[j]) + (y[k] - y[j])*(y[k] - y[j]), inverseSeparationCubed);
+            dvx_dt(j => j) += m(j => k)*(x(j => k) - x(j => j))*inverseSeparationCubed;
+            dvx_dt(j => k) += m(j => j)*(x(j => j) - x(j => k))*inverseSeparationCubed;
+            dvy_dt(j => j) += m(j => k)*(y(j => k) - y(j => j))*inverseSeparationCubed;
+            dvy_dt(j => k) += m(j => j)*(y(j => j) - y(j => k))*inverseSeparationCubed;
+          }
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output>
+      <sampling_group basis="j" initial_sample="yes">
+        <moments>xR yR vxR vyR</moments>
+        <dependencies>motion</dependencies>
+        <![CDATA[
+          xR = x;
+          yR = y;
+          vxR = vx;
+          vyR = vy;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="j(0)" initial_sample="yes">
+        <moments>energy px py</moments>
+        <dependencies>mass motion</dependencies>
+        <![CDATA[
+        // Check conserved quantities
+          energy = 0.5*m*(vx*vx + vy*vy);
+          for (long k = 0; k < j; k++) {
+            energy += -m(j => j)*m(j => k)*pow((x(j => j)-x(j => k))*(x(j => j)-x(j => k)) + (y(j => j)-y(j => k))*(y(j => j)-y(j => k)), -0.5);
+          }
+          px = m*vx;
+          py = m*vy;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/groundstate_demo2.xmds b/examples/groundstate_demo2.xmds
new file mode 100644
index 0000000..02136e0
--- /dev/null
+++ b/examples/groundstate_demo2.xmds
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>groundstate_demo2</name>
+  <author>Joe Hope and Graham Dennis</author>
+  <description>
+    Calculate the ground state of the non-linear Schrodinger equation in a harmonic magnetic trap.
+    This is done by evolving it in imaginary time while re-normalising each timestep.
+	We demonstrate calculating the energy, energy per particle, and chemical potential at each time step to
+	monitor the convergence of the imaginary time algorithm.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw plan="exhaustive" />
+    <globals>
+      <![CDATA[
+        const real Uint = 1.0e2;
+        const real Nparticles = 1;
+
+        /* offset constants */
+        const real EnergyOffset = pow(pow(3.0*Nparticles/4*Uint,2.0)/2.0,1/3.0); // 1D
+
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="1024"  domain="(-10.0, 10.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" initial_basis="y" type="complex">
+    <components>
+      V1
+    </components>
+    <initialisation>
+      <![CDATA[
+        real Vtrap = 0.5*y*y;
+      
+        V1  = -i*(Vtrap - EnergyOffset);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" initial_basis="y" type="complex">
+    <components> phi </components>
+    <initialisation>
+      <![CDATA[
+        if (fabs(y) < 1.0) {
+          phi = 1.0;
+          // This will be automatically normalised later
+        } else {
+          phi = 0.0;
+        }
+            ]]>
+    </initialisation>
+  </vector>
+  
+  <!-- Calculate the kinetic energy as an integral in fourier space -->
+  <computed_vector name="kinetic_energy" dimensions="" type="real">
+    <components>KE</components>
+    <evaluation>
+      <dependencies basis="ky">wavefunction</dependencies>
+      <![CDATA[
+                  KE = 0.5*ky*ky*mod2(phi);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <!-- Calculate the spatial energy terms as integrals in position space -->
+  <computed_vector name="spatial_energy" dimensions="" type="real">
+    <components>VE NLE</components>
+    <evaluation>
+      <dependencies basis="y">potential wavefunction</dependencies>
+      <![CDATA[
+            VE = -Im(V1) * mod2(phi);
+            NLE = 0.5*Uint *mod2(phi) * mod2(phi);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <!-- 
+  Add the energy contributions.  We can't add a 'KE' term to the spatial_energy computed_vector because then we'd be integrating the scalar
+  over the physical volume, and we'd add KE * V to any term, instead of just KE.
+   -->
+  <computed_vector name="energy" dimensions="" type="real">
+    <components>E E_over_N mu</components>
+    <evaluation>
+      <dependencies>spatial_energy kinetic_energy normalisation</dependencies>
+      <![CDATA[
+            E = KE + VE + NLE;
+            E_over_N = E/Ncalc;
+            mu = (KE + VE + 2.0*NLE) / Ncalc;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>
+      Ncalc
+    </components>
+    <evaluation>
+      <dependencies basis="y">wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="1e0" steps="10000" tolerance="1e-8">
+      <samples>20 20</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi *= sqrt(Nparticles/Ncalc);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] - (i*V1 + Uint*mod2(phi))*phi;
+        ]]>
+      </operators>
+    </integrate>
+
+    <breakpoint filename="groundstate_break.xsil" format="ascii">
+      <dependencies basis="ky">wavefunction</dependencies>
+    </breakpoint>
+  </sequence>
+
+  <output filename="groundstate.xsil">
+      <sampling_group basis="y" initial_sample="no">
+        <moments>norm_dens</moments>
+        <dependencies>wavefunction normalisation</dependencies>
+        <![CDATA[
+          norm_dens = mod2(phi)/Ncalc;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="" initial_sample="no">
+        <moments>ER E_over_NR NR muR</moments>
+        <dependencies>energy normalisation</dependencies>
+        <![CDATA[
+        ER = E;
+        E_over_NR = E_over_N;
+        NR = Ncalc;
+        muR = mu;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/groundstate_gaussian.xmds b/examples/groundstate_gaussian.xmds
new file mode 100644
index 0000000..9d3064e
--- /dev/null
+++ b/examples/groundstate_gaussian.xmds
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>groundstate_gaussian</name>
+  <author>Graham Dennis</author>
+  <description>
+    Calculate the ground state of a negative gaussian potential.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="1024"  domain="(-12.0, 12.0)" aliases="yp" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" initial_basis="y" type="complex">
+    <components> V1 </components>
+    <initialisation>
+      <![CDATA[
+        real Vtrap = -exp(-y*y);
+      
+        V1  = -i*Vtrap;
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" initial_basis="y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+      
+      // This will be automatically normalised later
+      phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components> Ncalc </components>
+    <evaluation>
+      <dependencies basis="y">wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="10.0" steps="10000" tolerance="1e-8">
+      <samples>50 50 1</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi *= sqrt(1.0/Ncalc);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes" type="real">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] - (i*V1)*phi;
+        ]]>
+      </operators>
+    </integrate>
+    
+    <breakpoint filename="groundstate_gaussian_break.xsil" format="hdf5">
+      <dependencies>wavefunction potential</dependencies>
+    </breakpoint>
+  </sequence>
+
+  <output>
+      <sampling_group basis="y" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+
+      <sampling_group initial_sample="no">
+        <moments>N</moments>
+        <dependencies>normalisation</dependencies>
+        <![CDATA[
+          N = Ncalc;
+        ]]>
+      </sampling_group>
+
+      <sampling_group basis="y yp" initial_sample="no">
+        <moments>g1R g1I g2</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          complex g1 = conj(phi(y => y)) * phi(y => yp);
+          _SAMPLE_COMPLEX(g1);
+          g2 = mod2(phi(y => y)) * mod2(phi(y => yp));
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/groundstate_workedexamples.xmds b/examples/groundstate_workedexamples.xmds
new file mode 100644
index 0000000..a2fca2d
--- /dev/null
+++ b/examples/groundstate_workedexamples.xmds
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>groundstate</name>
+  <author>Joe Hope</author>
+  <description>
+    Calculate the ground state of the non-linear Schrodinger equation in a harmonic magnetic trap.
+    This is done by evolving it in imaginary time while re-normalising each timestep.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <fftw plan="exhaustive" />
+    <globals>
+      <![CDATA[
+        const real Uint = 2.0;
+        const real Nparticles = 5.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="256"  domain="(-15.0, 15.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" initial_basis="y" type="real">
+    <components> V1 </components>
+    <initialisation>
+      <![CDATA[
+        V1  = 0.5*y*y;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" initial_basis="y" type="complex">
+    <components> phi </components>
+    <initialisation>
+      <![CDATA[
+        if (fabs(y) < 3.0) {
+          phi = 1.0;
+          // This will be automatically normalised later
+        } else {
+          phi = 0.0;
+        }
+            ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components> Ncalc </components>
+    <evaluation>
+      <dependencies basis="y">wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+      <filter>
+        <![CDATA[
+          printf("Hello world from a filter segment!\n");
+        ]]>
+      </filter>
+
+    <filter>
+        <dependencies>normalisation wavefunction</dependencies>
+      <![CDATA[
+        phi *= sqrt(Nparticles/Ncalc);
+      ]]>
+    </filter>
+
+    <integrate algorithm="ARK45" interval="1.0" steps="4000" tolerance="1e-10">
+      <samples>25 4000</samples>
+      <filters where="step end">
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi *= sqrt(Nparticles/Ncalc);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] - (V1 + Uint*mod2(phi))*phi;
+        ]]>
+      </operators>
+    </integrate>
+
+    <breakpoint filename="groundstate_break.xsil" format="ascii">
+      <dependencies basis="ky">wavefunction </dependencies>
+    </breakpoint>
+
+  </sequence>
+
+  <output filename="groundstate.xsil">
+      <sampling_group basis="y" initial_sample="yes">
+        <moments>norm_dens</moments>
+        <dependencies>wavefunction normalisation</dependencies>
+        <![CDATA[
+          norm_dens = mod2(phi);
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes">
+        <moments>norm</moments>
+        <dependencies>normalisation</dependencies>
+        <![CDATA[
+          norm = Ncalc;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/halt_non_finite.xmds b/examples/halt_non_finite.xmds
new file mode 100644
index 0000000..2c18c2a
--- /dev/null
+++ b/examples/halt_non_finite.xmds
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>halt_non_finite</name>
+  <author>Gabriel McManus</author>
+  <description>
+    An ODE with NaN derivatives.
+    Used to test the halt_non_finite feature.
+  </description>
+  
+  <features>
+    <benchmark />
+    <halt_non_finite />
+    <globals>
+      <![CDATA[
+      const real x0 = 1.0;
+      const real t0 = 1.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <vector name="main" type="real">
+    <components> x </components>
+    <initialisation>
+      <![CDATA[
+      x = x0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="2" steps="10000" tolerance="1e-5">
+      <samples>200</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dx_dt = sqrt(t0 - t);
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output>
+      <sampling_group initial_sample="yes">
+        <moments>xOut</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          xOut = x;
+        ]]>
+      </sampling_group>
+  </output>
+  
+</simulation>
diff --git a/examples/hermitegauss_groundstate.xmds b/examples/hermitegauss_groundstate.xmds
new file mode 100644
index 0000000..92be60e
--- /dev/null
+++ b/examples/hermitegauss_groundstate.xmds
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>hermitegauss_groundstate</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve for the groundstate of the Gross-Pitaevskii equation using the hermite-Gauss basis.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <validation kind="run-time" />
+    <globals>
+      <![CDATA[
+        const real omegaz = 2*M_PI*20;
+        const real omegarho = 2*M_PI*200;
+        const real hbar = 1.05457148e-34;
+        const real M = 1.409539200000000e-25;
+        const real g = 9.8;
+        const real scatteringLength = 5.57e-9;
+        const real transverseLength = 1e-5;
+        const real Uint = 4.0*M_PI*hbar*hbar*scatteringLength/M/transverseLength/transverseLength;
+        const real Nparticles = 5.0e5;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="81" spectral_lattice="40" length_scale="sqrt(hbar/(M*omegarho))" transform="hermite-gauss" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="wavefunction" initial_basis="x" type="complex">
+    <components> phi </components>
+    <initialisation>
+      <![CDATA[
+      real eta = sqrt(M*omegarho/hbar)*x;
+      phi = sqrt(Nparticles) * pow(M*omegarho/(hbar*M_PI), 0.25) * exp(-0.5*eta*eta);
+        ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components> Ncalc </components>
+    <evaluation>
+      <dependencies basis="x">wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="2.0e-3" steps="4000"  tolerance="1e-10">
+      <samples>100 100</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi *= sqrt(Nparticles/Ncalc);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes" type="real">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = - (nx + 0.5)*omegarho;
+          ]]>
+        </operator>
+        <!-- The 'x_4f' basis permits exact calculation of |psi|^2 psi provided that lattice="2N+1" with spectral_lattice="N" -->
+        <!-- If there were other terms in the integration code, the nonlinear term could be calculated exactly in a computed vector -->
+        <!-- See the example NLProjection.xmds for an example. -->
+        <integration_vectors basis="x_4f">wavefunction</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi] - Uint/hbar*mod2(phi)*phi;
+        ]]>
+      </operators>
+    </integrate>
+
+    <filter>
+        <dependencies>normalisation wavefunction</dependencies>
+      <![CDATA[
+        phi *= sqrt(Nparticles/Ncalc);
+      ]]>
+    </filter>
+    
+    <breakpoint filename="hermitegauss_groundstate_break.xsil" format="ascii">
+      <dependencies basis="nx">wavefunction</dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output>
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/hermitegauss_transform.xmds b/examples/hermitegauss_transform.xmds
new file mode 100644
index 0000000..ee6dd39
--- /dev/null
+++ b/examples/hermitegauss_transform.xmds
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>hermitegauss_transform</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the Schroedinger equation using the hermite-Gauss basis.
+  </description>
+  
+  <features>
+    <benchmark />
+    <!-- <error_check /> -->
+    <bing />
+    <globals>
+      <![CDATA[
+        const real offset = 1.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="30" spectral_lattice="20" length_scale="1.0" transform="hermite-gauss" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+        psi = pow(M_PI, -0.25) * exp(-0.25*(x - offset)*(x - offset));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" tolerance="1e-6" interval="10." steps="100">
+      <samples>100 100 100</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="nx">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*(nx + 0.5);
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dpsi_dt = L[psi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output>
+      <sampling_group basis="x" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="nx" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/hermitegauss_transform_2d.xmds b/examples/hermitegauss_transform_2d.xmds
new file mode 100644
index 0000000..e870570
--- /dev/null
+++ b/examples/hermitegauss_transform_2d.xmds
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>hermitegauss_transform_2d</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the Schroedinger equation using the hermite-Gauss basis.
+  </description>
+  
+  <features>
+    <benchmark />
+    <!-- <error_check /> -->
+    <bing />
+    <validation kind="run-time" />
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="20" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+      <dimension name="y" lattice="20" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+      psi = pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.5*(M*omega/hbar)*(x - offset)*(x - offset));
+      psi *= pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.25*(M*omega/hbar)*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>N integral_y2</components>
+    <evaluation>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        N = mod2(psi);
+        integral_y2 = mod2(psi)*y*y;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-6" interval="1e-3" steps="400">
+      <samples>10 1 100</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="nx ny">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*(nx + ny + 1.0)*omega;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dpsi_dt = L[psi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output>
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="nx ny" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(0)" initial_sample="yes">
+        <moments>mean_x mean_sigmay</moments>
+        <dependencies>main normalisation</dependencies>
+        <![CDATA[
+          mean_x = mod2(psi)*x/N;
+          mean_sigmay = sqrt(integral_y2/N);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/hermitegauss_transform_2d_mpi.xmds b/examples/hermitegauss_transform_2d_mpi.xmds
new file mode 100644
index 0000000..69334d5
--- /dev/null
+++ b/examples/hermitegauss_transform_2d_mpi.xmds
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>hermitegauss_transform_2d_mpi</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the Schroedinger equation using the hermite-Gauss basis.
+  </description>
+  
+  <features>
+    <benchmark />
+    <!-- <error_check /> -->
+    <bing />
+    <validation kind="run-time" />
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="200" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+      <dimension name="y" lattice="200" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+      psi = pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.5*(M*omega/hbar)*(x - offset)*(x - offset));
+      psi *= pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.25*(M*omega/hbar)*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>N integral_y2</components>
+    <evaluation>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        N = mod2(psi);
+        integral_y2 = mod2(psi)*y*y;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" tolerance="1e-6" interval="1e-3" steps="400">
+      <samples>10 1 10</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="nx ny">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*(nx + ny + 1.0)*omega;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dpsi_dt = L[psi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output>
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx ky" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(0)" initial_sample="yes">
+        <moments>mean_x mean_sigmay</moments>
+        <dependencies>main normalisation</dependencies>
+        <![CDATA[
+          mean_x = mod2(psi)*x/N;
+          mean_sigmay = sqrt(integral_y2/N);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/integer_dimensions.xmds b/examples/integer_dimensions.xmds
new file mode 100644
index 0000000..08f0f22
--- /dev/null
+++ b/examples/integer_dimensions.xmds
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>integer_dimensions</name>
+  <author>Graham Dennis</author>
+  <description>
+    XMDS2 script to test integer dimensions.
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <diagnostics /> <!-- This will make sure that all nonlocal accesses of dimensions are safe -->
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" type="integer" lattice="5" domain="(0,4)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" type="complex">
+    <components> x </components>
+    <initialisation>
+      <![CDATA[
+      x = 1.0e-3;
+      x(j => 0) = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="60" steps="25000" tolerance="1.0e-9">
+      <samples>1000</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        long j_minus_one = (j-1) % _lattice_j;
+        if (j_minus_one < 0)
+          j_minus_one += _lattice_j;
+        long j_plus_one  = (j+1) % _lattice_j;
+        dx_dt(j => j) = x(j => j)*(x(j => j_minus_one) - x(j => j_plus_one));
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="ascii">
+      <sampling_group basis="j" initial_sample="yes">
+        <moments>xR</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          xR = x.Re();
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/examples/integer_dimensions_with_runtime_lattice.xmds b/examples/integer_dimensions_with_runtime_lattice.xmds
new file mode 100644
index 0000000..2c3062d
--- /dev/null
+++ b/examples/integer_dimensions_with_runtime_lattice.xmds
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>integer_dimensions_with_runtime_lattice</name>
+  <author>Graham Dennis</author>
+  <description>
+    XMDS2 script to test integer dimensions.
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <diagnostics /> <!-- This will make sure that all nonlocal accesses of dimensions are safe -->
+	<validation kind="run-time" />
+	<arguments>
+		<argument name="j_max" type="integer" default_value="10" />
+	</arguments>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" type="integer" lattice="11" domain="(0,j_max)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" type="complex">
+    <components> x </components>
+    <initialisation>
+      <![CDATA[
+      x = 1.0e-3;
+      x(j => 0) = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="60" steps="25000" tolerance="1.0e-9">
+      <samples>1000</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        long j_minus_one = (j-1) % _lattice_j;
+        if (j_minus_one < 0)
+          j_minus_one += _lattice_j;
+        long j_plus_one  = (j+1) % _lattice_j;
+        dx_dt(j => j) = x(j => j)*(x(j => j_minus_one) - x(j => j_plus_one));
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="hdf5">
+      <sampling_group basis="j" initial_sample="yes">
+        <moments>xR</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          xR = x.Re();
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/examples/kubo.xmds b/examples/kubo.xmds
new file mode 100644
index 0000000..92c3eaa
--- /dev/null
+++ b/examples/kubo.xmds
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>kubo</name>
+  <author>Graham Dennis</author>
+  <description>
+    Example Kubo oscillator simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <driver name="multi-path" paths="10000" />
+  
+  <features>
+    <error_check />
+    <benchmark />
+  </features>
+
+  <noise_vector name="drivingNoise" kind="wiener" type="real" method="dsfmt">
+    <components>eta</components>
+  </noise_vector>
+  
+  <vector name="main" type="complex">
+    <components> z </components>
+    <initialisation>
+      <![CDATA[
+        z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="SI" interval="10" steps="1000">
+      <samples>100</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>drivingNoise</dependencies>
+        <![CDATA[
+          dz_dt = i*z*eta;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+
+  <output format="ascii">
+      <sampling_group initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          zR = z.Re();
+          zI = z.Im();
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/kubo_integer_dimensions.xmds b/examples/kubo_integer_dimensions.xmds
new file mode 100644
index 0000000..a854a4a
--- /dev/null
+++ b/examples/kubo_integer_dimensions.xmds
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>kubo_integer_dimensions</name>
+  <author>Graham Dennis</author>
+  <description>
+    Example Kubo oscillator simulation
+  </description>
+  
+  <features>
+    <!-- <auto_vectorise /> -->
+    <benchmark />
+    <error_check />
+    <bing />
+
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" type="integer" lattice="10240" domain="(1, 10240)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <noise_vector name="noises" kind="wiener" type="real" method="posix" seed="157 9348 234">
+        <components>n_1</components>
+  </noise_vector>
+    
+  <vector name="main" type="complex">
+    <components> z </components>
+    <initialisation>
+      <![CDATA[
+        z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="SI" interval="10" steps="1000">
+      <samples>100</samples>
+      <operators>
+        <dependencies>noises</dependencies>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dz_dt(j => j) = i*z*n_1;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output>
+      <sampling_group basis="j(0)" initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          zR = z.Re()/_lattice_j;
+          zI = z.Im()/_lattice_j;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/kubo_integer_dimensions_mpi.xmds b/examples/kubo_integer_dimensions_mpi.xmds
new file mode 100644
index 0000000..c2e8245
--- /dev/null
+++ b/examples/kubo_integer_dimensions_mpi.xmds
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>kubo_integer_dimensions_mpi</name>
+  <author>Graham Dennis</author>
+  <description>
+    Example Kubo oscillator simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" type="integer" lattice="10240" domain="(1, 10240)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <features>
+    <benchmark />
+    <!-- <error_check /> -->
+    <bing />
+  </features>
+
+  <noise_vector name="noises" kind="wiener" type="real" method="posix" seed="157 9348 234">
+        <components>n_1</components>
+  </noise_vector>
+    
+  <vector name="main" type="complex">
+    <components>
+      z
+    </components>
+    <initialisation>
+      <![CDATA[
+        if (_index_j == 1)
+          _LOG(_WARNING_LOG_LEVEL, "_local_lattice_j: %li, _local_offset_j: %li\n", _local_lattice_j, _local_offset_j);
+        z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="SI" interval="10" steps="1000">
+      <samples>500 10</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>noises</dependencies>
+        <![CDATA[
+          dz_dt(j => j) = i*z*n_1;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="kubo_integer_dimensions_mpi_break.xsil">
+      <dependencies>main</dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output>
+      <sampling_group basis="j(0)" initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          zR = z.Re()/_lattice_j;
+          zI = z.Im()/_lattice_j;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="j" initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          zR = z.Re();
+          zI = z.Im();
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/lorenz.xmds b/examples/lorenz.xmds
new file mode 100644
index 0000000..16731f7
--- /dev/null
+++ b/examples/lorenz.xmds
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>lorenz</name>
+  
+  <!-- While not strictly necessary, the following two tags are handy. -->
+  <author>Graham Dennis</author>
+  <description>
+    The Lorenz Attractor, an example of chaos.
+  </description>
+  
+  <!-- 
+  This element defines some constants.  It can be used for other 
+  features as well, but we will go into that in more detail later.
+  -->
+  <features>
+    <globals>
+        <![CDATA[
+        real sigma = 10.0;
+        real b = 8.0/3.0;
+        real r = 28.0;
+        ]]>
+     </globals>
+   </features>
+   
+  <!-- 
+  This part defines all of the dimensions used in the problem,
+  in this case, only the dimension of 'time' is needed.
+  -->
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <!-- A 'vector' describes the variables that we will be evolving. -->
+  <vector name="position" type="real">
+    <components>
+      x y z
+    </components>
+    <initialisation>
+      <![CDATA[
+      x = y = z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <!--
+    Here we define what differential equations need to be solved
+    and what algorithm we want to use.
+    -->
+    <integrate algorithm="ARK89" interval="20.0" tolerance="1e-7">
+      <samples>5000</samples>
+      <operators>
+        <integration_vectors>position</integration_vectors>
+        <![CDATA[
+        dx_dt = sigma*(y-x);
+        dy_dt = r*x - y - x*z;
+        dz_dt = x*y - b*z;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <!-- This part defines what data will be saved in the output file -->
+  <output>
+    <sampling_group initial_sample="yes">
+      <moments>xR yR zR</moments>
+      <dependencies>position</dependencies>
+      <![CDATA[
+        xR = x;
+        yR = y;
+        zR = z;
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/lorenz_arguments.xmds b/examples/lorenz_arguments.xmds
new file mode 100644
index 0000000..eafa779
--- /dev/null
+++ b/examples/lorenz_arguments.xmds
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>lorenz_arguments</name>
+  <author>Mattias Johnsson</author>
+  <description>
+    First script to test command line argument passing.
+    Can accept an integration interval as the argument "time_arg"
+    Othewise the same as the lorenz script
+  </description>
+  
+  <features>
+    <arguments>
+      <argument name="sigma" type="real" default_value="10.0" />
+      <argument name="b"     type="real" default_value="2.67" />
+      <argument name="r"     type="real" default_value="28.0" />
+      <argument name="time_arg" type="real" default_value="100.0" />
+    </arguments>
+    <benchmark />
+    <error_check />
+    <bing />
+    <validation kind="run-time" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <vector name="position" type="real">
+    <components>
+      x y z
+    </components>
+    <initialisation>
+      <![CDATA[
+      x = y = z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" interval="1.0*time_arg" steps="25000" tolerance="1e-7">
+      <samples>10</samples>
+      <operators>
+        <integration_vectors>position</integration_vectors>
+        <![CDATA[
+        dx_dt = sigma*(y-x);
+        dy_dt = r*x - y - x*z;
+        dz_dt = x*y - b*z;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output>
+    <sampling_group initial_sample="yes">
+      <moments>xR yR zR</moments>
+      <dependencies>position</dependencies>
+      <![CDATA[
+        xR = x;
+        yR = y;
+        zR = z;
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/lorenz_code.txt b/examples/lorenz_code.txt
new file mode 100644
index 0000000..ec34a57
--- /dev/null
+++ b/examples/lorenz_code.txt
@@ -0,0 +1,5 @@
+<![CDATA[
+        dx_dt = sigma*(y-x);
+        dy_dt = r*x - y - x*z;
+        dz_dt = x*y - b*z;
+]]>
\ No newline at end of file
diff --git a/examples/lorenz_entity.xmds b/examples/lorenz_entity.xmds
new file mode 100644
index 0000000..fca7b83
--- /dev/null
+++ b/examples/lorenz_entity.xmds
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE simulation [
+<!ENTITY SimulationCode SYSTEM "lorenz_code.txt" >
+]>
+<simulation xmds-version="2">
+  <name>lorenz</name>
+  
+  <!-- While not strictly necessary, the following two tags are handy. -->
+  <author>Graham Dennis</author>
+  <description>
+    The Lorenz Attractor, an example of chaos.
+  </description>
+  
+  <!-- 
+  This element defines some constants.  It can be used for other 
+  features as well, but we will go into that in more detail later.
+  -->
+  <features>
+    <globals>
+        <![CDATA[
+        real sigma = 10.0;
+        real b = 8.0/3.0;
+        real r = 28.0;
+        ]]>
+     </globals>
+   </features>
+   
+  <!-- 
+  This part defines all of the dimensions used in the problem,
+  in this case, only the dimension of 'time' is needed.
+  -->
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <!-- A 'vector' describes the variables that we will be evolving. -->
+  <vector name="position" type="real">
+    <components>
+      x y z
+    </components>
+    <initialisation>
+      <![CDATA[
+      x = y = z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <!--
+    Here we define what differential equations need to be solved
+    and what algorithm we want to use.
+    -->
+    <integrate algorithm="ARK89" interval="20.0" tolerance="1e-7">
+      <samples>5000</samples>
+      <operators>
+        <integration_vectors>position</integration_vectors>
+              &SimulationCode;
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <!-- This part defines what data will be saved in the output file -->
+  <output>
+    <sampling_group initial_sample="yes">
+      <moments>xR yR zR</moments>
+      <dependencies>position</dependencies>
+      <![CDATA[
+        xR = x;
+        yR = y;
+        zR = z;
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/lorenz_lyap.xmds b/examples/lorenz_lyap.xmds
new file mode 100644
index 0000000..0d5a29b
--- /dev/null
+++ b/examples/lorenz_lyap.xmds
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>lorenz_lyap</name>
+  <author>Andre Carvalho and Graham Dennis</author>
+  <description>
+    The Lorenz Attractor, an example of chaos. Includes the calculation of the largest Lyapunov exponent.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <globals>
+      <![CDATA[
+      real sigma = 10.0;
+      real b = 8.0/3.0;
+      real r = 28.0;
+      real d0 = 1.0e-8; // separation between the main path and the 'test' path
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <vector name="position" type="real">
+    <components>
+      x y z xe ye ze
+    </components>
+    <initialisation>
+      <![CDATA[
+      x = 1.;
+      y = 1.;
+      z = 1.;
+      xe= x + d0;
+      ye= y;
+      ze= z;
+      ]]>
+    </initialisation>
+  </vector>
+  
+   <!-- Calculate the Lyapunov Exponent -->
+   <vector type="real" name="lyapunov" dimensions="">
+    <components>lyap</components>
+  </vector>
+  <!-- **************************-->   
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="100000.0" steps="10000000" tolerance="1e-8">
+      <samples>5000 100</samples>
+      <!-- 
+        At the end of a step, we need to work out how far the two paths have separated,
+        reset the separation to d0 and calculate the contribution to the lyapunov exponent.
+      -->
+      <filters where="step end">
+        <filter>
+            <dependencies>position lyapunov</dependencies>
+            <![CDATA[
+                real dlx=(xe - x);
+                real dly=(ye - y);
+                real dlz=(ze - z);
+                real d1 = sqrt(dlx*dlx + dly*dly + dlz*dlz);
+                real df = d1/d0;
+                xe = x + (xe-x)/df;
+                ye = y + (ye-y)/df;
+                ze = z + (ze-z)/df;
+                lyap += log(df);
+            ]]>
+        </filter>
+      </filters>
+
+      <operators>
+        <integration_vectors>position</integration_vectors>
+        <![CDATA[
+        dx_dt = sigma*(y-x);
+        dy_dt = r*x - y - x*z;
+        dz_dt = x*y - b*z;
+        dxe_dt = sigma*(ye-xe);
+        dye_dt = r*xe - ye - xe*ze;
+        dze_dt = xe*ye - b*ze;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output>
+      <sampling_group initial_sample="yes">
+        <moments>xR yR zR le</moments>
+        <dependencies>position lyapunov</dependencies>
+        <![CDATA[
+          xR = x;
+          yR = y;
+          zR = z;
+          le=lyap/t; // This value should asymptotically approach ~0.906
+        ]]>
+      </sampling_group>
+	
+      <sampling_group initial_sample="yes">
+        <moments>distance</moments>
+        <dependencies>position</dependencies>
+        <![CDATA[
+          distance = sqrt(x*x + y*y +z*z);
+        ]]>
+      </sampling_group>
+
+  </output>
+</simulation>
diff --git a/examples/lorenz_minimal.xmds b/examples/lorenz_minimal.xmds
new file mode 100644
index 0000000..ab4f9d9
--- /dev/null
+++ b/examples/lorenz_minimal.xmds
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>lorenz_minimal</name>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <vector name="position" type="real">
+    <components>
+      x y z
+    </components>
+    <initialisation>
+      <![CDATA[
+      x = y = z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" interval="10.0" tolerance="1e-7">
+      <samples>100</samples>
+      <operators>
+        <integration_vectors>position</integration_vectors>
+        <![CDATA[
+        dx_dt = 10.0*(y-x);
+        dy_dt = 28.0*x - y - x*z;
+        dz_dt = x*y - 8.0/3.0*z;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output>
+    <sampling_group>
+      <moments>xR yR zR</moments>
+      <dependencies>position</dependencies>
+      <![CDATA[
+        xR = x;
+        yR = y;
+        zR = z;
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/lorenz_single.xmds b/examples/lorenz_single.xmds
new file mode 100644
index 0000000..8c7922a
--- /dev/null
+++ b/examples/lorenz_single.xmds
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>lorenz_single</name>
+  <author>Graham Dennis</author>
+  <description>
+    The Lorenz Attractor, an example of chaos.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <error_check />
+    <bing />
+    <precision>single</precision>
+    <diagnostics />
+    <globals>
+      <![CDATA[
+      real sigma = 10.0;
+      real b = 8.0/3.0;
+      real r = 28.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <vector name="main" type="real">
+    <components>
+      x y z
+    </components>
+    <initialisation>
+      <![CDATA[
+      x = y = z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="100.0" steps="25000" tolerance="3e-5">
+      <samples>5000</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        dx_dt = sigma*(y-x);
+        dy_dt = r*x - y - x*z;
+        dz_dt = x*y - b*z;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output>
+    <sampling_group initial_sample="yes">
+      <moments>xR yR zR</moments>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        xR = x;
+        yR = y;
+        zR = z;
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/nlse.xmds b/examples/nlse.xmds
new file mode 100644
index 0000000..4f37011
--- /dev/null
+++ b/examples/nlse.xmds
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>nlse</name>
+
+  <author>Joe Hope</author>
+  <description>
+    The nonlinear Schrodinger equation in one dimension, 
+    which is a simple partial differential equation.  
+    We introduce several new features in this script.
+  </description>
+
+  <features>
+      <benchmark />
+      <bing />
+      <fftw plan="patient" />
+
+      <auto_vectorise />
+      <globals>
+          <![CDATA[
+          const double energy = 4;
+          const double vel = 0.3;
+          const double hwhm = 1.0;
+          ]]>
+       </globals>
+     </features>
+
+  <geometry>
+      <propagation_dimension> xi </propagation_dimension>
+      <transverse_dimensions>
+        <dimension name="tau" lattice="128"  domain="(-6, 6)" />
+      </transverse_dimensions>
+   </geometry>
+
+  <vector name="wavefunction" type="complex" dimensions="tau">
+    <components> phi </components>
+    <initialisation>
+      <![CDATA[
+      const double w0 = hwhm*sqrt(2/log(2));
+      const double amp = sqrt(energy/w0/sqrt(M_PI/2));
+      phi = amp*exp(-tau*tau/w0/w0)*exp(i*vel*tau);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <vector name="dampingVector" type="real">
+    <components> Gamma </components>
+    <initialisation>
+      <![CDATA[
+      Gamma=1.0*(1-exp(-pow(tau*tau/4.0/4.0,10)));
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <integrate algorithm="ARK45" interval="20.0" tolerance="1e-7">
+      <samples>10 100 10</samples>
+      <operators>
+        <integration_vectors>wavefunction</integration_vectors>
+        <operator kind="ex" constant="yes">
+          <operator_names>Ltt</operator_names>
+          <![CDATA[
+            Ltt = -i*ktau*ktau*0.5;
+          ]]>
+        </operator>
+        <![CDATA[
+        dphi_dxi = Ltt[phi] - phi*Gamma + i*mod2(phi)*phi;
+        ]]>
+        <dependencies>dampingVector</dependencies>
+      </operators>
+    </integrate>
+  </sequence>
+
+  <output>
+      <sampling_group basis="tau" initial_sample="yes">
+        <moments>density</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          density = mod2(phi);
+        ]]>
+      </sampling_group>
+
+      <sampling_group basis="tau(0)" initial_sample="yes">
+        <moments>normalisation</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          normalisation = mod2(phi);
+        ]]>
+      </sampling_group>
+
+      <sampling_group basis="ktau(32)" initial_sample="yes">
+        <moments>densityK</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          densityK = mod2(phi);
+        ]]>
+      </sampling_group>
+
+  </output>
+</simulation>
+
diff --git a/examples/photodetector.xmds b/examples/photodetector.xmds
new file mode 100644
index 0000000..3435c3b
--- /dev/null
+++ b/examples/photodetector.xmds
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>photodetector</name>
+  <author>Graham Dennis</author>
+  <description>
+    Example Poissonian noise simulation
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <!-- <fftw /> -->
+
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+
+  <noise_vector name="noises" kind="jump" mean-rate="5.0" type="real" method="posix" seed="314 159 276">
+        <components>nn</components>
+  </noise_vector>
+  
+  <vector name="main" type="real">
+    <components> N </components>
+    <initialisation>
+      <![CDATA[
+        N = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="10" steps="1000">
+      <samples>1000</samples>
+      <operators>
+        <dependencies>noises</dependencies>
+        <![CDATA[
+          dN_dt = nn;
+        ]]>
+        <integration_vectors>main</integration_vectors>
+      </operators>
+    </integrate>
+  </sequence>
+  <output>
+      <sampling_group initial_sample="yes">
+        <moments>Ndet</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          Ndet = N;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/schroedinger_gaussian.xmds b/examples/schroedinger_gaussian.xmds
new file mode 100644
index 0000000..a4dbd23
--- /dev/null
+++ b/examples/schroedinger_gaussian.xmds
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>schroedinger_gaussian</name>
+  <author>Graham Dennis</author>
+  <description>
+    Evolve a superposition of the groundstate and first excited state.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <chunked_output size="1Mb" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="1024"  domain="(-12.0, 12.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" initial_basis="y" type="complex">
+    <components>
+      V1
+    </components>
+    <initialisation kind="hdf5">
+      <!-- Use the same potential as the previous simulation -->
+      <filename>groundstate_gaussian_break.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="excitedstate" initial_basis="y" type="complex">
+    <components>
+      phi1
+    </components>
+    <initialisation kind="hdf5">
+      <filename>excitedstate_gaussian_break.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="groundstate" initial_basis="y" type="complex">
+    <components>phi</components>
+    <initialisation kind="hdf5">
+      <filename>groundstate_gaussian_break.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components>psi</components>
+    <initialisation>
+      <dependencies>excitedstate groundstate</dependencies>
+      <![CDATA[
+        psi = 1.0/sqrt(2.0) * (phi1 + phi);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK9" interval="10.0" steps="10000" tolerance="1e-8">
+      <samples>500 500</samples>
+      <operators>
+        <operator kind="ip" constant="no" type="imaginary">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*i*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dpsi_dt = T[psi] + V1*psi;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output>
+      <sampling_group basis="y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="y" initial_sample="yes">
+        <moments>T V</moments>
+        <dependencies>wavefunction potential</dependencies>
+        <operator kind="ex">
+            <operator_names>L</operator_names>
+            <![CDATA[
+                L = i*ky;
+            ]]>
+        </operator>
+        <![CDATA[
+            // Calculate the potential energy at each point
+            V = (-V1.Im()) * mod2(psi);
+            // Calculate the kinetic energy at each point
+            T = 0.5*mod2(L[psi]);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/examples/sech_soliton.xmds b/examples/sech_soliton.xmds
new file mode 100644
index 0000000..802f2ae
--- /dev/null
+++ b/examples/sech_soliton.xmds
@@ -0,0 +1,63 @@
+<simulation xmds-version="2">
+  <name>sech_soliton</name>
+  
+  <author>Sebastian Wuster / Graham Dennis</author>
+  <description>
+    Nonlinear Schrodinger equation with attractive interactions.
+    This equation has an analytic solution of the form of a breathing soliton.
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="4096"  domain="(-4.0, 4.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <features>
+    <auto_vectorise />
+    <fftw />
+    <globals>
+      <![CDATA[
+      const double N = 3.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <vector name="wavefunction" initial_basis="x" type="complex">
+    <components>psi</components>
+    <initialisation>
+      <![CDATA[
+        psi = N/cosh(x);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="1.570796327" tolerance="1e-6">
+      <samples>200</samples>
+      <operators>
+        <operator kind="ip">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.5*i*kx*kx;
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <![CDATA[
+          dpsi_dt = L[psi] + i*mod2(psi)*psi;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output>
+      <sampling_group basis="x(512)" initial_sample="yes">
+        <moments>density</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          density = mod2(psi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/sine_cross.xmds b/examples/sine_cross.xmds
new file mode 100644
index 0000000..b0a4525
--- /dev/null
+++ b/examples/sine_cross.xmds
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>sine_cross</name>
+  <author>Graham Dennis</author>
+  <description>
+    Sine cross-propagation validity tests.
+    
+    The 'u' variable checks for errors caused by poorly interpolating
+    dependencies. The 'v' variable checks for errors just in the
+    cross-propagation algorithm. The 'w' variable checks for errors due
+    to IP cross-propagation (should be the smallest). The 'x' variable checks
+    for errors due to EX cross-propagation, they should be the same as 'v'.
+    You can choose the cross-propagation algorithm to be either 'SI' or 'RK4'.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <!-- That's right, this script breaks the shackles with FFTW! -->
+  </features>
+  
+  <geometry>
+    <propagation_dimension> z </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="t" lattice="128"  domain="(0, 10)" transform="none" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" type="complex">
+    <components>
+      foo
+    </components>
+    <initialisation>
+      <![CDATA[
+      foo = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="constants" type="real">
+    <components>cosine</components>
+    <initialisation>
+      <![CDATA[
+        cosine = cos(t);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="cross" type="complex">
+    <components>u v w x</components>
+    <initialisation>
+      <![CDATA[
+        u = 0.0;
+        v = 1.0;
+        w = 1.0;
+        x = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK9" interval="1" steps="2">
+      <samples>1</samples>
+      <operators>
+        <operator kind="cross_propagation" algorithm="SI" propagation_dimension="t">
+          <integration_vectors>cross</integration_vectors>
+          <dependencies>constants</dependencies>
+          <boundary_condition kind="left">
+            <![CDATA[
+              u = 0.0;
+              v = 1.0;
+              w = 1.0;
+              x = 1.0;
+            ]]>
+          </boundary_condition>
+          
+          <operator kind="ip" constant="yes">
+            <operator_names>L</operator_names>
+            <![CDATA[
+              L = i;
+            ]]>
+          </operator>
+          
+          <operator kind="ex" constant="yes">
+            <operator_names>M</operator_names>
+            <![CDATA[
+              M = i;
+            ]]>
+          </operator>
+          
+          <![CDATA[
+            du_dt = cosine;
+            dv_dt = i*v;
+            dw_dt = L[w]; // this one is pretty much exact
+            dx_dt = M[x];
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        dfoo_dz = 0.0;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="ascii">
+      <sampling_group basis="t" initial_sample="no">
+        <moments>error_u error_v error_w error_x</moments>
+        <dependencies>cross</dependencies>
+        <![CDATA[
+          error_u = abs(u - sin(t));
+          error_v = abs(v - polar(1.0, t));
+          error_w = abs(w - polar(1.0, t));
+          error_x = abs(x - polar(1.0, t));
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/tla.xmds b/examples/tla.xmds
new file mode 100644
index 0000000..5ea50ff
--- /dev/null
+++ b/examples/tla.xmds
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>tla</name>
+  <author>Unknown</author>
+  <description>
+    Two level atom example simulation. Illustrates a cross-propagating field.
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw plan="patient" />
+    <globals>
+      <![CDATA[
+      const real g = 1.0;
+      const real t0 = 1.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> z </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="t" lattice="10000"  domain="(-10, 15)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="t" type="real">
+    <components>
+      E
+    </components>
+    <initialisation>
+      <![CDATA[
+        E = 2/t0/cosh(t/t0);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <vector name="cross" initial_basis="t" type="real">
+    <components>
+      P N
+    </components>
+    <initialisation>
+      <![CDATA[
+        P = 0.0;
+        N = -1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="4" steps="200">
+      <samples>100 100</samples>
+      <operators>
+        <operator kind="cross_propagation" algorithm="RK4" propagation_dimension="t">
+          <integration_vectors>cross</integration_vectors>
+          <!-- You can have a dependencies tag in here -->
+          <dependencies>main</dependencies>
+          <boundary_condition kind="left">
+            <!-- You can also have a dependencies tag in here -->
+            <!-- like the one shown below, but none are needed -->
+            <!-- in this example -->
+            <!-- <dependencies>cross</dependencies> -->
+            <![CDATA[
+              P = 0.0;
+              N = -1.0;
+            ]]>
+          </boundary_condition>
+          <![CDATA[
+            dP_dt = E*N;
+            dN_dt = -E*P;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dE_dz = g*P;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output>
+      <sampling_group basis="t(1000)" initial_sample="yes">
+        <moments>pow_dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          pow_dens = E*E;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="t(1000)" initial_sample="no">
+        <moments>P_out N_out</moments>
+        <dependencies>cross</dependencies>
+        <![CDATA[
+          P_out = P;
+          N_out = N;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/tla_sic.xmds b/examples/tla_sic.xmds
new file mode 100644
index 0000000..930db1a
--- /dev/null
+++ b/examples/tla_sic.xmds
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>tla_sic</name>
+  <author>Unknown</author>
+  <description>
+    Two level atom example simulation. Illustrates a cross-propagating field.
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw plan="patient" />
+    <globals>
+      <![CDATA[
+      const real g = 1.0;
+      const real t0 = 1.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> z </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="t" lattice="10000"  domain="(-10, 15)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="t" type="real">
+    <components>
+      E
+    </components>
+    <initialisation>
+      <![CDATA[
+        E = 2/t0/cosh(t/t0);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <vector name="cross" initial_basis="t" type="real">
+    <components>
+      P N
+    </components>
+    <initialisation>
+      <![CDATA[
+        P = 0.0;
+        N = -1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="SIC" interval="4" steps="200">
+      <samples>100 100</samples>
+      <operators>
+        <operator kind="cross_propagation" algorithm="SI" propagation_dimension="t">
+          <integration_vectors>cross</integration_vectors>
+          <!-- You can have a dependencies tag in here -->
+          <dependencies>main</dependencies>
+          <boundary_condition kind="left">
+            <!-- You can also have a dependencies tag in here -->
+            <!-- like the one shown below, but none are needed -->
+            <!-- in this example -->
+            <!-- <dependencies>cross</dependencies> -->
+            <![CDATA[
+              P = 0.0;
+              N = -1.0;
+            ]]>
+          </boundary_condition>
+          <![CDATA[
+            dP_dt = E*N;
+            dN_dt = -E*P;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dE_dz = g*P;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output>
+      <sampling_group basis="t(1000)" initial_sample="yes">
+        <moments>pow_dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          pow_dens = E*E;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="t(1000)" initial_sample="no">
+        <moments>P_out N_out</moments>
+        <dependencies>cross</dependencies>
+        <![CDATA[
+          P_out = P;
+          N_out = N;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/van_der_pol.xmds b/examples/van_der_pol.xmds
new file mode 100644
index 0000000..b19f4b0
--- /dev/null
+++ b/examples/van_der_pol.xmds
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>van_der_pol</name>
+  <author>Graham Dennis</author>
+  <description>
+    Van der Pol oscillator. An example of a stiff equation.
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <!-- That's right, this script breaks the shackles with FFTW! -->
+    <arguments>
+      <argument name="lambda" type="real" default_value="100.0" />
+      <![CDATA[
+        _LOG(_SIMULATION_LOG_LEVEL, "lambda is %e\n", lambda);
+      ]]>
+    </arguments>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <vector name="main" type="real">
+    <components>
+      y yDot
+    </components>
+    <initialisation>
+      <![CDATA[
+      y = 1.0;
+      yDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" interval="100.0" steps="25000" tolerance="1e-7">
+      <samples>5000</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        dy_dt = yDot;
+        dyDot_dt = lambda*(1.0 - y*y)*yDot - y;
+        
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output>
+      <sampling_group initial_sample="yes">
+        <moments>yR yDotR</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          yR = y;
+          yDotR = yDot;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/vibstring.xmds b/examples/vibstring.xmds
new file mode 100644
index 0000000..fd6fc4a
--- /dev/null
+++ b/examples/vibstring.xmds
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>vibstring</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw plan="estimate" />
+
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="2e-3" steps="100">
+      <samples>50 50</samples>
+      <computed_vector name="moment_creator" dimensions="" type="real">
+        <components>moment</components>
+        <evaluation>
+          <dependencies basis="kx"> main </dependencies>
+          <![CDATA[
+            moment = mod2(u);
+          ]]>
+        </evaluation>
+      </computed_vector>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>moment_creator</dependencies>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+          moment;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="vibstring_break.xsil">
+      <dependencies>main</dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output>
+    <sampling_group basis="x" initial_sample="yes">
+      <moments>amp</moments>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        amp = u.Re();
+      ]]>
+    </sampling_group>
+    <sampling_group basis="kx(50)" initial_sample="no">
+      <moments>amp</moments>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        amp = u.Re();
+        
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/vibstring2.xmds b/examples/vibstring2.xmds
new file mode 100644
index 0000000..6aa3033
--- /dev/null
+++ b/examples/vibstring2.xmds
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>vibstring2</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw />
+
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="q" type="integer" lattice="2"  domain="(0, 1)" />
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+      <dimension name="y" lattice="100"  domain="(0, 1)" />
+      <dimension name="z" lattice="100"  domain="(0, 1)" />
+      <dimension name="w" type="integer" domain="(-3, 3)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" dimensions="x y" initial_basis="x y" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="integrated_u" dimensions="" type="complex">
+    <components>
+      mom
+    </components>
+  </vector>
+  
+  <computed_vector name="filter1" dimensions="" type="complex">
+    <components>moment</components>
+    <evaluation>
+      <dependencies>integrated_u main</dependencies>
+      <![CDATA[
+        moment = mod2(u);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence cycles="10">
+    <integrate algorithm="RK9" interval="2e-3" steps="100">
+      <samples>10 10</samples>
+      <operators> <!-- For the x y dimensions -->
+        <operator kind="functions">
+          <![CDATA[
+            // print one '.' per integration step.
+            printf(".");
+          ]]>
+        </operator>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u /**/];
+        ]]>
+      </operators>
+      <operators> <!-- For the zero-dimensional field -->
+        <integration_vectors>integrated_u</integration_vectors>
+        <dependencies>filter1</dependencies>
+        <![CDATA[
+          dmom_dt = moment;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output>
+      <sampling_group basis="x y(1)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = Re(u);
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="no">
+        <moments>momR momentR</moments>
+        <dependencies>integrated_u filter1</dependencies>
+        <![CDATA[
+          momR = mom.Re();
+          momentR = moment.Re();
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/vibstring3.xmds b/examples/vibstring3.xmds
new file mode 100644
index 0000000..11ba687
--- /dev/null
+++ b/examples/vibstring3.xmds
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>vibstring3</name>
+  <author>Joe Hope</author>
+  <description>
+    Vibrating string
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw />
+
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="q" type="integer" lattice="2"  domain="(0, 1)" />
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+      <dimension name="y" lattice="100"  domain="(0, 1)" />
+      <dimension name="z" lattice="100"  domain="(0, 1)" />
+      <dimension name="w" type="integer" domain="(-3, 3)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" dimensions="x y" initial_basis="x y" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="integrated_u" dimensions="" type="complex">
+    <components>
+      mom
+    </components>
+  </vector>
+  <computed_vector name="filter1" dimensions="" type="complex">
+    <components>moment</components>
+    <!-- If the moments are of type 'real', then all dimensions that aren't integrated
+         must be evaluated in 'x' space. -->
+    <evaluation>
+      <dependencies basis="kx ky">integrated_u main</dependencies>
+      <![CDATA[
+        moment = mod2(u);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK9" interval="2e-3" steps="100">
+      <samples>50 50</samples>
+      
+      <computed_vector name="filter2" dimensions="" type="complex">
+        <components>sparemoment</components>
+        <!-- If the moments are of type 'real', then all dimensions that aren't integrated
+             must be evaluated in 'x' space. -->
+        <evaluation>
+          <dependencies basis="kx ky">integrated_u main</dependencies>
+          <![CDATA[
+            sparemoment = mod2(u);
+          ]]>
+        </evaluation>
+      </computed_vector>
+      
+      <operators>  <!-- For the x y dimensions -->
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u /**/];
+        ]]>
+      </operators>
+      
+      <operators>  <!-- For the zero-dimensional field -->
+        <integration_vectors>integrated_u</integration_vectors>
+        <dependencies>filter1</dependencies>
+        <![CDATA[
+          dmom_dt = moment;
+        ]]>
+      </operators>
+      
+      <filters>
+        <filter>
+          <dependencies>filter1 main</dependencies>
+          <![CDATA[
+            u = 1.0 * u;
+          ]]>
+        </filter>
+      </filters>
+    </integrate>
+  </sequence>
+  
+  <output>
+      <sampling_group basis="x y" initial_sample="yes">
+        <computed_vector name="filter3" dimensions="" type="complex">
+          <components>sparemomentagain</components>
+          <!-- If the moments are of type 'real', then all dimensions that aren't integrated
+               must be evaluated in 'x' space. -->
+          <evaluation>
+            <dependencies basis="kx ky">integrated_u main</dependencies>
+            <![CDATA[
+              sparemomentagain = mod2(u);
+            ]]>
+          </evaluation>
+        </computed_vector>
+        <operator kind="ex" constant="no">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <moments>amp ke</moments>
+        <dependencies>main filter1</dependencies>
+        <![CDATA[
+          amp = mod2(u + moment);
+          ke = mod2(L[u]);
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="no">
+        <moments>momR momentR</moments>
+        <dependencies>integrated_u filter1</dependencies>
+        <![CDATA[
+          momR = mom.Re();
+          momentR = moment.Re();
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/vibstring_circle.xmds b/examples/vibstring_circle.xmds
new file mode 100644
index 0000000..010cfa8
--- /dev/null
+++ b/examples/vibstring_circle.xmds
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>vibstring_circle</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string with Dirichlet boundary conditions on a circle.
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw plan="patient" />
+
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      const real T_mu = T/mu;
+      
+      const real xmax = _max_x;
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="256"  domain="(-1, 1)" />
+      <dimension name="y" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="boundary" initial_basis="x y" type="real">
+    <components>
+      bc
+    </components>
+    <initialisation>
+      <![CDATA[
+        real r = sqrt(x*x + y*y);
+        real rright = xmax-width;
+        real rdamping = r > rright ? absorb*(1-cos(M_PI*(r - rright)/width)) : 0.0;
+
+        bc = exp(-rdamping);
+        if (r > xmax)
+          bc = 0.0;
+        if ( r > rright)
+          bc = 0.0;
+        else
+          bc = 1.0;
+          
+        
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" tolerance="1e-7" interval="2e-2" steps="1000">
+      <samples>50</samples>
+      <operators>
+        <operator kind="ex" constant="no">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T_mu*(kx*kx + ky*ky);
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>boundary</dependencies>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = bc*L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output>
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/vibstring_circle_mpi.xmds b/examples/vibstring_circle_mpi.xmds
new file mode 100644
index 0000000..e8edb75
--- /dev/null
+++ b/examples/vibstring_circle_mpi.xmds
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>vibstring_circle_mpi</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string with Dirichlet boundary conditions on a circle.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      
+      const real xmax = _max_x;
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="256"  domain="(-1, 1)" />
+      <dimension name="y" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="boundary" initial_basis="x y" type="real">
+    <components>
+      bc
+    </components>
+    <initialisation>
+      <![CDATA[
+        real r = sqrt(x*x + y*y);
+        real rright = xmax-width;
+        real rdamping = r > rright ? absorb*(1-cos(M_PI*(r - rright)/width)) : 0.0;
+
+        bc = exp(-rdamping);
+        if (r > xmax)
+          bc = 0.0;
+        if ( r > rright)
+          bc = 0.0;
+        else
+          bc = 1.0;
+          
+        
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-5" interval="2e-2" steps="1000">
+      <samples>50 50</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*(kx*kx + ky*ky)/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>boundary</dependencies>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = bc*L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output>
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = Re(u);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx ky" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = mod2(u);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/vibstring_circle_spectral.xmds b/examples/vibstring_circle_spectral.xmds
new file mode 100644
index 0000000..48a9e85
--- /dev/null
+++ b/examples/vibstring_circle_spectral.xmds
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>vibstring_circle_spectral</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string with Dirichlet boundary conditions on a circle.
+    
+    Modification of vibstring_circle to calculate temporal derivatives in fourier (spectral) space.
+    This runs faster than vibstring_circle on the same grid.
+  </description>
+  
+  <features>
+    <benchmark />
+    <!-- <error_check /> -->
+    <bing />
+    <fftw plan="patient" />
+
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      const real T_mu = T/mu;
+      
+      const real xmax = _max_x;
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="64"  domain="(-1, 1)" />
+      <dimension name="y" lattice="64"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="boundary" initial_basis="x y" type="real">
+    <components>
+      bc
+    </components>
+    <initialisation>
+      <![CDATA[
+        real r = sqrt(x*x + y*y);
+        real rright = xmax-width;
+        real rdamping = r > rright ? absorb*(1-cos(M_PI*(r - rright)/width)) : 0.0;
+
+        bc = exp(-rdamping);
+        if (r > xmax)
+          bc = 0.0;
+        if ( r > rright)
+          bc = 0.0;
+        else
+          bc = 1.0;
+          
+        
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" tolerance="1e-7" interval="4e-2" steps="1000" home_space="k">
+      <samples>100 100 100</samples>
+      <operators>
+        <operator kind="ex" constant="yes" basis="x y">
+          <operator_names>L</operator_names>
+          <![CDATA[
+          real r2 = x*x + y*y;
+          if (r2 > (_max_x - width)*(_max_x-width))
+            L = 0.0;
+          else
+            L = 1.0;
+          ]]>
+        </operator>
+        <integration_vectors basis="kx ky">main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[-T_mu*(kx*kx+ky*ky)*u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output>
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx ky" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(0)" initial_sample="yes">
+        <moments>energy</moments>
+        <dependencies>main</dependencies>
+        <operator kind="ex" constant="no">
+          <operator_names>Lx Ly</operator_names>
+          <![CDATA[
+            Lx = i*kx;
+            Ly = i*ky;
+          ]]>
+        </operator>
+        <![CDATA[
+          energy = mod2(uDot) + T_mu*mod2(Lx[u]) + T_mu*mod2(Ly[u]);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/vibstring_dct.xmds b/examples/vibstring_dct.xmds
new file mode 100644
index 0000000..1bb89bb
--- /dev/null
+++ b/examples/vibstring_dct.xmds
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>vibstring_dct</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string using a Discrete Cosine transform (i.e. even boundary conditions on both sides)
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw plan="estimate" />
+
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="50"  domain="(0.5, 1.0)" transform="dct"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="real">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="2e-3" steps="100">
+      <samples>50 50</samples>
+      <computed_vector name="moment_creator" dimensions="" type="real">
+        <components>moment</components>
+        <evaluation>
+          <dependencies basis="kx"> main </dependencies>
+          <![CDATA[
+            moment = mod2(u);
+          ]]>
+        </evaluation>
+      </computed_vector>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>moment_creator</dependencies>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+          moment;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output>
+      <sampling_group basis="x(50)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx(50)" initial_sample="no">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u;
+        
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/vibstring_dirichlet_boundary.xmds b/examples/vibstring_dirichlet_boundary.xmds
new file mode 100644
index 0000000..dc930b5
--- /dev/null
+++ b/examples/vibstring_dirichlet_boundary.xmds
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>vibstring_dirichlet_boundary</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string with Dirichlet boundary conditions.
+	
+	This script is the first of two scripts that demonstrate how to refine or coarsen a grid between simulations.
+	This simulation saves the final state as part of the output moment groups in Fourier space, and the next
+	simulation (vibstring_dirichlet_boundary2.xmds) initialises from the results of this simulation in Fourier space,
+	but with a higher (spatial) resolution.  Because the spatial grid widths are the same, the step size in Fourier space
+	is the same, and so the higher resolution simulation simply initialises the lower kx values from the results of the lower
+	resolution simulation and all higher fourier components are set to zero.
+	
+	Note that when saving the state of the simulation for later loading by another simulation, it is better to use a breakpoint
+	element rather than a moment_group as used below.  A moment group is used in this case to demonstrate how to load from a
+	specific moment group rather than a breakpoint, which is demonstrated elsewhere.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <error_check />
+    <fftw plan="patient" />
+
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      
+      const real xmax = _max_x;
+      const real width = 0.1;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  <vector name="boundary" initial_basis="x" type="real">
+    <components>
+      bc
+    </components>
+    <initialisation>
+      <![CDATA[
+        real r = abs(x);
+        real rright = xmax-width;
+
+        if ( r > rright)
+          bc = 0.0;
+        else
+          bc = 1.0;
+          
+        
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" tolerance="1e-8" interval="2e-2" steps="1000">
+      <samples>500 1</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>boundary</dependencies>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = bc*L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output>
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx" initial_sample="no">
+        <moments>uR uI uDotR uDotI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          uR = u.Re();
+          uI = u.Im();
+          uDotR = uDot.Re();
+          uDotI = uDot.Im();
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/vibstring_dirichlet_boundary2.xmds b/examples/vibstring_dirichlet_boundary2.xmds
new file mode 100644
index 0000000..ae5055c
--- /dev/null
+++ b/examples/vibstring_dirichlet_boundary2.xmds
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>vibstring_dirichlet_boundary2</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string with Dirichlet boundary conditions.
+	
+	This script is the second of two scripts that demonstrate how to refine or coarsen a grid between simulations.
+	This simulation loads the final state of the previous simulation (vibstring_dirichlet_boundary.xmds) and initialises from
+	the results of that simulation in Fourier space, but with a higher (spatial) resolution.  Because the spatial grid widths are
+	the same, the step size in Fourier space is the same, and so the higher resolution simulation simply initialises the lower kx
+	values from the results of the lower resolution simulation and all higher fourier components are set to zero.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      
+      const real xmax = _max_x;
+      const real width = 0.1;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="512"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="kx" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation kind="hdf5" geometry_matching_mode="loose">
+      <filename group="2">vibstring_dirichlet_boundary.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="boundary" initial_basis="x" type="real">
+    <components>
+      bc
+    </components>
+    <initialisation>
+      <![CDATA[
+        real r = abs(x);
+        real rright = xmax-width;
+
+        if ( r > rright)
+          bc = 0.0;
+        else
+          bc = 1.0;
+          
+        
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" tolerance="1e-8" interval="2e-2" steps="1000">
+      <samples>500</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>boundary</dependencies>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = bc*L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output>
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/vibstring_ellipse.xmds b/examples/vibstring_ellipse.xmds
new file mode 100644
index 0000000..30650ba
--- /dev/null
+++ b/examples/vibstring_ellipse.xmds
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>vibstring_ellipse</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string with Dirichlet boundary conditions on an ellipse.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      const real T_mu = T/mu;
+      
+      const real ellipse_a = 0.9;
+      const real ellipse_b = 0.5;
+      const real ellipse_focus = sqrt(ellipse_a*ellipse_a - ellipse_b*ellipse_b);
+      
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="128"  domain="(-1, 1)" />
+      <dimension name="y" lattice="128"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-500.0*((x-ellipse_focus)*(x-ellipse_focus) + y*y));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="boundary" initial_basis="x y" type="real">
+    <components>
+      bc
+    </components>
+    <initialisation>
+      <![CDATA[
+        real r_norm = sqrt(x*x/ellipse_a/ellipse_a + y*y/ellipse_b/ellipse_b);
+
+        if ( r_norm > 1.0)
+          bc = 0.0;
+        else
+          bc = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" tolerance="1e-8" interval="2e-2" steps="1000">
+      <samples>50</samples>
+      <operators>
+        <operator kind="ex" constant="yes" basis="x y">
+          <operator_names>L</operator_names>
+          <![CDATA[
+          real r_norm = sqrt(x*x/ellipse_a/ellipse_a + y*y/ellipse_b/ellipse_b);
+
+          if ( r_norm > 1.0)
+            L = 0.0;
+          else
+            L = 1.0;
+          ]]>
+        </operator>
+        <integration_vectors basis="kx ky">main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[-T_mu*(kx*kx+ky*ky)*u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output>
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = Re(u);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/wigner.xmds b/examples/wigner.xmds
new file mode 100644
index 0000000..c10dd2c
--- /dev/null
+++ b/examples/wigner.xmds
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>wigner</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simulation of the Wigner function for an anharmonic oscillator with the initial state
+    being a coherent state.
+    
+    WARNING: This simulation will take a couple of hours.
+  </description>
+  
+  <features>
+    <benchmark />
+    <!-- <error_check /> -->
+    <bing />
+    <fftw plan="patient" />
+
+    <globals>
+      <![CDATA[
+      /* physical constants */
+        const real hbar = 1.05457148e-34;
+        
+      /* system constants */
+        const real omega = 0.0;
+        const real Uint = 1.0*hbar;
+        
+      /* initial state constants */
+        const real alpha_0 = 3.0;
+        
+      /* used for calculating constants derived from arguments */
+        bool firstTime = true;
+        
+      /* absorbing boundary constants */
+       const real absorb = 8.0;
+       const real width = 0.3;
+       
+      /* derived constants */
+        const complex miOmega = -i*omega;
+        const complex miUint_hbar = -i*Uint/hbar;
+        const real Uint_hbar = Uint/hbar;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="128"  domain="(-6, 6)" />
+      <dimension name="y" lattice="128"  domain="(-6, 6)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components> W </components>
+    <initialisation>
+      <![CDATA[
+        W = 2.0/M_PI * exp(-2.0*(y*y + (x-alpha_0)*(x-alpha_0)));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="dampConstants" initial_basis="x y" type="real">
+    <components>damping</components>
+    <initialisation>
+      <![CDATA[
+      real r = sqrt(x*x + y*y);
+      
+      if (r > _max_x-width)
+        damping = 0.0;
+      else
+        damping = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" tolerance="1e-7" interval="7.0" steps="100000">
+      <samples>200</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>Lx Ly Lxxx Lxxy Lxyy Lyyy</operator_names>
+          <![CDATA[
+            Lx = i*kx;
+            Ly = i*ky;
+            Lxxx = -i*kx*kx*kx;
+            Lxxy = -i*kx*kx*ky;
+            Lxyy = -i*kx*ky*ky;
+            Lyyy = -i*ky*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>dampConstants</dependencies>
+        <![CDATA[
+          dW_dt = damping * (
+                  (omega + Uint_hbar*(-1.0 + x*x + y*y))*x*Ly[W]
+                - (omega + Uint_hbar*(-1.0 + x*x + y*y))*y*Lx[W]
+                - Uint_hbar/16.0*(x*(Lxxy[W] + Lyyy[W])
+                                 -y*(Lxyy[W] + Lxxx[W]))
+                );
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output>
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>WR WI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          WR = W.Re();
+          WI = W.Im();
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/wigner_argument_mpi.xmds b/examples/wigner_argument_mpi.xmds
new file mode 100644
index 0000000..ff2232f
--- /dev/null
+++ b/examples/wigner_argument_mpi.xmds
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>wigner_argument_mpi</name>
+  <author>Graham Dennis and Joe Hope</author>
+  <description>
+    Simulation of the Wigner function for an anharmonic oscillator with the initial state
+    being a coherent state.
+  </description>
+  
+  <features>
+    <benchmark />
+    
+    <globals>
+      <![CDATA[
+        real Uint_hbar_on16;
+      ]]>
+    </globals>
+
+    <arguments>
+      <argument name="omega" type="real" default_value="0.0" />
+      <argument name="alpha_0"     type="real" default_value="3.0" />
+      <argument name="absorb"     type="real" default_value="8.0" />
+      <argument name="width" type="real" default_value="0.3" />
+      <argument name="Uint_hbar" type="real" default_value="1.0" />
+      <![CDATA[
+      /* derived constants */
+        Uint_hbar_on16 = Uint_hbar/16.0;
+      ]]>
+    </arguments>
+    <bing />
+    <fftw plan="patient" />
+
+  </features>
+
+  <driver name="distributed-mpi" />
+    
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="128"  domain="(-6, 6)" />
+      <dimension name="y" lattice="128"  domain="(-6, 6)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components> W </components>
+    <initialisation>
+      <![CDATA[
+        W = 2.0/M_PI * exp(-2.0*(y*y + (x-alpha_0)*(x-alpha_0)));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="dampConstants" initial_basis="x y" type="real">
+    <components>damping</components>
+    <initialisation>
+      <![CDATA[
+      if (sqrt(x*x + y*y) > _max_x-width)
+        damping = 0.0;
+      else
+        damping = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" tolerance="1e-7" interval="7.0e-2" steps="100000">
+      <samples>50</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>Lx Ly Lxxx Lxxy Lxyy Lyyy</operator_names>
+          <![CDATA[
+            Lx = i*kx;
+            Ly = i*ky;
+            Lxxx = -i*kx*kx*kx;
+            Lxxy = -i*kx*kx*ky;
+            Lxyy = -i*kx*ky*ky;
+            Lyyy = -i*ky*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>dampConstants</dependencies>
+        <![CDATA[
+        real rotation = omega + Uint_hbar*(-1.0 + x*x + y*y);
+
+        dW_dt = damping * ( rotation * (x*Ly[W] - y*Lx[W]) 
+                    - Uint_hbar_on16*( x*(Lxxy[W] + Lyyy[W]) - y*(Lxyy[W] + Lxxx[W]) )
+                );
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output>
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>WR WI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(W);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/examples/wigner_spectral.xmds b/examples/wigner_spectral.xmds
new file mode 100644
index 0000000..699cb23
--- /dev/null
+++ b/examples/wigner_spectral.xmds
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <name>wigner_spectral</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simulation of the Wigner function for an anharmonic oscillator with the initial state
+    being a coherent state.
+    
+    This is a modification of wigner.xmds to be more like a true spectral method by evaluating
+    the temporal derivatives in spectral (fourier) space. This script runs faster than the original
+    wigner.xmds
+    
+    WARNING: This simulation will take a couple of hours.
+  </description>
+  
+  <features>
+    <benchmark />
+    <!-- <error_check /> -->
+    <bing />
+    <fftw plan="patient" />
+
+    <validation kind="run-time" />
+    <globals>
+      <![CDATA[
+      /* physical constants */
+        const real hbar = 1.05457148e-34;
+        
+      /* system constants */
+        const real omega = 0.0;
+        const real Uint = 1.0*hbar;
+        
+      /* initial state constants */
+        const real alpha_0 = 3.0;
+        
+      /* used for calculating constants derived from arguments */
+        bool firstTime = true;
+        
+      /* absorbing boundary constants */
+       const real absorb = 8.0;
+       const real width = 0.3;
+       
+      /* derived constants */
+        const complex miOmega = -i*omega;
+        const complex miUint_hbar = -i*Uint/hbar;
+        const real Uint_hbar = Uint/hbar;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="128"  domain="(-6, 6)" />
+      <dimension name="y" lattice="128"  domain="(-6, 6)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      W
+    </components>
+    <initialisation>
+      <![CDATA[
+        W = 2.0/M_PI * exp(-2.0*(y*y + (x-alpha_0)*(x-alpha_0)));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="dampConstants" initial_basis="x y" type="real">
+    <components>damping</components>
+    <initialisation>
+      <![CDATA[
+      real r = sqrt(x*x + y*y);
+      
+      if (r > _max_x-width)
+        damping = 0.0;
+      else
+        damping = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" tolerance="1e-7" interval="2.0*M_PI" steps="100000" home_space="k">
+      <samples>200</samples>
+      <operators>
+        <operator kind="ex" constant="no" basis="x y">
+          <operator_names>Lx Ly LxR LyR</operator_names>
+          <![CDATA[
+            real r2 = x*x + y*y;
+            if (r2 > (_max_x-width)*(_max_x-width)) {
+              Lx = Ly = LxR = LyR = 0.0;
+            } else {
+              Lx = x;
+              Ly = y;
+              LxR = x*(r2-1.0);
+              LyR = y*(r2-1.0);
+            }
+          ]]>
+        </operator>
+        <integration_vectors basis="kx ky">main</integration_vectors>
+        <![CDATA[
+          dW_dt = -i*omega*(kx*Ly[W] - ky*Lx[W])
+                  -i*Uint_hbar*(kx*LyR[W] - ky*LxR[W])
+                  -i*Uint_hbar/16.0*((kx*kx*kx+ky*ky*kx)*Ly[W] - (ky*ky*ky + ky*kx*kx)*Lx[W]);
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output>
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>WR WI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          WR = W.Re();
+          WI = W.Im();
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/ez_setup.py b/ez_setup.py
new file mode 100644
index 0000000..1ff1d3e
--- /dev/null
+++ b/ez_setup.py
@@ -0,0 +1,284 @@
+#!python
+"""Bootstrap setuptools installation
+
+If you want to use setuptools in your package's setup.py, just include this
+file in the same directory with it, and add this to the top of your setup.py::
+
+    from ez_setup import use_setuptools
+    use_setuptools()
+
+If you want to require a specific version of setuptools, set a download
+mirror, or use an alternate download directory, you can do so by supplying
+the appropriate options to ``use_setuptools()``.
+
+This file can also be run as a script to install or upgrade setuptools.
+"""
+import sys
+DEFAULT_VERSION = "0.6c11"
+DEFAULT_URL     = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
+
+md5_data = {
+    'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
+    'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
+    'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
+    'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
+    'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
+    'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
+    'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
+    'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
+    'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
+    'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
+    'setuptools-0.6c10-py2.3.egg': 'ce1e2ab5d3a0256456d9fc13800a7090',
+    'setuptools-0.6c10-py2.4.egg': '57d6d9d6e9b80772c59a53a8433a5dd4',
+    'setuptools-0.6c10-py2.5.egg': 'de46ac8b1c97c895572e5e8596aeb8c7',
+    'setuptools-0.6c10-py2.6.egg': '58ea40aef06da02ce641495523a0b7f5',
+    'setuptools-0.6c11-py2.3.egg': '2baeac6e13d414a9d28e7ba5b5a596de',
+    'setuptools-0.6c11-py2.4.egg': 'bd639f9b0eac4c42497034dec2ec0c2b',
+    'setuptools-0.6c11-py2.5.egg': '64c94f3bf7a72a13ec83e0b24f2749b2',
+    'setuptools-0.6c11-py2.6.egg': 'bfa92100bd772d5a213eedd356d64086',
+    'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
+    'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
+    'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
+    'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
+    'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
+    'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
+    'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
+    'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
+    'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
+    'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
+    'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
+    'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
+    'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
+    'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
+    'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
+    'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
+    'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
+    'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
+    'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
+    'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
+    'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03',
+    'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a',
+    'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6',
+    'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a',
+}
+
+import sys, os
+try: from hashlib import md5
+except ImportError: from md5 import md5
+
+def _validate_md5(egg_name, data):
+    if egg_name in md5_data:
+        digest = md5(data).hexdigest()
+        if digest != md5_data[egg_name]:
+            print >>sys.stderr, (
+                "md5 validation of %s failed!  (Possible download problem?)"
+                % egg_name
+            )
+            sys.exit(2)
+    return data
+
+def use_setuptools(
+    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
+    download_delay=15
+):
+    """Automatically find/download setuptools and make it available on sys.path
+
+    `version` should be a valid setuptools version number that is available
+    as an egg for download under the `download_base` URL (which should end with
+    a '/').  `to_dir` is the directory where setuptools will be downloaded, if
+    it is not already available.  If `download_delay` is specified, it should
+    be the number of seconds that will be paused before initiating a download,
+    should one be required.  If an older version of setuptools is installed,
+    this routine will print a message to ``sys.stderr`` and raise SystemExit in
+    an attempt to abort the calling script.
+    """
+    was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
+    def do_download():
+        egg = download_setuptools(version, download_base, to_dir, download_delay)
+        sys.path.insert(0, egg)
+        import setuptools; setuptools.bootstrap_install_from = egg
+    try:
+        import pkg_resources
+    except ImportError:
+        return do_download()       
+    try:
+        pkg_resources.require("setuptools>="+version); return
+    except pkg_resources.VersionConflict, e:
+        if was_imported:
+            print >>sys.stderr, (
+            "The required version of setuptools (>=%s) is not available, and\n"
+            "can't be installed while this script is running. Please install\n"
+            " a more recent version first, using 'easy_install -U setuptools'."
+            "\n\n(Currently using %r)"
+            ) % (version, e.args[0])
+            sys.exit(2)
+        else:
+            del pkg_resources, sys.modules['pkg_resources']    # reload ok
+            return do_download()
+    except pkg_resources.DistributionNotFound:
+        return do_download()
+
+def download_setuptools(
+    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
+    delay = 15
+):
+    """Download setuptools from a specified location and return its filename
+
+    `version` should be a valid setuptools version number that is available
+    as an egg for download under the `download_base` URL (which should end
+    with a '/'). `to_dir` is the directory where the egg will be downloaded.
+    `delay` is the number of seconds to pause before an actual download attempt.
+    """
+    import urllib2, shutil
+    egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
+    url = download_base + egg_name
+    saveto = os.path.join(to_dir, egg_name)
+    src = dst = None
+    if not os.path.exists(saveto):  # Avoid repeated downloads
+        try:
+            from distutils import log
+            if delay:
+                log.warn("""
+---------------------------------------------------------------------------
+This script requires setuptools version %s to run (even to display
+help).  I will attempt to download it for you (from
+%s), but
+you may need to enable firewall access for this script first.
+I will start the download in %d seconds.
+
+(Note: if this machine does not have network access, please obtain the file
+
+   %s
+
+and place it in this directory before rerunning this script.)
+---------------------------------------------------------------------------""",
+                    version, download_base, delay, url
+                ); from time import sleep; sleep(delay)
+            log.warn("Downloading %s", url)
+            src = urllib2.urlopen(url)
+            # Read/write all in one block, so we don't create a corrupt file
+            # if the download is interrupted.
+            data = _validate_md5(egg_name, src.read())
+            dst = open(saveto,"wb"); dst.write(data)
+        finally:
+            if src: src.close()
+            if dst: dst.close()
+    return os.path.realpath(saveto)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+def main(argv, version=DEFAULT_VERSION):
+    """Install or upgrade setuptools and EasyInstall"""
+    try:
+        import setuptools
+    except ImportError:
+        egg = None
+        try:
+            egg = download_setuptools(version, delay=0)
+            sys.path.insert(0,egg)
+            from setuptools.command.easy_install import main
+            return main(list(argv)+[egg])   # we're done here
+        finally:
+            if egg and os.path.exists(egg):
+                os.unlink(egg)
+    else:
+        if setuptools.__version__ == '0.0.1':
+            print >>sys.stderr, (
+            "You have an obsolete version of setuptools installed.  Please\n"
+            "remove it from your system entirely before rerunning this script."
+            )
+            sys.exit(2)
+
+    req = "setuptools>="+version
+    import pkg_resources
+    try:
+        pkg_resources.require(req)
+    except pkg_resources.VersionConflict:
+        try:
+            from setuptools.command.easy_install import main
+        except ImportError:
+            from easy_install import main
+        main(list(argv)+[download_setuptools(delay=0)])
+        sys.exit(0) # try to force an exit
+    else:
+        if argv:
+            from setuptools.command.easy_install import main
+            main(argv)
+        else:
+            print "Setuptools version",version,"or greater has been installed."
+            print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
+
+def update_md5(filenames):
+    """Update our built-in md5 registry"""
+
+    import re
+
+    for name in filenames:
+        base = os.path.basename(name)
+        f = open(name,'rb')
+        md5_data[base] = md5(f.read()).hexdigest()
+        f.close()
+
+    data = ["    %r: %r,\n" % it for it in md5_data.items()]
+    data.sort()
+    repl = "".join(data)
+
+    import inspect
+    srcfile = inspect.getsourcefile(sys.modules[__name__])
+    f = open(srcfile, 'rb'); src = f.read(); f.close()
+
+    match = re.search("\nmd5_data = {\n([^}]+)}", src)
+    if not match:
+        print >>sys.stderr, "Internal error!"
+        sys.exit(2)
+
+    src = src[:match.start(1)] + repl + src[match.end(1):]
+    f = open(srcfile,'w')
+    f.write(src)
+    f.close()
+
+
+if __name__=='__main__':
+    if len(sys.argv)>2 and sys.argv[1]=='--md5update':
+        update_md5(sys.argv[2:])
+    else:
+        main(sys.argv[1:])
+
+
+
+
+
+
diff --git a/man/xmds2.1 b/man/xmds2.1
new file mode 100644
index 0000000..f1544c2
--- /dev/null
+++ b/man/xmds2.1
@@ -0,0 +1,73 @@
+.TH XMDS2 "1" "December 2012" "xmds2 xmds2:" "User Commands"
+.\" ********************************************************************
+.SH NAME
+xmds2 \- the eXtensible Multi-Dimensional Simulator v2
+.\" ********************************************************************
+.SH SYNOPSIS
+.BR xmds2  " [options] "  \fIfileToBeParsed
+.\" ********************************************************************
+.SH DESCRIPTION
+The program \fBxmds2\fR is a code generator that integrates equations. 
+You write them down in human readable form in an XML 
+file, and it goes away and writes and compiles a C++
+program that integrates those equations as fast as 
+it can possibly be done in your architecture. 
+.PP
+For information as to how to write a script for xmds, and how
+to solve problems in physics, mathematics and even finance
+and economics, read the associated documentation available
+from the xmds web site: http://www.xmds.org.
+.\" ********************************************************************
+.SH OPTIONS
+.TP
+.BR \-h ", " \-\-help
+Print help message
+.TP
+.BI \-o\  file \fR,\ \fB\-\-output\-file= file
+This overrides the name of the output file to be generated
+.TP
+.BR \-v ", " \-\- verbose
+Verbose mode
+.TP
+.BR \-g ", " \-\-debug
+Debug mode. Compiler error messages report errors in the .cc
+file, not the .xmds file. Implies \fB\-\-verbose\fR. Mostly useful when debuging xmds
+code generation.
+.TP
+.BR \-n ", " \-\-no\-compile
+Only generate a source file, don't compile
+.TP
+.B \-\-configure
+Run configuration checks for compiling simulations
+.TP
+.B \-\-reconfigure
+Run configuration using the same options as used with the last
+time \fB\-\-configure\fR was run with the additional arguments specified
+.TP
+\fB\-\-include\-path \fI/path/to/include
+Add the path /path/to/include to the list of paths searched for include headers
+This option is only meaningful when used with \fB\-\-(re)configure
+.TP
+\fB\-\-lib\-path \fI/path/to/lib
+Add the path /path/to/lib to the list of paths searched for libraries
+This option is only meaningful when used with \fB\-\-(re)configure
+.\" ********************************************************************
+.SH "FILES"
+.TP
+.I ${HOME}/.xmds/
+Directory for storing settings and fftw wisdom files.
+.\" ********************************************************************
+.SH "SEE ALSO"
+\fBxsil2graphics2\fR\|(1)
+.P
+For further help, please see http://www.xmds.org
+.\" ********************************************************************
+.SH AUTHORS
+.PP
+Graham Dennis <graham.dennis at anu.edu.au>,
+Joe Hope,
+Mattias Johnsson,
+Andy Ferris,
+Michael Hush,
+Gabriel McManus,
+and others.
diff --git a/man/xsil2graphics2.1 b/man/xsil2graphics2.1
new file mode 100644
index 0000000..c1af709
--- /dev/null
+++ b/man/xsil2graphics2.1
@@ -0,0 +1,43 @@
+.\" DO NOT MODIFY THIS FILE!  It was generated by help2man 1.40.10.
+.TH XSIL2GRAPHICS2 "1" "December 2012" "xsil2graphics2 xsil2graphics2:" "User Commands"
+.\" ********************************************************************
+.SH NAME
+xsil2graphics2 \- generate scripts to load xsil output data files
+.\" ********************************************************************
+.SH SYNOPSIS
+\fBxsil2graphics2 \fR [options]  \fIinfile1 \fR[\fIinfile2\fR] \fR[...]
+.\" ********************************************************************
+.SH OPTIONS
+.TP
+.B infile(s)
+required, the input xsil file or files
+.TP
+.BR \-h ", " \-\-help
+optional, display this information
+.TP
+.BR \-m ", " \-\-matlab
+optional, produce matlab output (default) (only supports HDF5 output files)
+.TP
+.BR \-e ", " \-\-mathmatica
+optional, produce mathematica output
+.TP
+.BR \-o ", " \-\-outfile
+optional, alternate output file name (one input file only)
+.TP
+.BR \-g ", " \-\-debug
+Debug mode
+.\" ********************************************************************
+.SH "SEE ALSO"
+\fBxmds2\fR\|(1)
+.P
+For further help, please see http://www.xmds.org
+.\" ********************************************************************
+.SH AUTHORS
+.PP
+Graham Dennis <graham.dennis at anu.edu.au>,
+Joe Hope,
+Mattias Johnsson,
+Andy Ferris,
+Michael Hush,
+Gabriel McManus,
+and others.
diff --git a/run_tests.py b/run_tests.py
new file mode 100755
index 0000000..30d6828
--- /dev/null
+++ b/run_tests.py
@@ -0,0 +1,350 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+run_tests.py
+
+Created by Graham Dennis on 2008-06-15.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+import xpdeint.Python24Support
+
+import os
+import re
+import sys
+import getopt
+import shutil
+import hashlib
+import unittest
+import subprocess
+
+from xml.dom import minidom
+import xpdeint.minidom_extras
+from xpdeint import CodeParser
+
+from xpdeint.XSILFile import XSILFile
+
+import numpy
+
+help_message = '''
+The help message goes here.
+'''
+
+
+class Usage(Exception):
+  def __init__(self, msg):
+    self.msg = msg
+
+def pass_nan_test(array1, array2):
+    """Return `True` if isNaN(`array1`) == isNaN(`array2`)"""
+    # NaN test. array2 is allowed to be NaN at an index if array1 is also NaN there.
+    nanTestPassed = numpy.equal(numpy.isnan(array1), numpy.isnan(array2)).all()
+    return nanTestPassed
+
+def array_approx_equal(array1, array2, absTol, relTol):
+  """Return `True` if all of (`array1` - `array2`) <= `absTol` or (`array1` - `array2`) <= `relTol` * `array2`"""
+  diff = array1-array2
+  # NaN values would fail this test. So we have to exclude them. But only exclude them if array2 (the expected results)
+  # have a NaN
+  return numpy.logical_or(numpy.logical_or(numpy.abs(diff) <= 0.5 * relTol * (numpy.abs(array2) + numpy.abs(array1)), numpy.abs(diff) <= absTol), numpy.isnan(array2)).all()
+
+def scriptTestingFunction(root, scriptName, testDir, absPath, self):
+  if not os.path.exists(testDir):
+    os.makedirs(testDir)
+  
+  proc = subprocess.Popen('xmds2 --no-version ' + '"' + absPath + '"',
+                          shell=True,
+                          stdout=subprocess.PIPE,
+                          stderr=subprocess.PIPE,
+                          cwd=testDir)
+  (stdout, stderr) = proc.communicate()
+  returnCode = proc.wait()
+  
+  message = ''.join(["\n%(handleName)s:\n%(content)s" % locals() for handleName, content in [('stdout', stdout), ('stderr', stderr)] if content])
+  
+  # A few tests require XMDS1. If XMDS1 isn't present we should just
+  # skip that test rather than failing.
+  # The skip functionality for the unittest class is only available
+  # in python 2.7 and later, so check for that too.
+  if returnCode != 0 and sys.version_info[:2] >= (2, 7):
+    if re.search(r'^The missing \w+ feature\(s\) were: .*xmds.*', message, re.MULTILINE):
+      self.skipTest("Skipping test as XMDS1 is required and not installed")
+
+  # A few tests require specific features.  If it isn't available, skip the test
+  # rather than failing.
+  # The skip functionality for the unittest class is only available
+  # in python 2.7 and later, so check for that too.
+  if returnCode != 0 and sys.version_info[:2] >= (2, 7):
+    if re.search(r'^The missing \w+ feature\(s\) were:', message, re.MULTILINE):
+      self.skipTest("Skipping test as feature required is not installed")
+
+  self.assert_(returnCode == 0, ("Failed to compile." % locals()) + message)
+  
+  xmlDocument = minidom.parse(absPath)
+  simulationElement = xmlDocument.getChildElementByTagName('simulation')
+  nameElement = simulationElement.getChildElementByTagName('name')
+  testingElement = simulationElement.getChildElementByTagName('testing')
+  
+  simulationName = nameElement.innerText()
+  
+  # If the source is the same as the last known good, then we don't need to compile or execute the simulation.
+  sourceFilePath = os.path.join(testDir, simulationName + '.cc')
+  checksumFilePath = os.path.join(testDir, simulationName + '_last_known_good.checksum')
+  sourceContents = file(sourceFilePath).read()
+  h = hashlib.sha1()
+  h.update(sourceContents)
+  currentChecksum = h.hexdigest()
+  
+  if os.path.exists(checksumFilePath):
+    lastKnownGoodChecksum = file(checksumFilePath).read()
+    
+    if lastKnownGoodChecksum == currentChecksum:
+      # The checksums check out, so we don't need to go any further
+      return
+  
+  # Now we have compiled, we need to copy any input data needed and then run the simulation
+  inputXSILElements = testingElement.getChildElementsByTagName('input_xsil_file', optional=True)
+  
+  filesToCopy = []
+  
+  for inputXSILElement in inputXSILElements:
+    name = inputXSILElement.getAttribute('name').strip()
+    filesToCopy.append(name)
+    inputXSILFile = XSILFile(os.path.join(os.path.split(absPath)[0], name), loadData=False)
+    filesToCopy.extend([os.path.join(os.path.split(name)[0], xsil.data.filename) for xsil in inputXSILFile.xsilObjects if hasattr(xsil.data, 'filename')])
+  
+  for fileToCopy in filesToCopy:
+    sourceFile = os.path.join(os.path.split(absPath)[0], fileToCopy)
+    shutil.copy(sourceFile, testDir)
+  
+  # Allow command-line arguments to be specified for the simulation
+  commandLineElement = testingElement.getChildElementByTagName('command_line', optional=True)
+  argumentsElement = testingElement.getChildElementByTagName('arguments', optional=True)
+  commandLineString = '"./' + simulationName + '"'
+  if commandLineElement:
+    # The command line element overrides the prefix
+    commandLineString = '"' + commandLineElement.innerText().strip() + '"'
+  if argumentsElement:
+    commandLineString += ' ' + argumentsElement.innerText().strip()
+  
+  simulationProc = subprocess.Popen(commandLineString,
+                                    shell=True,
+                                    stdout=subprocess.PIPE,
+                                    stderr=subprocess.PIPE,
+                                    cwd=testDir)
+  (stdout, stderr) = simulationProc.communicate()
+  returnCode = simulationProc.wait()
+  
+  self.assert_(returnCode == 0, "Failed to execute compiled simulation correctly." % locals())
+  
+  # The next thing to check is that the generated data agrees with the expected data to within the set error margins.
+  xsilFileElements = testingElement.getChildElementsByTagName('xsil_file', optional=True)
+  for xsilFileElement in xsilFileElements:
+    sourceFile = xsilFileElement.getAttribute('name').strip()
+    expectedResultsFile = xsilFileElement.getAttribute('expected').strip()
+    # Defaults
+    absoluteTolerance = 0 
+    relativeTolerance = 1e-9
+    
+    if xsilFileElement.hasAttribute('absolute_tolerance'):
+      absoluteTolerance = float(xsilFileElement.getAttribute('absolute_tolerance'))
+    if xsilFileElement.hasAttribute('relative_tolerance'):
+      relativeTolerance = float(xsilFileElement.getAttribute('relative_tolerance'))
+    
+    resultsFullPath = os.path.join(testDir, sourceFile)
+    results = XSILFile(resultsFullPath)
+    expectedResultsFullPath = os.path.join(os.path.split(absPath)[0], expectedResultsFile)
+    if not os.path.exists(expectedResultsFullPath):
+      print >> sys.stderr, "Expected results file '%(expectedResultsFile)s' missing. Using current. " % locals()
+      
+      # If there are any NaN's in the results, issue a warning.
+      for mgNum, o in enumerate(results.xsilObjects):
+        for v in o.independentVariables:
+          if numpy.isnan(v['array']).any():
+            print >> sys.stderr, "Warning: Coordinate '%s' in moment group %i of file '%s' contains a NaN." % (v['name'], mgNum+1, sourceFile)
+        for v in o.dependentVariables:
+          if numpy.isnan(v['array']).any():
+            print >> sys.stderr, "Warning: Dependent variable '%s' in moment group %i of file '%s' contains a NaN." % (v['name'], mgNum+1, sourceFile)
+      
+      resultsFileContents = file(resultsFullPath).read()
+      
+      for xsilObject in results.xsilObjects:
+        if hasattr(xsilObject.data, 'filename'):
+          # If the moment group has a data file name, then we need to copy it to the expected results file
+          newDataFilename = xsilObject.data.filename.replace(os.path.splitext(sourceFile)[0], os.path.splitext(expectedResultsFile)[0], 1)
+          
+          resultsFileContents = resultsFileContents.replace(xsilObject.data.filename, newDataFilename)
+          
+          shutil.copyfile(os.path.join(testDir, xsilObject.data.filename),
+                          os.path.join(os.path.split(absPath)[0], newDataFilename))
+      
+      file(expectedResultsFullPath, 'w').write(resultsFileContents)
+    else:
+      expectedResults = XSILFile(expectedResultsFullPath)
+      
+      self.assert_(len(results.xsilObjects) == len(expectedResults.xsilObjects))
+      
+      momentGroupElements = xsilFileElement.getChildElementsByTagName('moment_group', optional=True)
+      if momentGroupElements:
+        self.assert_(len(momentGroupElements) == len(results.xsilObjects))
+      else:
+        momentGroupElements = [None]*len(results.xsilObjects)
+      
+      for mgNum, (o1, o2, mgElem) in enumerate(zip(results.xsilObjects, expectedResults.xsilObjects, momentGroupElements)):
+        currentAbsoluteTolerance = absoluteTolerance
+        currentRelativeTolerance = relativeTolerance
+        self.assert_(len(o1.independentVariables) == len(o2.independentVariables),
+                     "The number of independent variables in moment group %(mgNum)i doesn't match." % locals())
+        self.assert_(len(o1.dependentVariables) == len(o2.dependentVariables),
+                     "The number of dependent variables in moment group %(mgNum)i doesn't match." % locals())
+        
+        if mgElem:
+          if mgElem.hasAttribute('absolute_tolerance'):
+            currentAbsoluteTolerance = float(mgElem.getAttribute('absolute_tolerance'))
+          if mgElem.hasAttribute('relative_tolerance'):
+            currentRelativeTolerance = float(mgElem.getAttribute('relative_tolerance'))
+        
+        self.assert_(currentAbsoluteTolerance != None and currentRelativeTolerance != None, "An absolute and a relative tolerance must be specified.")
+        
+        for v1, v2 in zip(o1.independentVariables, o2.independentVariables):
+          self.assert_(v1['name'] == v2['name'])
+          self.assert_(v1['length'] == v2['length'])
+          # These are the coordinates, we just specify a constant absolute and relative tolerance.
+          # No-one should need to change these
+          self.assert_(array_approx_equal(v1['array'], v2['array'], 1e-7, 1e-6),
+                      "Coordinate '%s' in moment group %i of file '%s' didn't pass tolerance criteria." % (v1['name'], mgNum+1, sourceFile))
+        
+        for v1, v2 in zip(o1.dependentVariables, o2.dependentVariables):
+          self.assert_(v1['name'] == v2['name'])
+          self.assert_(pass_nan_test(v1['array'], v2['array']),
+                       "Dependent variable '%s' in moment group %i of file '%s' had a NaN where the expected results didn't (or vice-versa)." % (v1['name'], mgNum+1, sourceFile))
+          self.assert_(array_approx_equal(v1['array'], v2['array'], currentAbsoluteTolerance, currentRelativeTolerance),
+                       "Dependent variable '%s' in moment group %i of file '%s' failed to pass tolerance criteria." % (v1['name'], mgNum+1, sourceFile))
+  
+  # Test has succeeded, so save our checksum for the source file and copy the source file
+  file(checksumFilePath, 'w').write(currentChecksum)
+  
+  lastKnownGoodSourcePath = os.path.join(testDir, simulationName + '_last_known_good.cc')
+  file(lastKnownGoodSourcePath, 'w').write(sourceContents)
+
+def partial(func, *args, **keywords):
+  def newfunc(*fargs, **fkeywords):
+    newkeywords = keywords.copy()
+    newkeywords.update(fkeywords)
+    return func(*(args + fargs), **newkeywords)
+  return newfunc
+
+
+def main(argv=None):
+  if argv is None:
+    argv = sys.argv
+  try:
+    try:
+      opts, args = getopt.getopt(argv[1:], "ho:v", ["help", "output="])
+    except getopt.error, msg:
+      raise Usage(msg)
+  
+    # option processing
+    for option, value in opts:
+      if option == "-v":
+        verbose = True
+      if option in ("-h", "--help"):
+        raise Usage(help_message)
+      if option in ("-o", "--output"):
+        output = value
+  
+  except Usage, err:
+    print >> sys.stderr, sys.argv[0].split("/")[-1] + ": " + str(err.msg)
+    print >> sys.stderr, "\t for help use --help"
+    return 2
+  
+  basePath = os.path.dirname(__file__)
+  
+  resultsPath = os.path.join(basePath, 'testsuite_results')
+  if not os.path.exists(resultsPath):
+    os.mkdir(resultsPath)
+  resultsPath = os.path.abspath(resultsPath)
+  
+  print "Saving test results in %(resultsPath)s" % locals()
+  
+  testsuites = {}
+  baseSuiteName = 'testsuite'
+  baseSuitePath = os.path.join(basePath, baseSuiteName)
+  
+  for root, dirs, files in os.walk(baseSuitePath):
+    # First remove directories we don't want to traverse
+    for dirName in ['.svn']:
+      if dirName in dirs:
+        dirs.remove(dirName)
+    # Remove the 'testsuite/' part of the path
+    dirRelativeToBase = root[(len(baseSuitePath)+1):]
+    if dirRelativeToBase:
+      testSuiteName = os.path.join(baseSuiteName, dirRelativeToBase)
+    else:
+      testSuiteName = baseSuiteName
+    
+    # If we have .xmds files in this path, then create a TestCase subclass
+    xmdsTestScripts = [filename for filename in files if os.path.splitext(filename)[1].lower() == '.xmds']
+    
+    if xmdsTestScripts:
+      class ScriptTestCase(unittest.TestCase):
+        # Create test functions for each test script using 'scriptTestingFunction'
+        # These test function names are of the form 'test_ScriptName'
+        for scriptName in xmdsTestScripts:
+          prefix = os.path.splitext(scriptName)[0]
+          absPath = os.path.abspath(os.path.join(root, scriptName))
+          testDir = os.path.join(resultsPath, dirRelativeToBase)
+          locals()['test_' + prefix] = partial(scriptTestingFunction, root, scriptName, testDir, absPath)
+          locals()['test_' + prefix].__doc__ = os.path.join(dirRelativeToBase, scriptName)
+      
+      # Create a TestSuite from that class
+      suite = unittest.defaultTestLoader.loadTestsFromTestCase(ScriptTestCase)
+      testsuites[testSuiteName] = suite
+    
+    if not testSuiteName in testsuites:
+      testsuites[testSuiteName] = unittest.TestSuite()
+    
+    suite = testsuites[testSuiteName]
+    # Add our TestSuite as a sub-suite of all parent suites
+    head = testSuiteName
+    while True:
+      head, tail = os.path.split(head)
+      if not head or not tail:
+        break
+      testsuites[head].addTest(suite)
+  
+  
+  suitesToRun = list()
+  if len(args):
+    for suiteName in args:
+      fullSuiteName = os.path.join(baseSuiteName, suiteName)
+      if fullSuiteName in testsuites:
+        suitesToRun.append(testsuites[fullSuiteName])
+      else:
+        print >> sys.stderr, "Unable to find test '%(suiteName)s'" % locals()
+  else:
+    suitesToRun.append(testsuites[baseSuiteName])
+  suitesToRun.append(unittest.defaultTestLoader.loadTestsFromModule(CodeParser))
+  
+  fullSuite = unittest.TestSuite(tests=suitesToRun)
+  
+  return not unittest.TextTestRunner().run(fullSuite).wasSuccessful()
+
+
+if __name__ == "__main__":
+  sys.exit(main())
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..87ee48a
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+
+from setuptools import setup, find_packages
+
+import os
+if not os.path.exists('xpdeint'):
+    raise Exception("setup.py must be run from the xpdeint main directory.")
+
+packages = ['xpdeint.waf.waflib', 'xpdeint.waf.waflib.Tools', 'xpdeint.waf.waflib.extras'] # The packages needed by waf
+skip_dirs = set(['.svn', 'waf_build'])
+for root, dirs, files in os.walk('xpdeint'):
+    for d in skip_dirs.intersection(dirs):
+        dirs.remove(d)
+    if not '__init__.py' in files:
+        del dirs[:]
+    else:
+        packages.append(root.replace(os.sep, '.'))
+
+setup(name="xmds2",
+      version="2.1.4",
+      description="Stochastic ODE/PDE integrator",
+      url="http://xmds.sourceforge.net",
+      license="GPLv2",
+      keywords="scientific/engineering simulation",
+      platforms="OS Independent",
+      packages = packages,
+      
+      scripts = ['bin/xmds2', 'bin/xsil2graphics2'],
+      
+      exclude_package_data = {'': ['README', 'TODO']},
+      
+      # Project requires Cheetah for all of the templates
+      install_requires = ['Cheetah>=2.0.1', 'pyparsing<2.0.0', 'mpmath', 'Sphinx>=1.1'],
+      
+      package_data = {
+        'xpdeint': ['includes/*.c',
+                    'includes/*.h',
+                    'includes/dSFMT/*',
+                    'includes/solirte/*',
+                    'support/xpdeint.rng',
+                    'support/wscript',
+                   ]
+      },
+      
+      # We aren't zip safe because we will require access to
+      # *.c and *.h files inside the distributed egg
+      zip_safe = False,
+      
+      entry_points = '''
+      [pygments.lexers]
+      XMDSScriptLexer = xpdeint.XMDSScriptLexer:XMDSScriptLexer
+      
+      [pygments.styles]
+      friendly_plus = xpdeint.FriendlyPlusStyle:FriendlyPlusStyle
+      '''
+)
+
diff --git a/testsuite/fast/RbGS_expected.xsil b/testsuite/fast/RbGS_expected.xsil
new file mode 100644
index 0000000..042f294
--- /dev/null
+++ b/testsuite/fast/RbGS_expected.xsil
@@ -0,0 +1,369 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 4 ./RbGS</command_line>
+    <xsil_file name="RbGS.xsil" expected="RbGS_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+    <xsil_file name="potential.xsil" expected="potential_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+    <xsil_file name="RbGSa.xsil" expected="RbGSa_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+  </testing>
+
+  <name>RbGS</name>
+  <author>Robin Stevenson</author>
+  <description>
+    Three dimensional harmonic trap Ground state calculation. cigar trap.
+  </description>
+  
+  <features>
+    <halt_non_finite />
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <!-- <openmp /> -->
+    <fftw plan="measure" />
+    <!-- <diagnostics /> -->
+	<globals>
+		<![CDATA[
+		/*constants*/
+			const double hbar = 1.054e-34;
+			const double massRb = 1.44316e-25;
+			const double c0OnHbar = 5.16891e-51/hbar; 		//for Rb-87
+			const double c2OnHbar = -2.38868e-53/hbar;         
+
+      const double cd = 2.1501769e-54;  // =mu0 * muB^2 *Gf^2 / 4pi --> this is for rubidium 
+      const double cdOnHbar = 2.1501769e-54/hbar;  // =mu0 * muB^2 *Gf^2 / 4pi --> this is for rubidium 
+      const double gamma1 = 4.39943e10;
+	
+			const double Sqrt2 = pow(2.0, 0.5); 			
+			const double a3dSqrt2 = 3.0/pow(2.0, 0.5); 
+			const double Pi = 3.141592654;   
+
+      /*experimental variables*/
+			const double ratio = 1.0/40.0;
+			const double omegap = 2*3.141592654*3000;
+			const double N0 = 1.0e5;                  //Note this change
+			const double B = 73.0e-7;        
+			const double gamma1B = gamma1*B;
+			const double muOnHbar = 0.0*24411.0;
+		]]>
+    </globals>  
+  </features>
+
+  <driver name="distributed-mpi" />  
+
+
+
+  <geometry>
+    <propagation_dimension>t</propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="32"  domain="(-2.2e-6, 2.2e-6)" />
+      <dimension name="y" lattice="32"  domain="(-2.2e-6, 2.2e-6)" />
+      <dimension name="z" lattice="32"  domain="(-90.0e-6, 90.0e-6)" />
+    </transverse_dimensions>
+  </geometry>
+
+  
+  <vector name="wavefunction" initial_basis="x y z" type="complex">
+    <components>
+      phi1 phi0 phim1
+    </components>
+
+    <initialisation>
+      <![CDATA[	    
+      phi1 = (x<1.0e-6 ? (y<1.0e-6 ? (z<40.0e-6 ? 1.0 : 0.0) : 0.0) : 0.0 );
+      phi0 = 0.0;
+      phim1 = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="potential" type="double">
+    <components>
+      VtrapOnHbar
+    </components>
+    <initialisation>
+      <![CDATA[
+   			//VtrapOnHbar = 0.5* massRb * omegap*omegap*(x*x + y*y + z*z*ratio*ratio);
+   			VtrapOnHbar = x*x+y*y+z*z*ratio*ratio < 2.0*2.0e-12 ? 0.5 * massRb * omegap * omegap *  (x*x+y*y+z*z*ratio*ratio)/hbar-muOnHbar : 0.5 * massRb * omegap * omegap *  2.0*2.0e-12/hbar-muOnHbar;
+      ]]>
+    </initialisation>
+  </vector>
+
+  
+  <computed_vector name="spins" type="complex">
+    <components>
+      Sz Splus Sminus S0
+    </components>
+	  <evaluation>
+	  <dependencies>
+	    wavefunction
+	  </dependencies>
+      <![CDATA[
+			S0 = mod2(phi1) + mod2(phi0) + mod2(phim1);
+			Splus = conj(phi1)*phi0 + conj(phi0)*phim1;
+			Sminus = conj(phi0)*phi1 + conj(phim1)*phi0;
+			//Sx = Sqrt2*(phi1.re * phi0.re - phi1.im * phi0.im + phi0.re * phim1.re - phi0.im * phim1.im);
+			//Sy = Sqrt2*(phim1.im * phi0.re - phim1.re * phi0.im - phi0.re * phi1.im + phi0.im * phi1.re);
+			Sz = mod2(phi1)- mod2(phim1);
+			// Splus = Sx + i*Sy;
+			// Sminus = conj(Splus);
+      ]]>		
+    </evaluation>
+  </computed_vector>  
+
+  <computed_vector type="complex" name="bilinear" dimensions="x y z">
+    <components>b11 bm1m1 b10 b01 bm10 b0m1</components>
+    <evaluation>
+      <dependencies fourier_space="x y z">wavefunction</dependencies>
+        <![CDATA[
+          b11 = mod2(phi1);
+          bm1m1 = mod2(phim1);
+          b10 = conj(phi1)*phi0;
+          b01 = conj(phi0)*phi1;
+          bm10 = conj(phim1)*phi0;
+          b0m1 = conj(phi0)*phim1;
+        ]]>
+    </evaluation>
+  </computed_vector>
+ 
+ 
+  <vector name="DipoleTerms" type="complex" initial_basis="kx ky kz">
+    <components>DA DB DC DCstar DE DEstar</components>
+    <initialisation>
+      <![CDATA[
+        double Ksqd = kx*kx + ky*ky + kz*kz;
+        DA = Ksqd<1.0      ?     0.0*i     :     -4*Pi/3 * (1 - 3 * kz*kz /Ksqd) + 0.0*i;
+        DB = Ksqd<1.0      ?     0.0*i     :     2*Pi/3 * (1 - 3 * kz*kz /Ksqd) + 0.0*i;
+        DC = Ksqd<1.0      ?     0.0*i     :    2* 2*Pi/3 * (kx - i * ky)*kz/Ksqd;
+        DCstar = Ksqd<1.0      ?     0.0*i     :  2*   2*Pi/3 * (kx + i * ky)*kz/Ksqd;
+        DE = Ksqd < 1.0      ?     0.0*i     :     -4*Pi/3 * (kx - i*ky)*(kx - i*ky) / Ksqd;
+        DEstar = Ksqd < 1.0      ?     0.0*i     :     -4*Pi/3 * (kx + i*ky)*(kx + i*ky) / Ksqd;
+      ]]>
+    </initialisation>
+  </vector>
+
+
+  <computed_vector name="dipoles" type="complex" dimensions="x y z">
+    <components>Dz Dplus Dminus</components>
+    <evaluation>
+      <dependencies fourier_space="kx ky kz">DipoleTerms bilinear</dependencies>
+      <![CDATA[
+        Dz = DA*(b11 - bm1m1) - a3dSqrt2 * DC*(b10 + b0m1) - a3dSqrt2 * DCstar*(bm10 + b01);
+        Dplus = DB*(b10 + b0m1) -1.5 * DEstar*(b01 + bm10) - a3dSqrt2 * DCstar*(b11 - bm1m1);
+        Dminus = DB*(b01 + bm10) -1.5 * DE*(b10 + b0m1) - a3dSqrt2 * DC*(b11 - bm1m1);        
+      ]]>
+    </evaluation>
+  </computed_vector>
+
+
+  
+  <computed_vector name="normalisation" dimensions="" type="double">
+    <components>
+      Ncalc
+    </components>
+    <evaluation>
+    <dependencies fourier_space="x y z">wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi1) + mod2(phi0) + mod2(phim1);
+      ]]>
+    </evaluation>
+  </computed_vector>
+ 
+  <sequence>
+    <breakpoint filename="potential.xsil">
+      <dependencies>
+        potential
+      </dependencies>
+    </breakpoint>
+    <integrate algorithm="RK4" interval="15.0e-7" steps="5">
+      <samples>1 1 1 1</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi1 *= sqrt(N0/Ncalc);
+            phi0 *= sqrt(N0/Ncalc);
+            phim1 *= sqrt(N0/Ncalc);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+			      T   = -0.5*hbar*(kx*kx+ky*ky+kz*kz)/massRb;
+          ]]>
+        </operator>
+        <dependencies>potential spins dipoles</dependencies>
+        <integration_vectors>wavefunction</integration_vectors>
+        <![CDATA[
+          dphi1_dt = T[phi1] + ((-VtrapOnHbar)*phi1 -c0OnHbar*S0*phi1 -c2OnHbar*(Sz*phi1 + Sminus*phi0) +gamma1B*phi1 -cdOnHbar*(phi1*Dz + phi0*Dminus));
+          
+          dphi0_dt = T[phi0] + ((-VtrapOnHbar)*phi0 -c0OnHbar*S0*phi0 -c2OnHbar*(Splus*phi1 + Sminus*phim1) -cdOnHbar*(phi1*Dplus + phim1*Dminus));
+          
+          dphim1_dt = T[phim1] + ((-VtrapOnHbar)*phim1 -c0OnHbar*S0*phim1 -c2OnHbar*(-Sz*phim1 + Splus*phi0) -gamma1B*phim1 -cdOnHbar*(-phim1*Dz + phi0*Dplus));
+        ]]>
+      </operators>
+    </integrate>
+    
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi1 *= sqrt(N0/Ncalc);
+            phi0 *= sqrt(N0/Ncalc);
+            phim1 *= sqrt(N0/Ncalc);
+          ]]>
+        </filter>
+
+
+    <breakpoint filename="potential.xsil">
+      <dependencies>
+        potential
+      </dependencies>
+    </breakpoint>
+    <breakpoint filename="RbGSa.xsil">
+      <dependencies>
+        wavefunction
+      </dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="no">
+        <dimension name="x" lattice="16" fourier_space="no" />
+        <dimension name="y" lattice="16" fourier_space="no" />
+        <dimension name="z" fourier_space="no" />
+        <moments>phi1re dens0 densm1 phi1im dens1</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens1 = mod2(phi1);
+          densm1 = mod2(phim1);
+          phi1re = real(phi1);
+          dens0 = mod2(phi0);
+          phi1im = imag(phi1);
+        ]]>
+      </sampling_group>
+
+
+    
+      <sampling_group initial_sample="no">
+        <dimension name="x" lattice="16" fourier_space="yes" />
+        <dimension name="y" lattice="16" fourier_space="yes" />
+        <dimension name="z" fourier_space="yes" />
+        <moments>dens1</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens1 = mod2(phi1);
+        ]]>
+      </sampling_group>
+ 
+      <sampling_group initial_sample="yes">
+        <dimension name="x" lattice="0" fourier_space="no" />
+        <dimension name="y" lattice="0" fourier_space="no" />
+        <dimension name="z" lattice="0" fourier_space="no" />
+        <moments>N1 N0 Nm1</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          N1 = mod2(phi1);
+          N0 = mod2(phi0);
+          Nm1 = mod2(phim1);
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="no">
+        <dimension name="x" lattice="0" fourier_space="no" />
+        <dimension name="y" lattice="0" fourier_space="no" />
+        <dimension name="z" lattice="0" fourier_space="no" />
+        <moments>E1OnHbarRe E1OnHbarIm</moments>
+        <operator kind="ex" constant="no">
+          <operator_names>T2</operator_names>
+          <![CDATA[
+			      T2   = -0.5*hbar*(kx*kx+ky*ky+kz*kz)/massRb;
+          ]]>
+        </operator>       
+        <dependencies>wavefunction potential spins dipoles</dependencies>
+        <![CDATA[
+          E1OnHbarRe =  real(conj(phi1)*(T2[phi1] + (-VtrapOnHbar)*phi1 -c0OnHbar*S0*phi1 -c2OnHbar*(Sz*phi1 + Sminus*phi0) +gamma1B*phi1 -cdOnHbar*(phi1*Dz + phi0*Dminus)));
+          E1OnHbarIm =  imag(conj(phi1)*(T2[phi1] + (-VtrapOnHbar)*phi1 -c0OnHbar*S0*phi1 -c2OnHbar*(Sz*phi1 + Sminus*phi0) +gamma1B*phi1 -cdOnHbar*(phi1*Dz + phi0*Dminus)));
+        ]]>
+      </sampling_group>
+  </output>
+
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>8</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x y z phi1re dens0 densm1 phi1im dens1 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>16</Dim>
+    <Dim>16</Dim>
+    <Dim>32</Dim>
+    <Dim>8</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+RbGS_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+kx ky kz dens1 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>16</Dim>
+    <Dim>16</Dim>
+    <Dim>32</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+RbGS_expected_mg1.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_3">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t N1 N0 Nm1 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>2</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+RbGS_expected_mg2.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_4">
+  <Param Name="n_independent">0</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+E1OnHbarRe E1OnHbarIm 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+RbGS_expected_mg3.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/fast/RbGS_expected_mg0.dat b/testsuite/fast/RbGS_expected_mg0.dat
new file mode 100644
index 0000000..9c6b9c9
Binary files /dev/null and b/testsuite/fast/RbGS_expected_mg0.dat differ
diff --git a/testsuite/fast/RbGS_expected_mg1.dat b/testsuite/fast/RbGS_expected_mg1.dat
new file mode 100644
index 0000000..31abddb
Binary files /dev/null and b/testsuite/fast/RbGS_expected_mg1.dat differ
diff --git a/testsuite/fast/RbGS_expected_mg2.dat b/testsuite/fast/RbGS_expected_mg2.dat
new file mode 100644
index 0000000..175c2f8
Binary files /dev/null and b/testsuite/fast/RbGS_expected_mg2.dat differ
diff --git a/testsuite/fast/RbGS_expected_mg3.dat b/testsuite/fast/RbGS_expected_mg3.dat
new file mode 100644
index 0000000..33767ad
Binary files /dev/null and b/testsuite/fast/RbGS_expected_mg3.dat differ
diff --git a/testsuite/fast/RbGSa_expected.dat b/testsuite/fast/RbGSa_expected.dat
new file mode 100644
index 0000000..50bc969
Binary files /dev/null and b/testsuite/fast/RbGSa_expected.dat differ
diff --git a/testsuite/fast/RbGSa_expected.xsil b/testsuite/fast/RbGSa_expected.xsil
new file mode 100644
index 0000000..b603983
--- /dev/null
+++ b/testsuite/fast/RbGSa_expected.xsil
@@ -0,0 +1,317 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 4 ./RbGS</command_line>
+    <xsil_file name="RbGS.xsil" expected="RbGS_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+    <xsil_file name="potential.xsil" expected="potential_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+    <xsil_file name="RbGSa.xsil" expected="RbGSa_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+  </testing>
+
+  <name>RbGS</name>
+  <author>Robin Stevenson</author>
+  <description>
+    Three dimensional harmonic trap Ground state calculation. cigar trap.
+  </description>
+  
+  <features>
+    <halt_non_finite />
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <!-- <openmp /> -->
+    <fftw plan="measure" />
+    <!-- <diagnostics /> -->
+	<globals>
+		<![CDATA[
+		/*constants*/
+			const double hbar = 1.054e-34;
+			const double massRb = 1.44316e-25;
+			const double c0OnHbar = 5.16891e-51/hbar; 		//for Rb-87
+			const double c2OnHbar = -2.38868e-53/hbar;         
+
+      const double cd = 2.1501769e-54;  // =mu0 * muB^2 *Gf^2 / 4pi --> this is for rubidium 
+      const double cdOnHbar = 2.1501769e-54/hbar;  // =mu0 * muB^2 *Gf^2 / 4pi --> this is for rubidium 
+      const double gamma1 = 4.39943e10;
+	
+			const double Sqrt2 = pow(2.0, 0.5); 			
+			const double a3dSqrt2 = 3.0/pow(2.0, 0.5); 
+			const double Pi = 3.141592654;   
+
+      /*experimental variables*/
+			const double ratio = 1.0/40.0;
+			const double omegap = 2*3.141592654*3000;
+			const double N0 = 1.0e5;                  //Note this change
+			const double B = 73.0e-7;        
+			const double gamma1B = gamma1*B;
+			const double muOnHbar = 0.0*24411.0;
+		]]>
+    </globals>  
+  </features>
+
+  <driver name="distributed-mpi" />  
+
+
+
+  <geometry>
+    <propagation_dimension>t</propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="32"  domain="(-2.2e-6, 2.2e-6)" />
+      <dimension name="y" lattice="32"  domain="(-2.2e-6, 2.2e-6)" />
+      <dimension name="z" lattice="32"  domain="(-90.0e-6, 90.0e-6)" />
+    </transverse_dimensions>
+  </geometry>
+
+  
+  <vector name="wavefunction" initial_basis="x y z" type="complex">
+    <components>
+      phi1 phi0 phim1
+    </components>
+
+    <initialisation>
+      <![CDATA[	    
+      phi1 = (x<1.0e-6 ? (y<1.0e-6 ? (z<40.0e-6 ? 1.0 : 0.0) : 0.0) : 0.0 );
+      phi0 = 0.0;
+      phim1 = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="potential" type="double">
+    <components>
+      VtrapOnHbar
+    </components>
+    <initialisation>
+      <![CDATA[
+   			//VtrapOnHbar = 0.5* massRb * omegap*omegap*(x*x + y*y + z*z*ratio*ratio);
+   			VtrapOnHbar = x*x+y*y+z*z*ratio*ratio < 2.0*2.0e-12 ? 0.5 * massRb * omegap * omegap *  (x*x+y*y+z*z*ratio*ratio)/hbar-muOnHbar : 0.5 * massRb * omegap * omegap *  2.0*2.0e-12/hbar-muOnHbar;
+      ]]>
+    </initialisation>
+  </vector>
+
+  
+  <computed_vector name="spins" type="complex">
+    <components>
+      Sz Splus Sminus S0
+    </components>
+	  <evaluation>
+	  <dependencies>
+	    wavefunction
+	  </dependencies>
+      <![CDATA[
+			S0 = mod2(phi1) + mod2(phi0) + mod2(phim1);
+			Splus = conj(phi1)*phi0 + conj(phi0)*phim1;
+			Sminus = conj(phi0)*phi1 + conj(phim1)*phi0;
+			//Sx = Sqrt2*(phi1.re * phi0.re - phi1.im * phi0.im + phi0.re * phim1.re - phi0.im * phim1.im);
+			//Sy = Sqrt2*(phim1.im * phi0.re - phim1.re * phi0.im - phi0.re * phi1.im + phi0.im * phi1.re);
+			Sz = mod2(phi1)- mod2(phim1);
+			// Splus = Sx + i*Sy;
+			// Sminus = conj(Splus);
+      ]]>		
+    </evaluation>
+  </computed_vector>  
+
+  <computed_vector type="complex" name="bilinear" dimensions="x y z">
+    <components>b11 bm1m1 b10 b01 bm10 b0m1</components>
+    <evaluation>
+      <dependencies fourier_space="x y z">wavefunction</dependencies>
+        <![CDATA[
+          b11 = mod2(phi1);
+          bm1m1 = mod2(phim1);
+          b10 = conj(phi1)*phi0;
+          b01 = conj(phi0)*phi1;
+          bm10 = conj(phim1)*phi0;
+          b0m1 = conj(phi0)*phim1;
+        ]]>
+    </evaluation>
+  </computed_vector>
+ 
+ 
+  <vector name="DipoleTerms" type="complex" initial_basis="kx ky kz">
+    <components>DA DB DC DCstar DE DEstar</components>
+    <initialisation>
+      <![CDATA[
+        double Ksqd = kx*kx + ky*ky + kz*kz;
+        DA = Ksqd<1.0      ?     0.0*i     :     -4*Pi/3 * (1 - 3 * kz*kz /Ksqd) + 0.0*i;
+        DB = Ksqd<1.0      ?     0.0*i     :     2*Pi/3 * (1 - 3 * kz*kz /Ksqd) + 0.0*i;
+        DC = Ksqd<1.0      ?     0.0*i     :    2* 2*Pi/3 * (kx - i * ky)*kz/Ksqd;
+        DCstar = Ksqd<1.0      ?     0.0*i     :  2*   2*Pi/3 * (kx + i * ky)*kz/Ksqd;
+        DE = Ksqd < 1.0      ?     0.0*i     :     -4*Pi/3 * (kx - i*ky)*(kx - i*ky) / Ksqd;
+        DEstar = Ksqd < 1.0      ?     0.0*i     :     -4*Pi/3 * (kx + i*ky)*(kx + i*ky) / Ksqd;
+      ]]>
+    </initialisation>
+  </vector>
+
+
+  <computed_vector name="dipoles" type="complex" dimensions="x y z">
+    <components>Dz Dplus Dminus</components>
+    <evaluation>
+      <dependencies fourier_space="kx ky kz">DipoleTerms bilinear</dependencies>
+      <![CDATA[
+        Dz = DA*(b11 - bm1m1) - a3dSqrt2 * DC*(b10 + b0m1) - a3dSqrt2 * DCstar*(bm10 + b01);
+        Dplus = DB*(b10 + b0m1) -1.5 * DEstar*(b01 + bm10) - a3dSqrt2 * DCstar*(b11 - bm1m1);
+        Dminus = DB*(b01 + bm10) -1.5 * DE*(b10 + b0m1) - a3dSqrt2 * DC*(b11 - bm1m1);        
+      ]]>
+    </evaluation>
+  </computed_vector>
+
+
+  
+  <computed_vector name="normalisation" dimensions="" type="double">
+    <components>
+      Ncalc
+    </components>
+    <evaluation>
+    <dependencies fourier_space="x y z">wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi1) + mod2(phi0) + mod2(phim1);
+      ]]>
+    </evaluation>
+  </computed_vector>
+ 
+  <sequence>
+    <breakpoint filename="potential.xsil">
+      <dependencies>
+        potential
+      </dependencies>
+    </breakpoint>
+    <integrate algorithm="RK4" interval="15.0e-7" steps="5">
+      <samples>1 1 1 1</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi1 *= sqrt(N0/Ncalc);
+            phi0 *= sqrt(N0/Ncalc);
+            phim1 *= sqrt(N0/Ncalc);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+			      T   = -0.5*hbar*(kx*kx+ky*ky+kz*kz)/massRb;
+          ]]>
+        </operator>
+        <dependencies>potential spins dipoles</dependencies>
+        <integration_vectors>wavefunction</integration_vectors>
+        <![CDATA[
+          dphi1_dt = T[phi1] + ((-VtrapOnHbar)*phi1 -c0OnHbar*S0*phi1 -c2OnHbar*(Sz*phi1 + Sminus*phi0) +gamma1B*phi1 -cdOnHbar*(phi1*Dz + phi0*Dminus));
+          
+          dphi0_dt = T[phi0] + ((-VtrapOnHbar)*phi0 -c0OnHbar*S0*phi0 -c2OnHbar*(Splus*phi1 + Sminus*phim1) -cdOnHbar*(phi1*Dplus + phim1*Dminus));
+          
+          dphim1_dt = T[phim1] + ((-VtrapOnHbar)*phim1 -c0OnHbar*S0*phim1 -c2OnHbar*(-Sz*phim1 + Splus*phi0) -gamma1B*phim1 -cdOnHbar*(-phim1*Dz + phi0*Dplus));
+        ]]>
+      </operators>
+    </integrate>
+    
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi1 *= sqrt(N0/Ncalc);
+            phi0 *= sqrt(N0/Ncalc);
+            phim1 *= sqrt(N0/Ncalc);
+          ]]>
+        </filter>
+
+
+    <breakpoint filename="potential.xsil">
+      <dependencies>
+        potential
+      </dependencies>
+    </breakpoint>
+    <breakpoint filename="RbGSa.xsil">
+      <dependencies>
+        wavefunction
+      </dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="no">
+        <dimension name="x" lattice="16" fourier_space="no" />
+        <dimension name="y" lattice="16" fourier_space="no" />
+        <dimension name="z" fourier_space="no" />
+        <moments>phi1re dens0 densm1 phi1im dens1</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens1 = mod2(phi1);
+          densm1 = mod2(phim1);
+          phi1re = real(phi1);
+          dens0 = mod2(phi0);
+          phi1im = imag(phi1);
+        ]]>
+      </sampling_group>
+
+
+    
+      <sampling_group initial_sample="no">
+        <dimension name="x" lattice="16" fourier_space="yes" />
+        <dimension name="y" lattice="16" fourier_space="yes" />
+        <dimension name="z" fourier_space="yes" />
+        <moments>dens1</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens1 = mod2(phi1);
+        ]]>
+      </sampling_group>
+ 
+      <sampling_group initial_sample="yes">
+        <dimension name="x" lattice="0" fourier_space="no" />
+        <dimension name="y" lattice="0" fourier_space="no" />
+        <dimension name="z" lattice="0" fourier_space="no" />
+        <moments>N1 N0 Nm1</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          N1 = mod2(phi1);
+          N0 = mod2(phi0);
+          Nm1 = mod2(phim1);
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="no">
+        <dimension name="x" lattice="0" fourier_space="no" />
+        <dimension name="y" lattice="0" fourier_space="no" />
+        <dimension name="z" lattice="0" fourier_space="no" />
+        <moments>E1OnHbarRe E1OnHbarIm</moments>
+        <operator kind="ex" constant="no">
+          <operator_names>T2</operator_names>
+          <![CDATA[
+			      T2   = -0.5*hbar*(kx*kx+ky*ky+kz*kz)/massRb;
+          ]]>
+        </operator>       
+        <dependencies>wavefunction potential spins dipoles</dependencies>
+        <![CDATA[
+          E1OnHbarRe =  real(conj(phi1)*(T2[phi1] + (-VtrapOnHbar)*phi1 -c0OnHbar*S0*phi1 -c2OnHbar*(Sz*phi1 + Sminus*phi0) +gamma1B*phi1 -cdOnHbar*(phi1*Dz + phi0*Dminus)));
+          E1OnHbarIm =  imag(conj(phi1)*(T2[phi1] + (-VtrapOnHbar)*phi1 -c0OnHbar*S0*phi1 -c2OnHbar*(Sz*phi1 + Sminus*phi0) +gamma1B*phi1 -cdOnHbar*(phi1*Dz + phi0*Dminus)));
+        ]]>
+      </sampling_group>
+  </output>
+
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>9</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x y z phi1R phi1I phi0R phi0I phim1R phim1I 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>32</Dim>
+    <Dim>32</Dim>
+    <Dim>32</Dim>
+    <Dim>9</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+RbGSa_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/fast/RbGSdipoles.xmds b/testsuite/fast/RbGSdipoles.xmds
new file mode 100644
index 0000000..ce17c92
--- /dev/null
+++ b/testsuite/fast/RbGSdipoles.xmds
@@ -0,0 +1,281 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 4 ./RbGS</command_line>
+    <xsil_file name="RbGS.xsil" expected="RbGS_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+    <xsil_file name="potential.xsil" expected="potential_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+    <xsil_file name="RbGSa.xsil" expected="RbGSa_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+  </testing>
+
+  <name>RbGS</name>
+  <author>Robin Stevenson</author>
+  <description>
+    Three dimensional harmonic trap Ground state calculation. cigar trap.
+  </description>
+  
+  <features>
+    <halt_non_finite />
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <!-- <openmp /> -->
+    <fftw plan="measure" />
+    <!-- <diagnostics /> -->
+	<globals>
+		<![CDATA[
+		/*constants*/
+			const real hbar = 1.054e-34;
+			const real massRb = 1.44316e-25;
+			const real c0OnHbar = 5.16891e-51/hbar; 		//for Rb-87
+			const real c2OnHbar = -2.38868e-53/hbar;         
+
+      const real cd = 2.1501769e-54;  // =mu0 * muB^2 *Gf^2 / 4pi --> this is for rubidium 
+      const real cdOnHbar = 2.1501769e-54/hbar;  // =mu0 * muB^2 *Gf^2 / 4pi --> this is for rubidium 
+      const real gamma1 = 4.39943e10;
+	
+			const real Sqrt2 = pow(2.0, 0.5); 			
+			const real a3dSqrt2 = 3.0/pow(2.0, 0.5); 
+			const real Pi = 3.141592654;   
+
+      /*experimental variables*/
+			const real ratio = 1.0/40.0;
+			const real omegap = 2*3.141592654*3000;
+			const real N0 = 1.0e5;                  //Note this change
+			const real B = 73.0e-7;        
+			const real gamma1B = gamma1*B;
+			const real muOnHbar = 0.0*24411.0;
+		]]>
+    </globals>  
+  </features>
+
+  <driver name="distributed-mpi" />  
+
+
+
+  <geometry>
+    <propagation_dimension>t</propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="32"  domain="(-2.2e-6, 2.2e-6)" />
+      <dimension name="y" lattice="32"  domain="(-2.2e-6, 2.2e-6)" />
+      <dimension name="z" lattice="32"  domain="(-90.0e-6, 90.0e-6)" />
+    </transverse_dimensions>
+  </geometry>
+
+  
+  <vector name="wavefunction" initial_basis="x y z" type="complex">
+    <components>
+      phi1 phi0 phim1
+    </components>
+
+    <initialisation>
+      <![CDATA[	    
+      phi1 = (x<1.0e-6 ? (y<1.0e-6 ? (z<40.0e-6 ? 1.0 : 0.0) : 0.0) : 0.0 );
+      phi0 = 0.0;
+      phim1 = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="potential" type="real">
+    <components>
+      VtrapOnHbar
+    </components>
+    <initialisation>
+      <![CDATA[
+   			//VtrapOnHbar = 0.5* massRb * omegap*omegap*(x*x + y*y + z*z*ratio*ratio);
+   			VtrapOnHbar = x*x+y*y+z*z*ratio*ratio < 2.0*2.0e-12 ? 0.5 * massRb * omegap * omegap *  (x*x+y*y+z*z*ratio*ratio)/hbar-muOnHbar : 0.5 * massRb * omegap * omegap *  2.0*2.0e-12/hbar-muOnHbar;
+      ]]>
+    </initialisation>
+  </vector>
+
+  
+  <computed_vector name="spins" type="complex">
+    <components>
+      Sz Splus Sminus S0
+    </components>
+	  <evaluation>
+	  <dependencies>
+	    wavefunction
+	  </dependencies>
+      <![CDATA[
+			S0 = mod2(phi1) + mod2(phi0) + mod2(phim1);
+			Splus = conj(phi1)*phi0 + conj(phi0)*phim1;
+			Sminus = conj(phi0)*phi1 + conj(phim1)*phi0;
+			//Sx = Sqrt2*(phi1.re * phi0.re - phi1.im * phi0.im + phi0.re * phim1.re - phi0.im * phim1.im);
+			//Sy = Sqrt2*(phim1.im * phi0.re - phim1.re * phi0.im - phi0.re * phi1.im + phi0.im * phi1.re);
+			Sz = mod2(phi1)- mod2(phim1);
+			// Splus = Sx + i*Sy;
+			// Sminus = conj(Splus);
+      ]]>		
+    </evaluation>
+  </computed_vector>  
+
+  <computed_vector type="complex" name="bilinear" dimensions="x y z">
+    <components>b11 bm1m1 b10 b01 bm10 b0m1</components>
+    <evaluation>
+      <dependencies basis="x y z">wavefunction</dependencies>
+        <![CDATA[
+          b11 = mod2(phi1);
+          bm1m1 = mod2(phim1);
+          b10 = conj(phi1)*phi0;
+          b01 = conj(phi0)*phi1;
+          bm10 = conj(phim1)*phi0;
+          b0m1 = conj(phi0)*phim1;
+        ]]>
+    </evaluation>
+  </computed_vector>
+ 
+ 
+  <vector name="DipoleTerms" type="complex" initial_basis="kx ky kz">
+    <components>DA DB DC DCstar DE DEstar</components>
+    <initialisation>
+      <![CDATA[
+        real Ksqd = kx*kx + ky*ky + kz*kz;
+        DA = Ksqd<1.0      ?     0.0*i     :     -4*Pi/3 * (1 - 3 * kz*kz /Ksqd) + 0.0*i;
+        DB = Ksqd<1.0      ?     0.0*i     :     2*Pi/3 * (1 - 3 * kz*kz /Ksqd) + 0.0*i;
+        DC = Ksqd<1.0      ?     0.0*i     :    2* 2*Pi/3 * (kx - i * ky)*kz/Ksqd;
+        DCstar = Ksqd<1.0      ?     0.0*i     :  2*   2*Pi/3 * (kx + i * ky)*kz/Ksqd;
+        DE = Ksqd < 1.0      ?     0.0*i     :     -4*Pi/3 * (kx - i*ky)*(kx - i*ky) / Ksqd;
+        DEstar = Ksqd < 1.0      ?     0.0*i     :     -4*Pi/3 * (kx + i*ky)*(kx + i*ky) / Ksqd;
+      ]]>
+    </initialisation>
+  </vector>
+
+
+  <computed_vector name="dipoles" type="complex" dimensions="x y z">
+    <components>Dz Dplus Dminus</components>
+    <evaluation>
+      <dependencies basis="kx ky kz">DipoleTerms bilinear</dependencies>
+      <![CDATA[
+        Dz = DA*(b11 - bm1m1) - a3dSqrt2 * DC*(b10 + b0m1) - a3dSqrt2 * DCstar*(bm10 + b01);
+        Dplus = DB*(b10 + b0m1) -1.5 * DEstar*(b01 + bm10) - a3dSqrt2 * DCstar*(b11 - bm1m1);
+        Dminus = DB*(b01 + bm10) -1.5 * DE*(b10 + b0m1) - a3dSqrt2 * DC*(b11 - bm1m1);        
+      ]]>
+    </evaluation>
+  </computed_vector>
+
+
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>
+      Ncalc
+    </components>
+    <evaluation>
+    <dependencies basis="x y z">wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi1) + mod2(phi0) + mod2(phim1);
+      ]]>
+    </evaluation>
+  </computed_vector>
+ 
+  <sequence>
+    <breakpoint filename="potential.xsil">
+      <dependencies>
+        potential
+      </dependencies>
+    </breakpoint>
+    <integrate algorithm="RK4" interval="15.0e-7" steps="5">
+      <samples>1 1 1 1</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi1 *= sqrt(N0/Ncalc);
+            phi0 *= sqrt(N0/Ncalc);
+            phim1 *= sqrt(N0/Ncalc);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+			      T   = -0.5*hbar*(kx*kx+ky*ky+kz*kz)/massRb;
+          ]]>
+        </operator>
+        <dependencies>potential spins dipoles</dependencies>
+        <integration_vectors>wavefunction</integration_vectors>
+        <![CDATA[
+          dphi1_dt = T[phi1] + ((-VtrapOnHbar)*phi1 -c0OnHbar*S0*phi1 -c2OnHbar*(Sz*phi1 + Sminus*phi0) +gamma1B*phi1 -cdOnHbar*(phi1*Dz + phi0*Dminus));
+          
+          dphi0_dt = T[phi0] + ((-VtrapOnHbar)*phi0 -c0OnHbar*S0*phi0 -c2OnHbar*(Splus*phi1 + Sminus*phim1) -cdOnHbar*(phi1*Dplus + phim1*Dminus));
+          
+          dphim1_dt = T[phim1] + ((-VtrapOnHbar)*phim1 -c0OnHbar*S0*phim1 -c2OnHbar*(-Sz*phim1 + Splus*phi0) -gamma1B*phim1 -cdOnHbar*(-phim1*Dz + phi0*Dplus));
+        ]]>
+      </operators>
+    </integrate>
+    
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi1 *= sqrt(N0/Ncalc);
+            phi0 *= sqrt(N0/Ncalc);
+            phim1 *= sqrt(N0/Ncalc);
+          ]]>
+        </filter>
+
+
+    <breakpoint filename="potential.xsil">
+      <dependencies>
+        potential
+      </dependencies>
+    </breakpoint>
+    <breakpoint filename="RbGSa.xsil">
+      <dependencies>
+        wavefunction
+      </dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="x(16) y(16) z" initial_sample="no">
+        <moments>phi1re dens0 densm1 phi1im dens1</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens1 = mod2(phi1);
+          densm1 = mod2(phim1);
+          phi1re = Re(phi1);
+          dens0 = mod2(phi0);
+          phi1im = Im(phi1);
+        ]]>
+      </sampling_group>
+
+
+
+      <sampling_group basis="kx(16) ky(16) kz" initial_sample="no">
+        <moments>dens1</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens1 = mod2(phi1);
+        ]]>
+      </sampling_group>
+ 
+      <sampling_group basis="x(0) y(0) z(0)" initial_sample="yes">
+        <moments>N1 N0 Nm1</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          N1 = mod2(phi1);
+          N0 = mod2(phi0);
+          Nm1 = mod2(phim1);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(0) z(0)" initial_sample="no">
+        <moments>E1OnHbarRe E1OnHbarIm</moments>
+        <operator kind="ex" constant="no">
+          <operator_names>T2</operator_names>
+          <![CDATA[
+			      T2   = -0.5*hbar*(kx*kx+ky*ky+kz*kz)/massRb;
+          ]]>
+        </operator>       
+        <dependencies>wavefunction potential spins dipoles</dependencies>
+        <![CDATA[
+          E1OnHbarRe =  Re(conj(phi1)*(T2[phi1] + (-VtrapOnHbar)*phi1 -c0OnHbar*S0*phi1 -c2OnHbar*(Sz*phi1 + Sminus*phi0) +gamma1B*phi1 -cdOnHbar*(phi1*Dz + phi0*Dminus)));
+          E1OnHbarIm =  Im(conj(phi1)*(T2[phi1] + (-VtrapOnHbar)*phi1 -c0OnHbar*S0*phi1 -c2OnHbar*(Sz*phi1 + Sminus*phi0) +gamma1B*phi1 -cdOnHbar*(phi1*Dz + phi0*Dminus)));
+        ]]>
+      </sampling_group>
+  </output>
+
+</simulation>
diff --git a/testsuite/fast/anharmonic_oscillator_wigner_mpi.xmds b/testsuite/fast/anharmonic_oscillator_wigner_mpi.xmds
new file mode 100644
index 0000000..fd7fec7
--- /dev/null
+++ b/testsuite/fast/anharmonic_oscillator_wigner_mpi.xmds
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 2 ./anharmonic_oscillator_wigner_mpi</command_line>
+    <input_xsil_file name="anharmonic_oscillator_wigner_mpi_initial_even.xsil" />
+    <input_xsil_file name="anharmonic_oscillator_wigner_mpi_initial_odd.xsil" />
+    <xsil_file name="anharmonic_oscillator_wigner_mpi.xsil" expected="anharmonic_oscillator_wigner_mpi_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>anharmonic_oscillator_wigner_mpi</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simulation of the Truncated Wigner function for an anharmonic oscillator with the initial state
+    being a coherent state.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient"/>
+    <globals>
+      <![CDATA[
+
+      /* system constants */
+        const real omega = 0.0;
+        const real g = 1.0;
+        
+      /* initial state constants */
+        const real alpha_0 = 3.0;
+        
+      ]]>
+    </globals>
+    <validation kind="run-time" />
+  </features>
+  
+  <driver name="distributed-mpi" />
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="m" type="integer" lattice="21" domain="(0, 20)" />
+      <dimension name="r" lattice="64"  domain="(0, 6)" transform="dct" />
+      <dimension name="s" lattice="64"  domain="(0, 6)" transform="dst" />
+      <dimension name="theta" lattice="32"  domain="(-M_PI, M_PI)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="evens" dimensions="m r" type="complex">
+    <components>
+      hE
+    </components>
+    <initialisation kind="xsil">
+      <filename>anharmonic_oscillator_wigner_mpi_initial_even.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="odds" dimensions="m s" type="complex">
+    <components>
+      hO
+    </components>
+    <initialisation kind="xsil">
+      <filename>anharmonic_oscillator_wigner_mpi_initial_odd.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="trig" dimensions="m theta" type="real">
+    <components>cos_me sin_me cos_mo sin_mo</components>
+    <initialisation>
+      <![CDATA[
+        cos_me = cos(2.0*m*theta);
+        sin_me = sin(2.0*m*theta);
+        cos_mo = cos((2.0*m+1.0)*theta);
+        sin_mo = sin((2.0*m+1.0)*theta);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="WignerEven" dimensions="r theta" type="real">
+    <components>WE</components>
+    <evaluation>
+      <dependencies>evens trig</dependencies>
+      <![CDATA[
+        WE = hE.Re()*cos_me + hE.Im()*sin_me;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <computed_vector name="WignerOdd" dimensions="s theta" type="real">
+    <components>WO</components>
+    <evaluation>
+      <dependencies>odds trig</dependencies>
+      <![CDATA[
+        WO = hO.Re()*cos_mo + hO.Im()*sin_mo;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" cutoff="1e-3" tolerance="1e-5" interval="7.0e-1" steps="100000">
+      <samples>20 20 20 20 20 20</samples>
+      <operators dimensions="r m">
+        <integration_vectors>evens</integration_vectors>
+        <![CDATA[
+          const real M = 2*m;
+          dhE_dt = -i*omega*M*hE - i*g*(r*r-1.0)*M*hE;
+        ]]>
+      </operators>
+      <operators dimensions="s m">
+        <integration_vectors>odds</integration_vectors>
+        <![CDATA[
+          const real M = 2*m+1.0;
+          dhO_dt = -i*omega*M*hO - i*g*(s*s-1.0)*M*hO;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+    <group>
+      <sampling basis="r theta" initial_sample="yes">
+        <moments>WER</moments>
+        <dependencies>WignerEven</dependencies>
+        <![CDATA[
+          WER = WE;
+        ]]>
+      </sampling>
+    </group>
+    <sampling_group basis="s theta" initial_sample="yes">
+      <moments>WOR</moments>
+      <dependencies>WignerOdd</dependencies>
+      <![CDATA[
+        WOR = WO;
+      ]]>
+    </sampling_group>
+    <sampling_group basis="m r" initial_sample="yes">
+      <moments>hER hEI</moments>
+      <dependencies>evens</dependencies>
+      <![CDATA[
+        _SAMPLE_COMPLEX(hE);
+      ]]>
+    </sampling_group>
+    <sampling_group basis="m s" initial_sample="yes">
+      <moments>hOR hOI</moments>
+      <dependencies>odds</dependencies>
+      <![CDATA[
+        _SAMPLE_COMPLEX(hO);
+      ]]>
+    </sampling_group>
+    <sampling_group basis="m kr" initial_sample="yes">
+      <moments>hER hEI</moments>
+      <dependencies>evens</dependencies>
+      <![CDATA[
+        _SAMPLE_COMPLEX(hE);
+      ]]>
+    </sampling_group>
+    <sampling_group basis="m ks" initial_sample="yes">
+      <moments>hOR hOI</moments>
+      <dependencies>odds</dependencies>
+      <![CDATA[
+        _SAMPLE_COMPLEX(hO);
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected.xsil b/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected.xsil
new file mode 100644
index 0000000..bb2bfec
--- /dev/null
+++ b/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected.xsil
@@ -0,0 +1,299 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 2 ./anharmonic_oscillator_wigner_mpi</command_line>
+    <input_xsil_file name="anharmonic_oscillator_wigner_mpi_initial_even.xsil" />
+    <input_xsil_file name="anharmonic_oscillator_wigner_mpi_initial_odd.xsil" />
+    <xsil_file name="anharmonic_oscillator_wigner_mpi.xsil" expected="anharmonic_oscillator_wigner_mpi_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>anharmonic_oscillator_wigner_mpi</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simulation of the Truncated Wigner function for an anharmonic oscillator with the initial state
+    being a coherent state.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient"/>
+    <globals>
+      <![CDATA[
+
+      /* system constants */
+        const double omega = 0.0;
+        const double g = 1.0;
+        
+      /* initial state constants */
+        const double alpha_0 = 3.0;
+        
+      ]]>
+    </globals>
+    <validation kind="run-time" />
+  </features>
+  
+  <driver name="distributed-mpi" />
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <integer_valued kind="first">
+        <dimension name="m" lattice="21" domain="(0, 20)" />
+      </integer_valued>
+      <dimension name="r" lattice="64"  domain="(0, 6)" transform="dct" />
+      <dimension name="s" lattice="64"  domain="(0, 6)" transform="dst" />
+      <dimension name="theta" lattice="32"  domain="(-M_PI, M_PI)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="evens" dimensions="m r" type="complex">
+    <components>
+      hE
+    </components>
+    <initialisation kind="xsil">
+      <filename>anharmonic_oscillator_wigner_mpi_initial_even.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="odds" dimensions="m s" type="complex">
+    <components>
+      hO
+    </components>
+    <initialisation kind="xsil">
+      <filename>anharmonic_oscillator_wigner_mpi_initial_odd.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="trig" dimensions="m theta" type="double">
+    <components>cos_me sin_me cos_mo sin_mo</components>
+    <initialisation>
+      <![CDATA[
+        cos_me = cos(2.0*m*theta);
+        sin_me = sin(2.0*m*theta);
+        cos_mo = cos((2.0*m+1.0)*theta);
+        sin_mo = sin((2.0*m+1.0)*theta);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="WignerEven" dimensions="r theta" type="double">
+    <components>WE</components>
+    <evaluation>
+      <dependencies>evens trig</dependencies>
+      <![CDATA[
+        WE = hE.re*cos_me + hE.im*sin_me;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <computed_vector name="WignerOdd" dimensions="s theta" type="double">
+    <components>WO</components>
+    <evaluation>
+      <dependencies>odds trig</dependencies>
+      <![CDATA[
+        WO = hO.re*cos_mo + hO.im*sin_mo;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" cutoff="1e-3" tolerance="1e-5" interval="7.0e-1" steps="100000">
+      <samples>20 20 20 20 20 20</samples>
+      <operators dimensions="r m">
+        <integration_vectors>evens</integration_vectors>
+        <![CDATA[
+          const double M = 2*m;
+          dhE_dt = -i*omega*M*hE - i*g*(r*r-1.0)*M*hE;
+        ]]>
+      </operators>
+      <operators dimensions="s m">
+        <integration_vectors>odds</integration_vectors>
+        <![CDATA[
+          const double M = 2*m+1.0;
+          dhO_dt = -i*omega*M*hO - i*g*(s*s-1.0)*M*hO;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <!-- Any dimension not mentioned is assumed to be in real space and its middle element will be sampled -->
+        <!-- Note that this is different default behaviour to the filter operator. To integrate, put in a dimension -->
+        <!-- with zero lattice points. -->
+        <!-- Note that dimensions can be in any order. Not that I can think of a reason why you would want to do that -->
+        <dimension name="r" fourier_space="no" />
+        <dimension name="theta" fourier_space="no" />
+        <moments>WER</moments>
+        <dependencies>WignerEven</dependencies>
+        <![CDATA[
+          WER = WE;
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes">
+        <dimension name="s" fourier_space="no" />
+        <dimension name="theta" />
+        <moments>WOR</moments>
+        <dependencies>WignerOdd</dependencies>
+        <![CDATA[
+          WOR = WO;
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes">
+        <dimension name="m"/>
+        <dimension name="r" />
+        <moments>hER hEI</moments>
+        <dependencies>evens</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(hE);
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes">
+        <dimension name="m"/>
+        <dimension name="s" />
+        <moments>hOR hOI</moments>
+        <dependencies>odds</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(hO);
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes">
+        <dimension name="m"/>
+        <dimension name="r" fourier_space="yes" />
+        <moments>hER hEI</moments>
+        <dependencies>evens</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(hE);
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes">
+        <dimension name="m"/>
+        <dimension name="s" fourier_space="yes" />
+        <moments>hOR hOI</moments>
+        <dependencies>odds</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(hO);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t r theta WER 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>21</Dim>
+    <Dim>64</Dim>
+    <Dim>32</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+anharmonic_oscillator_wigner_mpi_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t s theta WOR 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>21</Dim>
+    <Dim>64</Dim>
+    <Dim>32</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+anharmonic_oscillator_wigner_mpi_expected_mg1.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_3">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t m r hER hEI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>21</Dim>
+    <Dim>21</Dim>
+    <Dim>64</Dim>
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+anharmonic_oscillator_wigner_mpi_expected_mg2.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_4">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t m s hOR hOI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>21</Dim>
+    <Dim>21</Dim>
+    <Dim>64</Dim>
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+anharmonic_oscillator_wigner_mpi_expected_mg3.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_5">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t m kr hER hEI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>21</Dim>
+    <Dim>21</Dim>
+    <Dim>64</Dim>
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+anharmonic_oscillator_wigner_mpi_expected_mg4.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_6">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t m ks hOR hOI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>21</Dim>
+    <Dim>21</Dim>
+    <Dim>64</Dim>
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+anharmonic_oscillator_wigner_mpi_expected_mg5.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected_mg0.dat b/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected_mg0.dat
new file mode 100644
index 0000000..b48126d
Binary files /dev/null and b/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected_mg0.dat differ
diff --git a/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected_mg1.dat b/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected_mg1.dat
new file mode 100644
index 0000000..e3ff4a3
Binary files /dev/null and b/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected_mg1.dat differ
diff --git a/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected_mg2.dat b/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected_mg2.dat
new file mode 100644
index 0000000..e7b7dd4
Binary files /dev/null and b/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected_mg2.dat differ
diff --git a/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected_mg3.dat b/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected_mg3.dat
new file mode 100644
index 0000000..3f212ed
Binary files /dev/null and b/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected_mg3.dat differ
diff --git a/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected_mg4.dat b/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected_mg4.dat
new file mode 100644
index 0000000..bd4089f
Binary files /dev/null and b/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected_mg4.dat differ
diff --git a/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected_mg5.dat b/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected_mg5.dat
new file mode 100644
index 0000000..09eaef6
Binary files /dev/null and b/testsuite/fast/anharmonic_oscillator_wigner_mpi_expected_mg5.dat differ
diff --git a/testsuite/fast/anharmonic_oscillator_wigner_mpi_initial_even.dat b/testsuite/fast/anharmonic_oscillator_wigner_mpi_initial_even.dat
new file mode 100644
index 0000000..b5974bc
Binary files /dev/null and b/testsuite/fast/anharmonic_oscillator_wigner_mpi_initial_even.dat differ
diff --git a/testsuite/fast/anharmonic_oscillator_wigner_mpi_initial_even.xsil b/testsuite/fast/anharmonic_oscillator_wigner_mpi_initial_even.xsil
new file mode 100644
index 0000000..5758426
--- /dev/null
+++ b/testsuite/fast/anharmonic_oscillator_wigner_mpi_initial_even.xsil
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <input_xsil_file name="anharmonic_oscillator_wigner_mpi_initial_even.xsil" />
+    <input_xsil_file name="anharmonic_oscillator_wigner_mpi_initial_odd.xsil" />
+    <xsil_file name="anharmonic_oscillator_wigner_mpi.xsil" expected="anharmonic_oscillator_wigner_mpi_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>anharmonic_oscillator_wigner_mpi</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simulation of the Wigner function for an anharmonic oscillator with the initial state
+    being a coherent state.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient"/>
+    <globals>
+      <![CDATA[
+
+#include <gsl/gsl_sf_bessel.h>
+#include <gsl/gsl_errno.h>
+      /* system constants */
+        const double omega = 0.0;
+        const double g = 1.0;
+        
+      /* initial state constants */
+        const double alpha_0 = 3.0;
+        
+      ]]>
+    </globals>
+    <validation kind="run-time" />
+    <cflags><![CDATA[`gsl-config --cflags` `gsl-config --libs-without-cblas`]]></cflags>
+  </features>
+  
+  <driver name="distributed-mpi" />
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <integer_valued kind="first">
+        <dimension name="m" lattice="21" domain="(0, 20)" />
+      </integer_valued>
+      <dimension name="r" lattice="64"  domain="(0, 6)" transform="dct" />
+      <dimension name="s" lattice="64"  domain="(0, 6)" transform="dst" />
+      <dimension name="theta" lattice="128"  domain="(-M_PI, M_PI)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="evens" dimensions="m r" type="complex">
+    <components>
+      hE
+    </components>
+    <initialisation>
+      <![CDATA[
+        gsl_set_error_handler_off();
+        hE = 2.0*exp(-2.0*(r-alpha_0)*(r-alpha_0))*gsl_sf_bessel_In_scaled(2*m, 4.0*r*alpha_0);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="odds" dimensions="m s" type="complex">
+    <components>
+      hO
+    </components>
+    <initialisation>
+      <![CDATA[
+        hO = 2.0*exp(-2.0*(s-alpha_0)*(s-alpha_0))*gsl_sf_bessel_In_scaled(2*m+1, 4.0*s*alpha_0);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="trig" dimensions="m theta" type="double">
+    <components>cos_me sin_me cos_mo sin_mo</components>
+    <initialisation>
+      <![CDATA[
+        cos_me = cos(2.0*m*theta);
+        sin_me = sin(2.0*m*theta);
+        cos_mo = cos((2.0*m+1.0)*theta);
+        sin_mo = sin((2.0*m+1.0)*theta);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="WignerEven" dimensions="r theta" type="double">
+    <components>WE</components>
+    <evaluation>
+      <dependencies>evens trig</dependencies>
+      <![CDATA[
+        WE = hE.re*cos_me + hE.im*sin_me;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <computed_vector name="WignerOdd" dimensions="s theta" type="double">
+    <components>WO</components>
+    <evaluation>
+      <dependencies>odds trig</dependencies>
+      <![CDATA[
+        WO = hO.re*cos_mo + hO.im*sin_mo;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <breakpoint filename="anharmonic_oscillator_wigner_mpi_initial_even.xsil">
+      <dependencies>evens</dependencies>
+    </breakpoint>
+    <breakpoint filename="anharmonic_oscillator_wigner_mpi_initial_odd.xsil">
+      <dependencies>odds</dependencies>
+    </breakpoint>
+    
+    <integrate algorithm="ARK45" cutoff="1e-3" tolerance="1e-5" interval="7.0e-1" steps="100000">
+      <samples>20 20 20 20</samples>
+      <operators dimensions="r m">
+        <integration_vectors>evens</integration_vectors>
+        <![CDATA[
+          const double M = 2*m;
+          dhE_dt = -i*omega*M*hE - i*g*(r*r-1.0)*M*hE;
+        ]]>
+      </operators>
+      <operators dimensions="s m">
+        <integration_vectors>odds</integration_vectors>
+        <![CDATA[
+          const double M = 2*m+1.0;
+          dhO_dt = -i*omega*M*hO - i*g*(s*s-1.0)*M*hO;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <!-- Any dimension not mentioned is assumed to be in real space and its middle element will be sampled -->
+        <!-- Note that this is different default behaviour to the filter operator. To integrate, put in a dimension -->
+        <!-- with zero lattice points. -->
+        <!-- Note that dimensions can be in any order. Not that I can think of a reason why you would want to do that -->
+        <dimension name="r" fourier_space="no" />
+        <dimension name="theta" fourier_space="no" />
+        <moments>WER</moments>
+        <dependencies>WignerEven</dependencies>
+        <![CDATA[
+          WER = WE;
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes">
+        <dimension name="s" fourier_space="no" />
+        <dimension name="theta" />
+        <moments>WOR</moments>
+        <dependencies>WignerOdd</dependencies>
+        <![CDATA[
+          WOR = WO;
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes">
+        <dimension name="m"/>
+        <dimension name="r" />
+        <moments>hER hEI</moments>
+        <dependencies>evens</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(hE);
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes">
+        <dimension name="m"/>
+        <dimension name="s" />
+        <moments>hOR hOI</moments>
+        <dependencies>odds</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(hO);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version 0.4 "Soylent Green is Purple!" (r2106)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+m r hER hEI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>21</Dim>
+    <Dim>64</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+anharmonic_oscillator_wigner_mpi_initial_even.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/fast/anharmonic_oscillator_wigner_mpi_initial_odd.dat b/testsuite/fast/anharmonic_oscillator_wigner_mpi_initial_odd.dat
new file mode 100644
index 0000000..b2f58a6
Binary files /dev/null and b/testsuite/fast/anharmonic_oscillator_wigner_mpi_initial_odd.dat differ
diff --git a/testsuite/fast/anharmonic_oscillator_wigner_mpi_initial_odd.xsil b/testsuite/fast/anharmonic_oscillator_wigner_mpi_initial_odd.xsil
new file mode 100644
index 0000000..96f77b9
--- /dev/null
+++ b/testsuite/fast/anharmonic_oscillator_wigner_mpi_initial_odd.xsil
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <input_xsil_file name="anharmonic_oscillator_wigner_mpi_initial_even.xsil" />
+    <input_xsil_file name="anharmonic_oscillator_wigner_mpi_initial_odd.xsil" />
+    <xsil_file name="anharmonic_oscillator_wigner_mpi.xsil" expected="anharmonic_oscillator_wigner_mpi_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>anharmonic_oscillator_wigner_mpi</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simulation of the Wigner function for an anharmonic oscillator with the initial state
+    being a coherent state.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient"/>
+    <globals>
+      <![CDATA[
+
+#include <gsl/gsl_sf_bessel.h>
+#include <gsl/gsl_errno.h>
+      /* system constants */
+        const double omega = 0.0;
+        const double g = 1.0;
+        
+      /* initial state constants */
+        const double alpha_0 = 3.0;
+        
+      ]]>
+    </globals>
+    <validation kind="run-time" />
+    <cflags><![CDATA[`gsl-config --cflags` `gsl-config --libs-without-cblas`]]></cflags>
+  </features>
+  
+  <driver name="distributed-mpi" />
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <integer_valued kind="first">
+        <dimension name="m" lattice="21" domain="(0, 20)" />
+      </integer_valued>
+      <dimension name="r" lattice="64"  domain="(0, 6)" transform="dct" />
+      <dimension name="s" lattice="64"  domain="(0, 6)" transform="dst" />
+      <dimension name="theta" lattice="128"  domain="(-M_PI, M_PI)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="evens" dimensions="m r" type="complex">
+    <components>
+      hE
+    </components>
+    <initialisation>
+      <![CDATA[
+        gsl_set_error_handler_off();
+        hE = 2.0*exp(-2.0*(r-alpha_0)*(r-alpha_0))*gsl_sf_bessel_In_scaled(2*m, 4.0*r*alpha_0);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="odds" dimensions="m s" type="complex">
+    <components>
+      hO
+    </components>
+    <initialisation>
+      <![CDATA[
+        hO = 2.0*exp(-2.0*(s-alpha_0)*(s-alpha_0))*gsl_sf_bessel_In_scaled(2*m+1, 4.0*s*alpha_0);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="trig" dimensions="m theta" type="double">
+    <components>cos_me sin_me cos_mo sin_mo</components>
+    <initialisation>
+      <![CDATA[
+        cos_me = cos(2.0*m*theta);
+        sin_me = sin(2.0*m*theta);
+        cos_mo = cos((2.0*m+1.0)*theta);
+        sin_mo = sin((2.0*m+1.0)*theta);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="WignerEven" dimensions="r theta" type="double">
+    <components>WE</components>
+    <evaluation>
+      <dependencies>evens trig</dependencies>
+      <![CDATA[
+        WE = hE.re*cos_me + hE.im*sin_me;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <computed_vector name="WignerOdd" dimensions="s theta" type="double">
+    <components>WO</components>
+    <evaluation>
+      <dependencies>odds trig</dependencies>
+      <![CDATA[
+        WO = hO.re*cos_mo + hO.im*sin_mo;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <breakpoint filename="anharmonic_oscillator_wigner_mpi_initial_even.xsil">
+      <dependencies>evens</dependencies>
+    </breakpoint>
+    <breakpoint filename="anharmonic_oscillator_wigner_mpi_initial_odd.xsil">
+      <dependencies>odds</dependencies>
+    </breakpoint>
+    
+    <integrate algorithm="ARK45" cutoff="1e-3" tolerance="1e-5" interval="7.0e-1" steps="100000">
+      <samples>20 20 20 20</samples>
+      <operators dimensions="r m">
+        <integration_vectors>evens</integration_vectors>
+        <![CDATA[
+          const double M = 2*m;
+          dhE_dt = -i*omega*M*hE - i*g*(r*r-1.0)*M*hE;
+        ]]>
+      </operators>
+      <operators dimensions="s m">
+        <integration_vectors>odds</integration_vectors>
+        <![CDATA[
+          const double M = 2*m+1.0;
+          dhO_dt = -i*omega*M*hO - i*g*(s*s-1.0)*M*hO;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <!-- Any dimension not mentioned is assumed to be in real space and its middle element will be sampled -->
+        <!-- Note that this is different default behaviour to the filter operator. To integrate, put in a dimension -->
+        <!-- with zero lattice points. -->
+        <!-- Note that dimensions can be in any order. Not that I can think of a reason why you would want to do that -->
+        <dimension name="r" fourier_space="no" />
+        <dimension name="theta" fourier_space="no" />
+        <moments>WER</moments>
+        <dependencies>WignerEven</dependencies>
+        <![CDATA[
+          WER = WE;
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes">
+        <dimension name="s" fourier_space="no" />
+        <dimension name="theta" />
+        <moments>WOR</moments>
+        <dependencies>WignerOdd</dependencies>
+        <![CDATA[
+          WOR = WO;
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes">
+        <dimension name="m"/>
+        <dimension name="r" />
+        <moments>hER hEI</moments>
+        <dependencies>evens</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(hE);
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes">
+        <dimension name="m"/>
+        <dimension name="s" />
+        <moments>hOR hOI</moments>
+        <dependencies>odds</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(hO);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version 0.4 "Soylent Green is Purple!" (r2106)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+m s hOR hOI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>21</Dim>
+    <Dim>64</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+anharmonic_oscillator_wigner_mpi_initial_odd.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/fast/anharmonic_oscillator_wigner_mpi_parsing.xmds b/testsuite/fast/anharmonic_oscillator_wigner_mpi_parsing.xmds
new file mode 100644
index 0000000..b3d6c55
--- /dev/null
+++ b/testsuite/fast/anharmonic_oscillator_wigner_mpi_parsing.xmds
@@ -0,0 +1,162 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 2 ./anharmonic_oscillator_wigner_mpi_parsing</command_line>
+    <input_xsil_file name="anharmonic_oscillator_wigner_mpi_initial_even.xsil" />
+    <input_xsil_file name="anharmonic_oscillator_wigner_mpi_initial_odd.xsil" />
+    <xsil_file name="anharmonic_oscillator_wigner_mpi_parsing.xsil" expected="anharmonic_oscillator_wigner_mpi_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>anharmonic_oscillator_wigner_mpi_parsing</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simulation of the Truncated Wigner function for an anharmonic oscillator with the initial state
+    being a coherent state.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient"/>
+    <globals>
+      <![CDATA[
+
+      /* system constants */
+        const real omega = 0.0;
+        const real g = 1.0;
+        
+      /* initial state constants */
+        const real alpha_0 = 3.0;
+        
+      ]]>
+    </globals>
+    <validation kind="run-time" />
+  </features>
+  
+  <driver name="distributed-mpi" />
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="m" type="integer" lattice="21" domain="(0, 20)" />
+      <dimension name="r" lattice="64"  domain="(0, 6)" transform="dct" />
+      <dimension name="s" lattice="64"  domain="(0, 6)" transform="dst" />
+      <dimension name="theta" lattice="32"  domain="(-M_PI, M_PI)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="evens" dimensions="m r" type="complex">
+    <components>
+      hE
+    </components>
+    <initialisation kind="xsil">
+      <filename>anharmonic_oscillator_wigner_mpi_initial_even.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="odds" dimensions="m s" type="complex">
+    <components>
+      hO
+    </components>
+    <initialisation kind="xsil">
+      <filename>anharmonic_oscillator_wigner_mpi_initial_odd.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="trig" dimensions="m theta" type="real">
+    <components>cos_me sin_me cos_mo sin_mo</components>
+    <initialisation>
+      <![CDATA[
+        cos_me = cos(2.0*m*theta);
+        sin_me = sin(2.0*m*theta);
+        cos_mo = cos((2.0*m+1.0)*theta);
+        sin_mo = sin((2.0*m+1.0)*theta);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="WignerEven" dimensions="r theta" type="real">
+    <components>WE</components>
+    <evaluation>
+      <dependencies>evens trig</dependencies>
+      <![CDATA[
+        WE = hE.Re()*cos_me + hE.Im()*sin_me;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <computed_vector name="WignerOdd" dimensions="s theta" type="real">
+    <components>WO</components>
+    <evaluation>
+      <dependencies>odds trig</dependencies>
+      <![CDATA[
+        WO = hO.Re()*cos_mo + hO.Im()*sin_mo;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" cutoff="1e-3" tolerance="1e-5" interval="7.0e-1" steps="100000">
+      <samples>20 20 20 20 20 20</samples>
+      <operators>
+        <integration_vectors>evens</integration_vectors>
+        <![CDATA[
+          const real M = 2*m;
+          dhE_dt = -i*omega*M*hE - i*g*(r*r-1.0)*M*hE;
+        ]]>
+      </operators>
+      <operators>
+        <integration_vectors>odds</integration_vectors>
+        <![CDATA[
+          const real M = 2*m+1.0;
+          dhO_dt = -i*omega*M*hO - i*g*(s*s-1.0)*M*hO;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="r theta" initial_sample="yes">
+        <moments>WER</moments>
+        <dependencies>WignerEven</dependencies>
+        <![CDATA[
+          WER = WE;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="s theta" initial_sample="yes">
+        <moments>WOR</moments>
+        <dependencies>WignerOdd</dependencies>
+        <![CDATA[
+          WOR = WO;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="m r" initial_sample="yes">
+        <moments>hER hEI</moments>
+        <dependencies>evens</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(hE);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="m s" initial_sample="yes">
+        <moments>hOR hOI</moments>
+        <dependencies>odds</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(hO);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="m kr" initial_sample="yes">
+        <moments>hER hEI</moments>
+        <dependencies>evens</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(hE);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="m ks" initial_sample="yes">
+        <moments>hOR hOI</moments>
+        <dependencies>odds</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(hO);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/fast/bessel_cosine_evolution.xmds b/testsuite/fast/bessel_cosine_evolution.xmds
new file mode 100644
index 0000000..1bbe138
--- /dev/null
+++ b/testsuite/fast/bessel_cosine_evolution.xmds
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <input_xsil_file name="bessel_cosine_groundstate_breakpoint_expected.xsil" />
+    <xsil_file name="bessel_cosine_evolution.xsil" expected="bessel_cosine_evolution_expected.xsil" absolute_tolerance="1e10" relative_tolerance="8e-5" />
+  </testing>
+  
+  <name>bessel_cosine_evolution</name>
+  <author>Graham Dennis</author>
+  <description>
+    Evolve the 3D ground state of a Rubidium BEC in a harmonic magnetic trap assuming
+    cylindrical symmetry about the z axis and reflection symmetry about z=0.
+    This permits us to use the cylindrical bessel functions to expand the solution transverse
+    to z and a cosine series to expand the solution along z.
+    
+    This testcase tests using both Fourier transforms and Matrix transforms in a single simulation.
+    
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <globals>
+      <![CDATA[
+        const real omegaz = 2*M_PI*20;
+        const real omegarho = 2*M_PI*200;
+        const real hbar = 1.05457148e-34;
+        const real M = 1.409539200000000e-25;
+        const real g = 9.8;
+        const real scatteringLength = 5.57e-9;
+        const real Uint = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+        const complex miUint_hbar = -i*Uint/hbar;
+        const real Nparticles = 5.0e5;
+
+        /* offset constants */
+        const real EnergyOffset = pow(15.0*Nparticles*Uint*omegaz*omegarho*omegarho/(8*M_PI), 2.0/5.0)
+                                    * pow(M/2.0, 3.0/5.0);
+
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="z" lattice="32"  domain="(0.0, 1.0e-4)" transform="dct" volume_prefactor="2.0" />
+      <dimension name="r" lattice="32"  domain="(0.0, 1.0e-5)" transform="bessel" volume_prefactor="2.0*M_PI"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" type="complex">
+    <components>
+      V1
+    </components>
+    <initialisation>
+      <![CDATA[
+        real Vtrap = 0.5*M*(omegarho*omegarho*r*r + omegaz*omegaz*z*z);
+      
+        V1  = -i/hbar*(Vtrap - EnergyOffset);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation kind="hdf5">
+      <filename>bessel_cosine_groundstate_breakpoint_expected.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-6" interval="1e-3">
+      <samples>10</samples>
+      <operators>
+        <operator kind="ip" constant="yes" type="imaginary">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -i*0.5*hbar/M*(kr*kr + kz*kz);
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] + (V1 + miUint_hbar*mod2(phi))*phi;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="hdf5">
+      <sampling_group basis="r z" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/fast/bessel_cosine_evolution_expected.h5 b/testsuite/fast/bessel_cosine_evolution_expected.h5
new file mode 100644
index 0000000..c59114a
Binary files /dev/null and b/testsuite/fast/bessel_cosine_evolution_expected.h5 differ
diff --git a/testsuite/fast/bessel_cosine_evolution_expected.xsil b/testsuite/fast/bessel_cosine_evolution_expected.xsil
new file mode 100644
index 0000000..0b41983
--- /dev/null
+++ b/testsuite/fast/bessel_cosine_evolution_expected.xsil
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <input_xsil_file name="bessel_cosine_groundstate_breakpoint_expected.xsil" />
+    <xsil_file name="bessel_cosine_evolution.xsil" expected="bessel_cosine_evolution_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>bessel_cosine_evolution</name>
+  <author>Graham Dennis</author>
+  <description>
+    Evolve the 3D ground state of a Rubidium BEC in a harmonic magnetic trap assuming
+    cylindrical symmetry about the z axis and reflection symmetry about z=0.
+    This permits us to use the cylindrical bessel functions to expand the solution transverse
+    to z and a cosine series to expand the solution along z.
+    
+    This testcase tests using both Fourier transforms and Matrix transforms in a single simulation.
+    
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <globals>
+      <![CDATA[
+        const real omegaz = 2*M_PI*20;
+        const real omegarho = 2*M_PI*200;
+        const real hbar = 1.05457148e-34;
+        const real M = 1.409539200000000e-25;
+        const real g = 9.8;
+        const real scatteringLength = 5.57e-9;
+        const real Uint = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+        const complex miUint_hbar = -i*Uint/hbar;
+        const real Nparticles = 5.0e5;
+
+        /* offset constants */
+        const real EnergyOffset = pow(15.0*Nparticles*Uint*omegaz*omegarho*omegarho/(8*M_PI), 2.0/5.0)
+                                    * pow(M/2.0, 3.0/5.0);
+
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="z" lattice="32"  domain="(0.0, 1.0e-4)" transform="dct" />
+      <dimension name="r" lattice="32"  domain="(0.0, 1.0e-5)" transform="bessel" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" type="complex">
+    <components>
+      V1
+    </components>
+    <initialisation>
+      <![CDATA[
+        real Vtrap = 0.5*M*(omegarho*omegarho*r*r + omegaz*omegaz*z*z);
+      
+        V1  = -i/hbar*(Vtrap - EnergyOffset);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation kind="hdf5">
+      <filename>bessel_cosine_groundstate_breakpoint_expected.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-6" interval="1e-3">
+      <samples>10</samples>
+      <operators>
+        <operator kind="ip" constant="yes" type="imaginary">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -i*0.5*hbar/M*(kr*kr + kz*kz);
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] + (V1 + miUint_hbar*mod2(phi))*phi;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="hdf5">
+      <sampling_group initial_sample="no">
+        <dimension name="r" />
+        <dimension name="z" />
+        <moments>dens</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t z r dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>10</Dim>
+    <Dim>32</Dim>
+    <Dim>32</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+bessel_cosine_evolution_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/fast/bessel_cosine_groundstate.xmds b/testsuite/fast/bessel_cosine_groundstate.xmds
new file mode 100644
index 0000000..133ec6c
--- /dev/null
+++ b/testsuite/fast/bessel_cosine_groundstate.xmds
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="bessel_cosine_groundstate.xsil" expected="bessel_cosine_groundstate_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="bessel_cosine_groundstate_breakpoint.xsil" expected="bessel_cosine_groundstate_breakpoint_expected.xsil" absolute_tolerance="1e0" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>bessel_cosine_groundstate</name>
+  <author>Graham Dennis</author>
+  <description>
+    Calculate the 3D ground state of a Rubidium BEC in a harmonic magnetic trap assuming
+    cylindrical symmetry about the z axis and reflection symmetry about z=0.
+    This permits us to use the cylindrical bessel functions to expand the solution transverse
+    to z and a cosine series to expand the solution along z.
+    
+    This testcase tests using both Fourier transforms and Matrix transforms in a single simulation.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <globals>
+      <![CDATA[
+        const real omegaz = 2*M_PI*20;
+        const real omegarho = 2*M_PI*200;
+        const real hbar = 1.05457148e-34;
+        const real M = 1.409539200000000e-25;
+        const real g = 9.8;
+        const real scatteringLength = 5.57e-9;
+        const real Uint = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+        const real Nparticles = 5.0e5;
+
+        /* offset constants */
+        const real EnergyOffset = pow(15.0*Nparticles*Uint*omegaz*omegarho*omegarho/(8*M_PI), 2.0/5.0)
+                                    * pow(M/2.0, 3.0/5.0);
+
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="z" lattice="32"  domain="(0.0, 1.0e-4)" transform="dct" volume_prefactor="2.0" />
+      <dimension name="r" lattice="32"  domain="(0.0, 1.0e-5)" transform="bessel" volume_prefactor="2.0*M_PI"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" type="complex">
+    <components>
+      V1
+    </components>
+    <initialisation>
+      <![CDATA[
+        real Vtrap = 0.5*M*(omegarho*omegarho*r*r + omegaz*omegaz*z*z);
+      
+        V1  = -i/hbar*(Vtrap - EnergyOffset);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+      
+        if ((abs(r) < 0.9e-5) && abs(z) < 0.9e-4) {
+          phi = 1.0; //sqrt(Nparticles/2.0e-5);
+          // This will be automatically normalised later
+        } else {
+          phi = 0.0;
+        }
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>
+      Ncalc
+    </components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="1e-4" steps="1000">
+      <samples>100</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi *= sqrt(Nparticles/Ncalc);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*hbar/M*(kr*kr + kz*kz);
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] - (i*V1 + Uint/hbar*mod2(phi))*phi;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="bessel_cosine_groundstate_breakpoint.xsil" format="hdf5">
+      <dependencies>wavefunction</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="r z" initial_sample="no">
+        <moments>norm_dens</moments>
+        <dependencies>wavefunction normalisation</dependencies>
+        <![CDATA[
+          norm_dens = mod2(phi)/Ncalc;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/fast/bessel_cosine_groundstate_breakpoint_expected.h5 b/testsuite/fast/bessel_cosine_groundstate_breakpoint_expected.h5
new file mode 100644
index 0000000..e562835
Binary files /dev/null and b/testsuite/fast/bessel_cosine_groundstate_breakpoint_expected.h5 differ
diff --git a/testsuite/fast/bessel_cosine_groundstate_breakpoint_expected.xsil b/testsuite/fast/bessel_cosine_groundstate_breakpoint_expected.xsil
new file mode 100644
index 0000000..98b4004
--- /dev/null
+++ b/testsuite/fast/bessel_cosine_groundstate_breakpoint_expected.xsil
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="bessel_cosine_groundstate.xsil" expected="bessel_cosine_groundstate_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="bessel_cosine_groundstate_breakpoint.xsil" expected="bessel_cosine_groundstate_breakpoint_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>bessel_cosine_groundstate</name>
+  <author>Graham Dennis</author>
+  <description>
+    Calculate the 3D ground state of a Rubidium BEC in a harmonic magnetic trap assuming
+    cylindrical symmetry about the z axis and reflection symmetry about z=0.
+    This permits us to use the cylindrical bessel functions to expand the solution transverse
+    to z and a cosine series to expand the solution along z.
+    
+    This testcase tests using both Fourier transforms and Matrix transforms in a single simulation.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <fftw />
+    <mmt />
+    <!-- <openmp /> -->
+    <globals>
+      <![CDATA[
+        const real omegaz = 2*M_PI*20;
+        const real omegarho = 2*M_PI*200;
+        const real hbar = 1.05457148e-34;
+        const real M = 1.409539200000000e-25;
+        const real g = 9.8;
+        const real scatteringLength = 5.57e-9;
+        const real Uint = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+        const real Nparticles = 5.0e5;
+
+        /* offset constants */
+        const real EnergyOffset = pow(15.0*Nparticles*Uint*omegaz*omegarho*omegarho/(8*M_PI), 2.0/5.0)
+                                    * pow(M/2.0, 3.0/5.0);
+
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="z" lattice="32"  domain="(0.0, 1.0e-4)" transform="dct" />
+      <dimension name="r" lattice="32"  domain="(0.0, 1.0e-5)" transform="bessel" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" type="complex">
+    <components>
+      V1
+    </components>
+    <initialisation>
+      <![CDATA[
+        real Vtrap = 0.5*M*(omegarho*omegarho*r*r + omegaz*omegaz*z*z);
+      
+        V1  = -i/hbar*(Vtrap - EnergyOffset);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+      
+        if ((abs(r) < 0.9e-5) && abs(z) < 0.9e-4) {
+          phi = 1.0; //sqrt(Nparticles/2.0e-5);
+          // This will be automatically normalised later
+        } else {
+          phi = 0.0;
+        }
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>
+      Ncalc
+    </components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = 2.0*(2.0*M_PI)*mod2(phi);
+        // Factor of two is there due to z axis only covering half the condensate.
+        // Factor of two-pi is there for integration over the angular coordinate.
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="1e-4" steps="1000">
+      <samples>100</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi *= sqrt(Nparticles/Ncalc);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*hbar/M*(kr*kr + kz*kz);
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] - (i*V1 + Uint/hbar*mod2(phi))*phi;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="bessel_cosine_groundstate_breakpoint.xsil" format="hdf5">
+      <dependencies>wavefunction</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+      <sampling_group initial_sample="no">
+        <dimension name="r" />
+        <dimension name="z" />
+        <moments>norm_dens</moments>
+        <dependencies>wavefunction normalisation</dependencies>
+        <![CDATA[
+          norm_dens = mod2(phi)/Ncalc;
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+z r phiR phiI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>32</Dim>
+    <Dim>32</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+bessel_cosine_groundstate_breakpoint_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/fast/bessel_cosine_groundstate_expected.xsil b/testsuite/fast/bessel_cosine_groundstate_expected.xsil
new file mode 100644
index 0000000..ead9e7c
--- /dev/null
+++ b/testsuite/fast/bessel_cosine_groundstate_expected.xsil
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="bessel_cosine_groundstate.xsil" expected="bessel_cosine_groundstate_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="bessel_cosine_groundstate_breakpoint.xsil" expected="bessel_cosine_groundstate_breakpoint_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>bessel_cosine_groundstate</name>
+  <author>Graham Dennis</author>
+  <description>
+    Calculate the 3D ground state of a Rubidium BEC in a harmonic magnetic trap assuming
+    cylindrical symmetry about the z axis and reflection symmetry about z=0.
+    This permits us to use the cylindrical bessel functions to expand the solution transverse
+    to z and a cosine series to expand the solution along z.
+    
+    This testcase tests using both Fourier transforms and Matrix transforms in a single simulation.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <fftw />
+    <mmt />
+    <!-- <openmp /> -->
+    <globals>
+      <![CDATA[
+        const real omegaz = 2*M_PI*20;
+        const real omegarho = 2*M_PI*200;
+        const real hbar = 1.05457148e-34;
+        const real M = 1.409539200000000e-25;
+        const real g = 9.8;
+        const real scatteringLength = 5.57e-9;
+        const real Uint = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+        const real Nparticles = 5.0e5;
+
+        /* offset constants */
+        const real EnergyOffset = pow(15.0*Nparticles*Uint*omegaz*omegarho*omegarho/(8*M_PI), 2.0/5.0)
+                                    * pow(M/2.0, 3.0/5.0);
+
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="z" lattice="32"  domain="(0.0, 1.0e-4)" transform="dct" />
+      <dimension name="r" lattice="32"  domain="(0.0, 1.0e-5)" transform="bessel" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" type="complex">
+    <components>
+      V1
+    </components>
+    <initialisation>
+      <![CDATA[
+        real Vtrap = 0.5*M*(omegarho*omegarho*r*r + omegaz*omegaz*z*z);
+      
+        V1  = -i/hbar*(Vtrap - EnergyOffset);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+      
+        if ((abs(r) < 0.9e-5) && abs(z) < 0.9e-4) {
+          phi = 1.0; //sqrt(Nparticles/2.0e-5);
+          // This will be automatically normalised later
+        } else {
+          phi = 0.0;
+        }
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>
+      Ncalc
+    </components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = 2.0*(2.0*M_PI)*mod2(phi);
+        // Factor of two is there due to z axis only covering half the condensate.
+        // Factor of two-pi is there for integration over the angular coordinate.
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="1e-4" steps="1000">
+      <samples>100</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi *= sqrt(Nparticles/Ncalc);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*hbar/M*(kr*kr + kz*kz);
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] - (i*V1 + Uint/hbar*mod2(phi))*phi;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="bessel_cosine_groundstate_breakpoint.xsil" format="hdf5">
+      <dependencies>wavefunction</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+      <sampling_group initial_sample="no">
+        <dimension name="r" />
+        <dimension name="z" />
+        <moments>norm_dens</moments>
+        <dependencies>wavefunction normalisation</dependencies>
+        <![CDATA[
+          norm_dens = mod2(phi)/Ncalc;
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t z r norm_dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>100</Dim>
+    <Dim>32</Dim>
+    <Dim>32</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+bessel_cosine_groundstate_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/fast/bessel_cosine_groundstate_expected_mg0.dat b/testsuite/fast/bessel_cosine_groundstate_expected_mg0.dat
new file mode 100644
index 0000000..ebe0270
Binary files /dev/null and b/testsuite/fast/bessel_cosine_groundstate_expected_mg0.dat differ
diff --git a/testsuite/fast/eigenvalues.xmds b/testsuite/fast/eigenvalues.xmds
new file mode 100644
index 0000000..4f68a73
--- /dev/null
+++ b/testsuite/fast/eigenvalues.xmds
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="eigenvalues_break.xsil" expected="eigenvalues_break_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+    <xsil_file name="eigenvalues.xsil" expected="eigenvalues_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>eigenvalues</name>
+  <author>Graham Dennis</author>
+  <description>
+    1D TW model of the uniform Peaks system.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <fftw plan="exhaustive" />
+    <globals>
+      <![CDATA[
+      /* physical constants  */
+       const double omegaz = 2*M_PI*55.0;
+       const double omegarho = 2*M_PI*1020.0;
+       const double hbar = 1.05457148e-34;
+       const double M = 4.0026032*1.66053886e-27;
+       const double scatteringLength = 7.51e-9;
+       const double Uint3 = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+       const double Nparticles = 2.0e6;
+       const double mu = pow(15*Nparticles*Uint3*omegarho*omegarho*omegaz/(8.0*M_PI)*pow(M/2,3.0/2.0),2.0/5.0);
+       const double Uint = Uint3*5.0*omegarho*omegarho*M/(4.0*M_PI*mu);
+       const double Uint_hbar = Uint/hbar;
+       const complex miUint_hbar = -i*Uint_hbar;
+       const double otherScatteringLength = 5.56e-9;
+       const double kappa = otherScatteringLength/scatteringLength;
+       double Delta;
+       const double hbar_M = hbar/M;
+       const double Omega = 2.0*M_PI*3e3;
+       
+       double mu0 = hbar*1.7786e3*2.0*M_PI;
+       double nu = 6.649299328e3;//4.4046e4; // Hertz
+       
+      ]]>
+    </globals>
+    <validation kind="run-time" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="kz" lattice="32"  domain="(0, 3e6)" />
+      <!-- <dimension name="kz" lattice="1024"  domain="(1.3220e6, 1.3221e6)" /> -->
+      <dimension name="p" domain="(1, 4)" type="integer" aliases="q" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="wavefunction" dimensions="" type="complex">
+    <components>
+      phi1 phi0
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi1 = sqrt(mu/Uint);
+        phi0 = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="matrixterms" dimensions="kz p q" initial_basis="kz" type="complex">
+    <components>matrix</components>
+    <initialisation>
+      <![CDATA[
+        if (p == q) {
+          matrix = 1.0;
+        } else {
+          matrix = 0.0;
+        }
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="hamiltonian_matrix" dimensions="kz p q" type="complex">
+    <components>h_matrix</components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        const double kineticEnergy = 0.5*hbar*hbar*kz*kz/M;
+        if (p == 1 && q == 1) h_matrix = Uint*mod2(phi1)+kineticEnergy-mu0;
+        if (p == 1 && q == 2) h_matrix = Uint*phi1*phi1;
+        if (p == 1 && q == 3) h_matrix = Uint*phi1*conj(phi0)+hbar*Omega;
+        if (p == 1 && q == 4) h_matrix = Uint*phi1*phi0;
+        
+        if (p == 2 && q == 1) h_matrix = -Uint*conj(phi1*phi1);
+        if (p == 2 && q == 2) h_matrix = -Uint*mod2(phi1)-kineticEnergy+mu0;
+        if (p == 2 && q == 3) h_matrix = -Uint*conj(phi1 * phi0);
+        if (p == 2 && q == 4) h_matrix = -Uint*conj(phi1)*phi0 - hbar*Omega;
+        
+        if (p == 3 && q == 1) h_matrix = Uint*conj(phi1)*phi0 + hbar*Omega;
+        if (p == 3 && q == 2) h_matrix = Uint*phi0*phi1;
+        if (p == 3 && q == 3) h_matrix = Uint*(2.0*kappa-1.0)*mod2(phi0)-mu0+kineticEnergy;
+        if (p == 3 && q == 4) h_matrix = Uint*kappa*phi0*phi0;
+        
+        if (p == 4 && q == 1) h_matrix = -Uint*conj(phi0*phi1);
+        if (p == 4 && q == 2) h_matrix = -Uint*phi1*conj(phi0)-hbar*Omega;
+        if (p == 4 && q == 3) h_matrix = -Uint*kappa*conj(phi0*phi0);
+        if (p == 4 && q == 4) h_matrix = -Uint*(2.0*kappa-1.0)*mod2(phi0)-kineticEnergy+mu0;
+        
+        h_matrix *= -i/hbar;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" interval="1.0/nu" tolerance="1e-8">
+      <samples>20 20</samples>
+      <operators dimensions="">
+        <integration_vectors>wavefunction</integration_vectors>
+        <![CDATA[
+          dphi1_dt = - i/hbar*( - mu0)*phi1 -i*Omega*phi0;
+          dphi0_dt = - i/hbar*( - Uint*(1.0-kappa)*mod2(phi0) - mu0)*phi0 -i*Omega*phi1;
+        ]]>
+      </operators>
+      <operators dimensions="kz p q">
+        <integration_vectors>matrixterms</integration_vectors>
+        <dependencies>wavefunction hamiltonian_matrix</dependencies>
+        <![CDATA[
+          dmatrix_dt = 0.0;
+          for (long pp = 1; pp <= 4; pp++) {
+            dmatrix_dt += h_matrix(q=> pp)*matrix(p=> pp);
+          }
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="eigenvalues_break.xsil" format="hdf5">
+      <dependencies>matrixterms</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="hdf5">
+      <sampling_group initial_sample="yes">
+        <moments>phi1R phi1I phi0R phi0I</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(phi1); _SAMPLE_COMPLEX(phi0);
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes" basis="kz p q">
+        <moments>matrixR matrixI</moments>
+        <dependencies>matrixterms</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(matrix);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/fast/eigenvalues_break_expected.h5 b/testsuite/fast/eigenvalues_break_expected.h5
new file mode 100644
index 0000000..5000c46
Binary files /dev/null and b/testsuite/fast/eigenvalues_break_expected.h5 differ
diff --git a/testsuite/fast/eigenvalues_break_expected.xsil b/testsuite/fast/eigenvalues_break_expected.xsil
new file mode 100644
index 0000000..96c64e7
--- /dev/null
+++ b/testsuite/fast/eigenvalues_break_expected.xsil
@@ -0,0 +1,176 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="eigenvalues_break.xsil" expected="eigenvalues_break_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+    <xsil_file name="eigenvalues.xsil" expected="eigenvalues_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>eigenvalues</name>
+  <author>Graham Dennis</author>
+  <description>
+    1D TW model of the uniform Peaks system.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <fftw plan="exhaustive" />
+    <globals>
+      <![CDATA[
+      /* physical constants  */
+       const double omegaz = 2*M_PI*55.0;
+       const double omegarho = 2*M_PI*1020.0;
+       const double hbar = 1.05457148e-34;
+       const double M = 4.0026032*1.66053886e-27;
+       const double scatteringLength = 7.51e-9;
+       const double Uint3 = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+       const double Nparticles = 2.0e6;
+       const double mu = pow(15*Nparticles*Uint3*omegarho*omegarho*omegaz/(8.0*M_PI)*pow(M/2,3.0/2.0),2.0/5.0);
+       const double Uint = Uint3*5.0*omegarho*omegarho*M/(4.0*M_PI*mu);
+       const double Uint_hbar = Uint/hbar;
+       const complex miUint_hbar = -i*Uint_hbar;
+       const double otherScatteringLength = 5.56e-9;
+       const double kappa = otherScatteringLength/scatteringLength;
+       double Delta;
+       const double hbar_M = hbar/M;
+       const double Omega = 2.0*M_PI*3e3;
+       
+       double mu0 = hbar*1.7786e3*2.0*M_PI;
+       double nu = 6.649299328e3;//4.4046e4; // Hertz
+       
+      ]]>
+    </globals>
+    <validation kind="run-time" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="kz" lattice="32"  domain="(0, 3e6)" />
+      <!-- <dimension name="kz" lattice="1024"  domain="(1.3220e6, 1.3221e6)" /> -->
+      <dimension name="p" domain="(1, 4)" type="integer" aliases="q" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="wavefunction" dimensions="" type="complex">
+    <components>
+      phi1 phi0
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi1 = sqrt(mu/Uint);
+        phi0 = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="matrixterms" dimensions="kz p q" initial_basis="kz" type="complex">
+    <components>matrix</components>
+    <initialisation>
+      <![CDATA[
+        if (p == q) {
+          matrix = 1.0;
+        } else {
+          matrix = 0.0;
+        }
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="hamiltonian_matrix" dimensions="kz p q" type="complex">
+    <components>h_matrix</components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        const double kineticEnergy = 0.5*hbar*hbar*kz*kz/M;
+        if (p == 1 && q == 1) h_matrix = Uint*mod2(phi1)+kineticEnergy-mu0;
+        if (p == 1 && q == 2) h_matrix = Uint*phi1*phi1;
+        if (p == 1 && q == 3) h_matrix = Uint*phi1*conj(phi0)+hbar*Omega;
+        if (p == 1 && q == 4) h_matrix = Uint*phi1*phi0;
+        
+        if (p == 2 && q == 1) h_matrix = -Uint*conj(phi1*phi1);
+        if (p == 2 && q == 2) h_matrix = -Uint*mod2(phi1)-kineticEnergy+mu0;
+        if (p == 2 && q == 3) h_matrix = -Uint*conj(phi1 * phi0);
+        if (p == 2 && q == 4) h_matrix = -Uint*conj(phi1)*phi0 - hbar*Omega;
+        
+        if (p == 3 && q == 1) h_matrix = Uint*conj(phi1)*phi0 + hbar*Omega;
+        if (p == 3 && q == 2) h_matrix = Uint*phi0*phi1;
+        if (p == 3 && q == 3) h_matrix = Uint*(2.0*kappa-1.0)*mod2(phi0)-mu0+kineticEnergy;
+        if (p == 3 && q == 4) h_matrix = Uint*kappa*phi0*phi0;
+        
+        if (p == 4 && q == 1) h_matrix = -Uint*conj(phi0*phi1);
+        if (p == 4 && q == 2) h_matrix = -Uint*phi1*conj(phi0)-hbar*Omega;
+        if (p == 4 && q == 3) h_matrix = -Uint*kappa*conj(phi0*phi0);
+        if (p == 4 && q == 4) h_matrix = -Uint*(2.0*kappa-1.0)*mod2(phi0)-kineticEnergy+mu0;
+        
+        h_matrix *= -i/hbar;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" interval="1.0/nu" tolerance="1e-8">
+      <samples>20 20</samples>
+      <operators dimensions="">
+        <integration_vectors>wavefunction</integration_vectors>
+        <![CDATA[
+          dphi1_dt = - i/hbar*( - mu0)*phi1 -i*Omega*phi0;
+          dphi0_dt = - i/hbar*( - Uint*(1.0-kappa)*mod2(phi0) - mu0)*phi0 -i*Omega*phi1;
+        ]]>
+      </operators>
+      <operators dimensions="kz p q">
+        <integration_vectors>matrixterms</integration_vectors>
+        <dependencies>wavefunction hamiltonian_matrix</dependencies>
+        <![CDATA[
+          dmatrix_dt = 0.0;
+          for (long pp = 1; pp <= 4; pp++) {
+            dmatrix_dt += h_matrix(q=> pp)*matrix(p=> pp);
+          }
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="eigenvalues_break.xsil" format="hdf5">
+      <dependencies>matrixterms</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="hdf5">
+      <sampling_group initial_sample="yes">
+        <moments>phi1R phi1I phi0R phi0I</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(phi1); _SAMPLE_COMPLEX(phi0);
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes" basis="kz p q">
+        <moments>matrixR matrixI</moments>
+        <dependencies>matrixterms</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(matrix);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+kz p q matrixR matrixI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>32</Dim>
+    <Dim>4</Dim>
+    <Dim>4</Dim>
+    <Dim>5</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+eigenvalues_break_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/fast/eigenvalues_expected.h5 b/testsuite/fast/eigenvalues_expected.h5
new file mode 100644
index 0000000..eeac4da
Binary files /dev/null and b/testsuite/fast/eigenvalues_expected.h5 differ
diff --git a/testsuite/fast/eigenvalues_expected.xsil b/testsuite/fast/eigenvalues_expected.xsil
new file mode 100644
index 0000000..476253d
--- /dev/null
+++ b/testsuite/fast/eigenvalues_expected.xsil
@@ -0,0 +1,194 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="eigenvalues_break.xsil" expected="eigenvalues_break_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+    <xsil_file name="eigenvalues.xsil" expected="eigenvalues_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>eigenvalues</name>
+  <author>Graham Dennis</author>
+  <description>
+    1D TW model of the uniform Peaks system.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <fftw plan="exhaustive" />
+    <globals>
+      <![CDATA[
+      /* physical constants  */
+       const double omegaz = 2*M_PI*55.0;
+       const double omegarho = 2*M_PI*1020.0;
+       const double hbar = 1.05457148e-34;
+       const double M = 4.0026032*1.66053886e-27;
+       const double scatteringLength = 7.51e-9;
+       const double Uint3 = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+       const double Nparticles = 2.0e6;
+       const double mu = pow(15*Nparticles*Uint3*omegarho*omegarho*omegaz/(8.0*M_PI)*pow(M/2,3.0/2.0),2.0/5.0);
+       const double Uint = Uint3*5.0*omegarho*omegarho*M/(4.0*M_PI*mu);
+       const double Uint_hbar = Uint/hbar;
+       const complex miUint_hbar = -i*Uint_hbar;
+       const double otherScatteringLength = 5.56e-9;
+       const double kappa = otherScatteringLength/scatteringLength;
+       double Delta;
+       const double hbar_M = hbar/M;
+       const double Omega = 2.0*M_PI*3e3;
+       
+       double mu0 = hbar*1.7786e3*2.0*M_PI;
+       double nu = 6.649299328e3;//4.4046e4; // Hertz
+       
+      ]]>
+    </globals>
+    <validation kind="run-time" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="kz" lattice="32"  domain="(0, 3e6)" />
+      <!-- <dimension name="kz" lattice="1024"  domain="(1.3220e6, 1.3221e6)" /> -->
+      <dimension name="p" domain="(1, 4)" type="integer" aliases="q" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="wavefunction" dimensions="" type="complex">
+    <components>
+      phi1 phi0
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi1 = sqrt(mu/Uint);
+        phi0 = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="matrixterms" dimensions="kz p q" initial_basis="kz" type="complex">
+    <components>matrix</components>
+    <initialisation>
+      <![CDATA[
+        if (p == q) {
+          matrix = 1.0;
+        } else {
+          matrix = 0.0;
+        }
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="hamiltonian_matrix" dimensions="kz p q" type="complex">
+    <components>h_matrix</components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        const double kineticEnergy = 0.5*hbar*hbar*kz*kz/M;
+        if (p == 1 && q == 1) h_matrix = Uint*mod2(phi1)+kineticEnergy-mu0;
+        if (p == 1 && q == 2) h_matrix = Uint*phi1*phi1;
+        if (p == 1 && q == 3) h_matrix = Uint*phi1*conj(phi0)+hbar*Omega;
+        if (p == 1 && q == 4) h_matrix = Uint*phi1*phi0;
+        
+        if (p == 2 && q == 1) h_matrix = -Uint*conj(phi1*phi1);
+        if (p == 2 && q == 2) h_matrix = -Uint*mod2(phi1)-kineticEnergy+mu0;
+        if (p == 2 && q == 3) h_matrix = -Uint*conj(phi1 * phi0);
+        if (p == 2 && q == 4) h_matrix = -Uint*conj(phi1)*phi0 - hbar*Omega;
+        
+        if (p == 3 && q == 1) h_matrix = Uint*conj(phi1)*phi0 + hbar*Omega;
+        if (p == 3 && q == 2) h_matrix = Uint*phi0*phi1;
+        if (p == 3 && q == 3) h_matrix = Uint*(2.0*kappa-1.0)*mod2(phi0)-mu0+kineticEnergy;
+        if (p == 3 && q == 4) h_matrix = Uint*kappa*phi0*phi0;
+        
+        if (p == 4 && q == 1) h_matrix = -Uint*conj(phi0*phi1);
+        if (p == 4 && q == 2) h_matrix = -Uint*phi1*conj(phi0)-hbar*Omega;
+        if (p == 4 && q == 3) h_matrix = -Uint*kappa*conj(phi0*phi0);
+        if (p == 4 && q == 4) h_matrix = -Uint*(2.0*kappa-1.0)*mod2(phi0)-kineticEnergy+mu0;
+        
+        h_matrix *= -i/hbar;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" interval="1.0/nu" tolerance="1e-8">
+      <samples>20 20</samples>
+      <operators dimensions="">
+        <integration_vectors>wavefunction</integration_vectors>
+        <![CDATA[
+          dphi1_dt = - i/hbar*( - mu0)*phi1 -i*Omega*phi0;
+          dphi0_dt = - i/hbar*( - Uint*(1.0-kappa)*mod2(phi0) - mu0)*phi0 -i*Omega*phi1;
+        ]]>
+      </operators>
+      <operators dimensions="kz p q">
+        <integration_vectors>matrixterms</integration_vectors>
+        <dependencies>wavefunction hamiltonian_matrix</dependencies>
+        <![CDATA[
+          dmatrix_dt = 0.0;
+          for (long pp = 1; pp <= 4; pp++) {
+            dmatrix_dt += h_matrix(q=> pp)*matrix(p=> pp);
+          }
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="eigenvalues_break.xsil" format="hdf5">
+      <dependencies>matrixterms</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="hdf5">
+      <sampling_group initial_sample="yes">
+        <moments>phi1R phi1I phi0R phi0I</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(phi1); _SAMPLE_COMPLEX(phi0);
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes" basis="kz p q">
+        <moments>matrixR matrixI</moments>
+        <dependencies>matrixterms</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(matrix);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t phi1R phi1I phi0R phi0I 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>21</Dim>
+    <Dim>5</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+eigenvalues_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">4</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>6</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t kz p q matrixR matrixI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>21</Dim>
+    <Dim>32</Dim>
+    <Dim>4</Dim>
+    <Dim>4</Dim>
+    <Dim>6</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/2"/>
+eigenvalues_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/fast/groundstate.xmds b/testsuite/fast/groundstate.xmds
new file mode 100644
index 0000000..282ae7c
--- /dev/null
+++ b/testsuite/fast/groundstate.xmds
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="groundstate.xsil" expected="groundstate_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="groundstate_break.xsil" expected="groundstate_expected_break.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>groundstate</name>
+  <author>Graham Dennis</author>
+  <description>
+    Calculate the ground state of a negative gaussian potential.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="1024"  domain="(-12.0, 12.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" initial_basis="y" type="complex">
+    <components>
+      V1
+    </components>
+    <initialisation>
+      <![CDATA[
+        real Vtrap = -exp(-y*y);
+      
+        V1  = -i*Vtrap;
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" initial_basis="y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+      
+      // This will be automatically normalised later
+      phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components> Ncalc </components>
+    <evaluation>
+      <dependencies basis="y">wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = norm(phi);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="1.0" steps="1000">
+      <samples>50 50 50</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi *= sqrt(1.0/Ncalc);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] - (i*V1)*phi;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="groundstate_break.xsil">
+      <dependencies>wavefunction potential</dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output format="binary">
+    <group>
+      <sampling basis="y" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens = norm(phi);
+        ]]>
+      </sampling>
+    </group>
+    <group>
+      <sampling initial_sample="no">
+        <moments>N</moments>
+        <dependencies>normalisation</dependencies>
+        <![CDATA[
+          N = Ncalc;
+        ]]>
+      </sampling>
+    </group>
+    <group>
+      <sampling basis="y(0)" initial_sample="no">
+        <moments>N</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          N = norm(phi);
+        ]]>
+      </sampling>
+    </group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/fast/groundstate_expected.xsil b/testsuite/fast/groundstate_expected.xsil
new file mode 100644
index 0000000..d946c36
--- /dev/null
+++ b/testsuite/fast/groundstate_expected.xsil
@@ -0,0 +1,184 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="groundstate.xsil" expected="groundstate_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="groundstate_break.xsil" expected="groundstate_expected_break.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>groundstate</name>
+  <author>Graham Dennis</author>
+  <description>
+    Calculate the ground state of a negative gaussian potential.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="1024"  domain="(-12.0, 12.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" initial_basis="y" type="complex">
+    <components>
+      V1
+    </components>
+    <initialisation>
+      <![CDATA[
+        double Vtrap = -exp(-y*y);
+      
+        V1  = -i*Vtrap;
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" initial_basis="y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+      
+      // This will be automatically normalised later
+      phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="double">
+    <components> Ncalc </components>
+    <evaluation>
+      <dependencies fourier_space="y">wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="1.0" steps="1000">
+      <samples>50 50 50</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi *= sqrt(1.0/Ncalc);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] - (i*V1)*phi;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="groundstate_break.xsil">
+      <dependencies>wavefunction potential</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+    <group>
+      <sampling initial_sample="no">
+        <dimension name="y" />
+        <moments>dens</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling>
+    </group>
+    <group>
+      <sampling initial_sample="no">
+        <moments>N</moments>
+        <dependencies>normalisation</dependencies>
+        <![CDATA[
+          N = Ncalc;
+        ]]>
+      </sampling>
+    </group>
+    <group>
+      <sampling initial_sample="no">
+        <moments>N</moments>
+        <dimension name="y" lattice="0" />
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          N = mod2(phi);
+        ]]>
+      </sampling>
+    </group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t y dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>50</Dim>
+    <Dim>1024</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+groundstate_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t N 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>50</Dim>
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+groundstate_expected_mg1.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_3">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t N 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>50</Dim>
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+groundstate_expected_mg2.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/fast/groundstate_expected_break.dat b/testsuite/fast/groundstate_expected_break.dat
new file mode 100644
index 0000000..0483d85
Binary files /dev/null and b/testsuite/fast/groundstate_expected_break.dat differ
diff --git a/testsuite/fast/groundstate_expected_break.xsil b/testsuite/fast/groundstate_expected_break.xsil
new file mode 100644
index 0000000..f0341ee
--- /dev/null
+++ b/testsuite/fast/groundstate_expected_break.xsil
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="groundstate.xsil" expected="groundstate_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="groundstate_break.xsil" expected="groundstate_expected_break.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>groundstate</name>
+  <author>Graham Dennis</author>
+  <description>
+    Calculate the ground state of a negative gaussian potential.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="1024"  domain="(-12.0, 12.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" initial_basis="y" type="complex">
+    <components>
+      V1
+    </components>
+    <initialisation>
+      <![CDATA[
+        double Vtrap = -exp(-y*y);
+      
+        V1  = -i*Vtrap;
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" initial_basis="y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+      
+      // This will be automatically normalised later
+      phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="double">
+    <components> Ncalc </components>
+    <evaluation>
+      <dependencies fourier_space="y">wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="1.0" steps="1000">
+      <samples>50 50 50</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi *= sqrt(1.0/Ncalc);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] - (i*V1)*phi;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="groundstate_break.xsil">
+      <dependencies>wavefunction potential</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+    <group>
+      <sampling initial_sample="no">
+        <dimension name="y" />
+        <moments>dens</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling>
+    </group>
+    <group>
+      <sampling initial_sample="no">
+        <moments>N</moments>
+        <dependencies>normalisation</dependencies>
+        <![CDATA[
+          N = Ncalc;
+        ]]>
+      </sampling>
+    </group>
+    <group>
+      <sampling initial_sample="no">
+        <moments>N</moments>
+        <dimension name="y" lattice="0" />
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          N = mod2(phi);
+        ]]>
+      </sampling>
+    </group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+y phiR phiI V1R V1I 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>1024</Dim>
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+groundstate_expected_break.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/fast/groundstate_expected_mg0.dat b/testsuite/fast/groundstate_expected_mg0.dat
new file mode 100644
index 0000000..22ecae8
Binary files /dev/null and b/testsuite/fast/groundstate_expected_mg0.dat differ
diff --git a/testsuite/fast/groundstate_expected_mg1.dat b/testsuite/fast/groundstate_expected_mg1.dat
new file mode 100644
index 0000000..f143658
Binary files /dev/null and b/testsuite/fast/groundstate_expected_mg1.dat differ
diff --git a/testsuite/fast/groundstate_expected_mg2.dat b/testsuite/fast/groundstate_expected_mg2.dat
new file mode 100644
index 0000000..f143658
Binary files /dev/null and b/testsuite/fast/groundstate_expected_mg2.dat differ
diff --git a/testsuite/fast/lorenz.xmds b/testsuite/fast/lorenz.xmds
new file mode 100644
index 0000000..d6ddc34
--- /dev/null
+++ b/testsuite/fast/lorenz.xmds
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="lorenz.xsil" expected="lorenz_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+  </testing>
+  
+  <name>lorenz</name>
+  <author>Graham Dennis</author>
+  <description>
+    The Lorenz Attractor, an example of chaos.
+  </description>
+  
+  <features>
+    <benchmark />
+    <globals>
+      <![CDATA[
+      double sigma = 10.0;
+      double b = 8.0/3.0;
+      double r = 28.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <vector name="main" type="real">
+    <components>
+      x y z
+    </components>
+    <initialisation>
+      <![CDATA[
+      x = y = z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" interval="20.0" steps="25000" tolerance="1e-7">
+      <samples>500</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        dx_dt = sigma*(y-x);
+        dy_dt = r*x - y - x*z;
+        dz_dt = x*y - b*z;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="ascii" filename="lorenz.xsil">
+      <sampling_group initial_sample="yes">
+        <moments>xR yR zR</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          xR = x;
+          yR = y;
+          zR = z;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/fast/lorenz_expected.xsil b/testsuite/fast/lorenz_expected.xsil
new file mode 100644
index 0000000..8c3b33b
--- /dev/null
+++ b/testsuite/fast/lorenz_expected.xsil
@@ -0,0 +1,587 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="lorenz.xsil" expected="lorenz_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+  </testing>
+  
+  <name>lorenz</name>
+  <author>Graham Dennis</author>
+  <description>
+    The Lorenz Attractor, an example of chaos.
+  </description>
+  
+  <features>
+    <benchmark />
+    <fftw version="none" />
+    <!-- That's right, this script breaks the shackles with FFTW! -->
+    <globals>
+      <![CDATA[
+      double sigma = 10.0;
+      double b = 8.0/3.0;
+      double r = 28.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <vector name="main" type="double">
+    <components>
+      x y z
+    </components>
+    <initialisation>
+      <![CDATA[
+      x = y = z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" interval="20.0" steps="25000" tolerance="1e-7">
+      <samples>500</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        dx_dt = sigma*(y-x);
+        dy_dt = r*x - y - x*z;
+        dz_dt = x*y - b*z;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="ascii" filename="lorenz.xsil">
+      <sampling_group initial_sample="yes">
+        <moments>xR yR zR</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          xR = x;
+          yR = y;
+          zR = z;
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t xR yR zR 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>501</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+0.000000000000e+00 1.000000000000e+00 1.000000000000e+00 1.000000000000e+00
+4.000000000000e-02 1.186865463493e+00 2.088545572080e+00 9.617373650304e-01
+8.000000000000e-02 1.721145808685e+00 3.517577147510e+00 1.017186542430e+00
+1.200000000000e-01 2.663583975542e+00 5.650450265235e+00 1.291893522665e+00
+1.600000000000e-01 4.184014710226e+00 8.910162893052e+00 2.099504388160e+00
+2.000000000000e-01 6.542527555892e+00 1.373118671407e+01 4.180197411970e+00
+2.400000000000e-01 1.000065887945e+01 2.009563219437e+01 9.080554463857e+00
+2.800000000000e-01 1.444538182466e+01 2.604225107131e+01 1.905741912822e+01
+3.200000000000e-01 1.850818988024e+01 2.587701542227e+01 3.404382155578e+01
+3.600000000000e-01 1.929772909941e+01 1.510497609427e+01 4.607776658489e+01
+4.000000000000e-01 1.536620007382e+01 1.113037469028e+00 4.675784331911e+01
+4.400000000000e-01 9.095843973320e+00 -6.674058016211e+00 4.057411106344e+01
+4.800000000000e-01 3.424450814863e+00 -8.785532885692e+00 3.464452607297e+01
+5.200000000000e-01 -6.140556477804e-01 -8.714814488459e+00 3.072563865216e+01
+5.600000000000e-01 -3.207058206077e+00 -8.283165458952e+00 2.826867261658e+01
+6.000000000000e-01 -4.833214019842e+00 -8.061281107126e+00 2.667318953662e+01
+6.400000000000e-01 -5.904705574648e+00 -8.149278010219e+00 2.563385913629e+01
+6.800000000000e-01 -6.700445486594e+00 -8.500920366082e+00 2.503513624986e+01
+7.200000000000e-01 -7.382663886157e+00 -9.023080949426e+00 2.484660967768e+01
+7.600000000000e-01 -8.025097508960e+00 -9.599389384921e+00 2.506003101574e+01
+8.000000000000e-01 -8.635509302656e+00 -1.009563918797e+01 2.564672605094e+01
+8.400000000000e-01 -9.173441951150e+00 -1.037308791510e+01 2.652402978922e+01
+8.800000000000e-01 -9.569894708485e+00 -1.032171391402e+01 2.753749410692e+01
+9.200000000000e-01 -9.754318389215e+00 -9.906670009700e+00 2.847649592017e+01
+9.600000000000e-01 -9.686221242123e+00 -9.198723840818e+00 2.913064373610e+01
+1.000000000000e+00 -9.378570010917e+00 -8.357033788426e+00 2.936232533734e+01
+1.040000000000e+00 -8.899062669092e+00 -7.566338797306e+00 2.914887539895e+01
+1.080000000000e+00 -8.348188472241e+00 -6.970169531108e+00 2.856952464676e+01
+1.120000000000e+00 -7.828220333354e+00 -6.640353646620e+00 2.775699011416e+01
+1.160000000000e+00 -7.419843067113e+00 -6.586646685397e+00 2.685131727929e+01
+1.200000000000e+00 -7.173397136421e+00 -6.783423781610e+00 2.597599214852e+01
+1.240000000000e+00 -7.111363333665e+00 -7.191429275084e+00 2.523369172561e+01
+1.280000000000e+00 -7.234893345014e+00 -7.766081274513e+00 2.471047626478e+01
+1.320000000000e+00 -7.528704796577e+00 -8.453815106677e+00 2.447896752968e+01
+1.360000000000e+00 -7.961841524636e+00 -9.181956899433e+00 2.459454144027e+01
+1.400000000000e+00 -8.484793258966e+00 -9.849677041502e+00 2.508112224571e+01
+1.440000000000e+00 -9.026258734891e+00 -1.033028525824e+01 2.590725001383e+01
+1.480000000000e+00 -9.495411332985e+00 -1.049585292298e+01 2.696208850329e+01
+1.520000000000e+00 -9.795993020945e+00 -1.026597248616e+01 2.805277002421e+01
+1.560000000000e+00 -9.853309348464e+00 -9.659471881865e+00 2.894488099126e+01
+1.600000000000e+00 -9.643895089396e+00 -8.808622308405e+00 2.944101522780e+01
+1.640000000000e+00 -9.209394234009e+00 -7.912609782076e+00 2.945284924895e+01
+1.680000000000e+00 -8.643278644301e+00 -7.157860148961e+00 2.901829328039e+01
+1.720000000000e+00 -8.058203379207e+00 -6.660481101318e+00 2.826117609868e+01
+1.760000000000e+00 -7.553787395124e+00 -6.458233768135e+00 2.733340924902e+01
+1.800000000000e+00 -7.199100684215e+00 -6.536178714948e+00 2.637594710643e+01
+1.840000000000e+00 -7.030815755896e+00 -6.856496329368e+00 2.550613098641e+01
+1.880000000000e+00 -7.059756248061e+00 -7.375373680887e+00 2.482068894849e+01
+1.920000000000e+00 -7.278097744433e+00 -8.044622623654e+00 2.440198939079e+01
+1.960000000000e+00 -7.662697292080e+00 -8.802700645480e+00 2.431939477413e+01
+2.000000000000e+00 -8.173499932250e+00 -9.562023686797e+00 2.462070204971e+01
+2.040000000000e+00 -8.748967083864e+00 -1.020187291233e+01 2.531122058055e+01
+2.080000000000e+00 -9.303501456100e+00 -1.057948952989e+01 2.632436987035e+01
+2.120000000000e+00 -9.734278144254e+00 -1.056983112199e+01 2.750045036798e+01
+2.160000000000e+00 -9.943313470766e+00 -1.012683483143e+01 2.860159283066e+01
+2.200000000000e+00 -9.871103964536e+00 -9.329296396081e+00 2.937932605673e+01
+2.240000000000e+00 -9.524538111656e+00 -8.366140185268e+00 2.966769582903e+01
+2.280000000000e+00 -8.978853841046e+00 -7.458987733743e+00 2.943982797745e+01
+2.320000000000e+00 -8.350168300170e+00 -6.777022160908e+00 2.879182367515e+01
+2.360000000000e+00 -7.756501299345e+00 -6.399725494359e+00 2.788035563310e+01
+2.400000000000e+00 -7.289190878377e+00 -6.332130945525e+00 2.686518987149e+01
+2.440000000000e+00 -7.003356169544e+00 -6.540564114291e+00 2.588215798879e+01
+2.480000000000e+00 -6.922372206361e+00 -6.980222801527e+00 2.504116679710e+01
+2.520000000000e+00 -7.046875562759e+00 -7.604997355472e+00 2.443403696764e+01
+2.560000000000e+00 -7.361250895477e+00 -8.362327243736e+00 2.414073305287e+01
+2.600000000000e+00 -7.834609090741e+00 -9.179651255729e+00 2.422727736408e+01
+2.640000000000e+00 -8.416665418653e+00 -9.950569511165e+00 2.473092903480e+01
+2.680000000000e+00 -9.032037801448e+00 -1.053244136311e+01 2.563160565178e+01
+2.720000000000e+00 -9.579878903945e+00 -1.077036819397e+01 2.681857023802e+01
+2.760000000000e+00 -9.947515562330e+00 -1.055460946943e+01 2.807805064471e+01
+2.800000000000e+00 -1.004171772269e+01 -9.889761052169e+00 2.913393207045e+01
+2.840000000000e+00 -9.826784745136e+00 -8.922492060511e+00 2.974333342685e+01
+2.880000000000e+00 -9.345389282246e+00 -7.889249765486e+00 2.979227826715e+01
+2.920000000000e+00 -8.704774910159e+00 -7.014514953797e+00 2.932236890654e+01
+2.960000000000e+00 -8.036615860910e+00 -6.435189948793e+00 2.847998403432e+01
+3.000000000000e+00 -7.456658260665e+00 -6.190996127674e+00 2.744180650547e+01
+3.040000000000e+00 -7.043442036786e+00 -6.259339087708e+00 2.636650583970e+01
+3.080000000000e+00 -6.837208815856e+00 -6.594397891031e+00 2.538161234038e+01
+3.120000000000e+00 -6.849216820015e+00 -7.148548367612e+00 2.459009537574e+01
+3.160000000000e+00 -7.071499012948e+00 -7.874265757074e+00 2.408060250197e+01
+3.200000000000e+00 -7.481489642929e+00 -8.712704068468e+00 2.393192422814e+01
+3.240000000000e+00 -8.040124655806e+00 -9.576497476716e+00 2.420597873393e+01
+3.280000000000e+00 -8.685265025993e+00 -1.033652845253e+01 2.492522539484e+01
+3.320000000000e+00 -9.325777196764e+00 -1.082767419570e+01 2.603597761160e+01
+3.360000000000e+00 -9.845357540575e+00 -1.089007034601e+01 2.737437938449e+01
+3.400000000000e+00 -1.012527840450e+01 -1.044481304187e+01 2.867098498215e+01
+3.440000000000e+00 -1.008503264035e+01 -9.562309971939e+00 2.962439923208e+01
+3.480000000000e+00 -9.720886826796e+00 -8.458129226803e+00 3.002013607427e+01
+3.520000000000e+00 -9.113916219723e+00 -7.400122210927e+00 2.981248313582e+01
+3.560000000000e+00 -8.398644672374e+00 -6.595602786234e+00 2.911065968751e+01
+3.600000000000e+00 -7.714092840787e+00 -6.139364420226e+00 2.809891986640e+01
+3.640000000000e+00 -7.167195665772e+00 -6.033379970430e+00 2.696179576061e+01
+3.680000000000e+00 -6.821071688796e+00 -6.234475919821e+00 2.585074799794e+01
+3.720000000000e+00 -6.701582242968e+00 -6.690714067397e+00 2.488413032956e+01
+3.760000000000e+00 -6.809636574248e+00 -7.354431668537e+00 2.415958101042e+01
+3.800000000000e+00 -7.130196901072e+00 -8.176325176773e+00 2.376456927294e+01
+3.840000000000e+00 -7.634204253567e+00 -9.088458430249e+00 2.377766572800e+01
+3.880000000000e+00 -8.273511009343e+00 -9.984418307182e+00 2.425512506039e+01
+3.920000000000e+00 -8.972160679209e+00 -1.070887616862e+01 2.519905936436e+01
+3.960000000000e+00 -9.621530170357e+00 -1.107565937665e+01 2.651296145348e+01
+4.000000000000e+00 -1.009069843625e+01 -1.093044391380e+01 2.797212598093e+01
+4.040000000000e+00 -1.026031179094e+01 -1.024241668016e+01 2.925468220694e+01
+4.080000000000e+00 -1.007131148713e+01 -9.159140617688e+00 3.005241966841e+01
+4.120000000000e+00 -9.558477343587e+00 -7.958239105604e+00 3.020187169237e+01
+4.160000000000e+00 -8.840629318449e+00 -6.918485666519e+00 2.973489648199e+01
+4.200000000000e+00 -8.072534314515e+00 -6.213025586180e+00 2.882043418089e+01
+4.240000000000e+00 -7.392510269167e+00 -5.890772767430e+00 2.766652727026e+01
+4.280000000000e+00 -6.893927360643e+00 -5.921675430313e+00 2.645579030889e+01
+4.320000000000e+00 -6.623667292012e+00 -6.249427031467e+00 2.532925129593e+01
+4.360000000000e+00 -6.594715264817e+00 -6.820789139410e+00 2.439690284409e+01
+4.400000000000e+00 -6.799627135839e+00 -7.589510678608e+00 2.375325718522e+01
+4.440000000000e+00 -7.217605268151e+00 -8.503201266125e+00 2.348661662794e+01
+4.480000000000e+00 -7.813162658174e+00 -9.481461557814e+00 2.367594965126e+01
+4.520000000000e+00 -8.527778484362e+00 -1.039445080706e+01 2.436955037738e+01
+4.560000000000e+00 -9.269555613270e+00 -1.105790626560e+01 2.554261075982e+01
+4.600000000000e+00 -9.911042691878e+00 -1.126827401852e+01 2.704630366194e+01
+4.640000000000e+00 -1.030869948844e+01 -1.089001866031e+01 2.858974922289e+01
+4.680000000000e+00 -1.034922878245e+01 -9.957309723997e+00 2.980714665164e+01
+4.720000000000e+00 -1.000347185996e+01 -8.700267991037e+00 3.040528373674e+01
+4.760000000000e+00 -9.348723703781e+00 -7.444751123525e+00 3.029060093995e+01
+4.800000000000e+00 -8.537858329112e+00 -6.459271619530e+00 2.957383801557e+01
+4.840000000000e+00 -7.737793708370e+00 -5.871229572898e+00 2.847109199414e+01
+4.880000000000e+00 -7.079339465018e+00 -5.685298871617e+00 2.720101914154e+01
+4.920000000000e+00 -6.639567299513e+00 -5.847013938761e+00 2.593770854652e+01
+4.960000000000e+00 -6.449763965941e+00 -6.293638425796e+00 2.481092100051e+01
+5.000000000000e+00 -6.512113699446e+00 -6.974042788457e+00 2.392412957211e+01
+5.040000000000e+00 -6.812784048641e+00 -7.843792933969e+00 2.337114137283e+01
+5.080000000000e+00 -7.326254757875e+00 -8.845560116158e+00 2.324301419461e+01
+5.120000000000e+00 -8.010377969348e+00 -9.882912094583e+00 2.361948849735e+01
+5.160000000000e+00 -8.794764663715e+00 -1.079837509051e+01 2.453814605730e+01
+5.200000000000e+00 -9.569496263110e+00 -1.137698356153e+01 2.594022182673e+01
+5.240000000000e+00 -1.018748347885e+01 -1.140342727081e+01 2.761569775734e+01
+5.280000000000e+00 -1.049554172726e+01 -1.077557128009e+01 2.920536570163e+01
+5.320000000000e+00 -1.039359555964e+01 -9.606812526707e+00 3.031233557073e+01
+5.360000000000e+00 -9.889471542668e+00 -8.208515225183e+00 3.068032753820e+01
+5.400000000000e+00 -9.104061976492e+00 -6.936664883926e+00 3.029816065949e+01
+5.440000000000e+00 -8.218486064870e+00 -6.031205099177e+00 2.934974354541e+01
+5.480000000000e+00 -7.404019498699e+00 -5.568418600010e+00 2.808412157672e+01
+5.520000000000e+00 -6.779075197829e+00 -5.514132237063e+00 2.672007372238e+01
+5.560000000000e+00 -6.403559279974e+00 -5.797291033331e+00 2.541963259699e+01
+5.600000000000e+00 -6.294789644417e+00 -6.354071066579e+00 2.430209481695e+01
+5.640000000000e+00 -6.446425796116e+00 -7.137608590853e+00 2.346670041067e+01
+5.680000000000e+00 -6.840045689737e+00 -8.105089888860e+00 2.300893949968e+01
+5.720000000000e+00 -7.446235945926e+00 -9.192337298596e+00 2.302448333838e+01
+5.760000000000e+00 -8.215854119573e+00 -1.028355326371e+01 2.359426147233e+01
+5.800000000000e+00 -9.065193241067e+00 -1.118986718750e+01 2.474253671318e+01
+5.840000000000e+00 -9.864464371180e+00 -1.166462766091e+01 2.636999582838e+01
+5.880000000000e+00 -1.044659015895e+01 -1.148730736654e+01 2.819808805258e+01
+5.920000000000e+00 -1.065211132822e+01 -1.060306863364e+01 2.980016681597e+01
+5.960000000000e+00 -1.040073371068e+01 -9.214352924315e+00 3.076307400589e+01
+6.000000000000e+00 -9.742121121441e+00 -7.706838536330e+00 3.088600941582e+01
+6.040000000000e+00 -8.839256588653e+00 -6.448036952515e+00 3.024525076039e+01
+6.080000000000e+00 -7.894935001585e+00 -5.636388386713e+00 2.908767034646e+01
+6.120000000000e+00 -7.078441008582e+00 -5.297129206151e+00 2.768219142137e+01
+6.160000000000e+00 -6.493039604164e+00 -5.364367349112e+00 2.624066611491e+01
+6.200000000000e+00 -6.182064086444e+00 -5.757279696882e+00 2.491199338638e+01
+6.240000000000e+00 -6.150996333754e+00 -6.414774392591e+00 2.380667180520e+01
+6.280000000000e+00 -6.387183567026e+00 -7.295532630650e+00 2.302198123087e+01
+6.320000000000e+00 -6.869227637007e+00 -8.358104275014e+00 2.265729973964e+01
+6.360000000000e+00 -7.564619585079e+00 -9.530081299340e+00 2.281484249686e+01
+6.400000000000e+00 -8.417095159949e+00 -1.067374357643e+01 2.357771543778e+01
+6.440000000000e+00 -9.328559476823e+00 -1.156569255066e+01 2.495542300320e+01
+6.480000000000e+00 -1.014788314769e+01 -1.192669295239e+01 2.680325475292e+01
+6.520000000000e+00 -1.068775253058e+01 -1.153646653039e+01 2.876896269149e+01
+6.560000000000e+00 -1.078516256568e+01 -1.039813075052e+01 3.036097700362e+01
+6.600000000000e+00 -1.038428463050e+01 -8.807945654596e+00 3.116303163617e+01
+6.640000000000e+00 -9.578820403142e+00 -7.216323611326e+00 3.104205400865e+01
+6.680000000000e+00 -8.570739501237e+00 -5.987130523859e+00 3.016040804684e+01
+6.720000000000e+00 -7.578683696113e+00 -5.270712400917e+00 2.881649478557e+01
+6.760000000000e+00 -6.765821513627e+00 -5.045000841025e+00 2.728917003073e+01
+6.800000000000e+00 -6.219514927829e+00 -5.219387028384e+00 2.577968008565e+01
+6.840000000000e+00 -5.968065464631e+00 -5.708384997385e+00 2.442432900390e+01
+6.880000000000e+00 -6.007345695254e+00 -6.456065090178e+00 2.332666759707e+01
+6.920000000000e+00 -6.320375418661e+00 -7.427524738212e+00 2.258390620055e+01
+6.960000000000e+00 -6.884280105236e+00 -8.582971967137e+00 2.230120952053e+01
+7.000000000000e+00 -7.664493517801e+00 -9.841657392702e+00 2.258953979290e+01
+7.040000000000e+00 -8.598143365180e+00 -1.104289086361e+01 2.353652250090e+01
+7.080000000000e+00 -9.572512917241e+00 -1.192641446977e+01 2.513818483378e+01
+7.120000000000e+00 -1.041416425745e+01 -1.217827400369e+01 2.720309867125e+01
+7.160000000000e+00 -1.091472540551e+01 -1.157978463789e+01 2.930263015748e+01
+7.200000000000e+00 -1.090823451662e+01 -1.019666506692e+01 3.088158224184e+01
+7.240000000000e+00 -1.036477740818e+01 -8.419529952139e+00 3.152752111522e+01
+7.280000000000e+00 -9.421701231571e+00 -6.755646487798e+00 3.117918869629e+01
+7.320000000000e+00 -8.316700009739e+00 -5.556872637690e+00 3.007961839722e+01
+7.360000000000e+00 -7.280598714325e+00 -4.924871130122e+00 2.856929878473e+01
+7.400000000000e+00 -6.468990649982e+00 -4.795549972810e+00 2.693132293737e+01
+7.440000000000e+00 -5.954247256231e+00 -5.058993566098e+00 2.535550094271e+01
+7.480000000000e+00 -5.751628886551e+00 -5.628087293033e+00 2.396688974585e+01
+7.520000000000e+00 -5.849385819883e+00 -6.453333666442e+00 2.286356764594e+01
+7.560000000000e+00 -6.227862656843e+00 -7.507157458400e+00 2.214382707456e+01
+7.600000000000e+00 -6.864204006932e+00 -8.752918443015e+00 2.191999981261e+01
+7.640000000000e+00 -7.723404658477e+00 -1.010364067150e+01 2.231439902395e+01
+7.680000000000e+00 -8.737722451523e+00 -1.137724916857e+01 2.342381861046e+01
+7.720000000000e+00 -9.781097058376e+00 -1.227552820825e+01 2.523697734173e+01
+7.760000000000e+00 -1.065756660263e+01 -1.244467981582e+01 2.752054874714e+01
+7.800000000000e+00 -1.113542577346e+01 -1.166062252611e+01 2.976966166998e+01
+7.840000000000e+00 -1.104224167309e+01 -1.004696104021e+01 3.136157308344e+01
+7.880000000000e+00 -1.037063822238e+01 -8.086675220348e+00 3.188300200793e+01
+7.920000000000e+00 -9.298871613270e+00 -6.342875195569e+00 3.133917261041e+01
+7.960000000000e+00 -8.098544275416e+00 -5.156776559610e+00 3.004733357049e+01
+8.000000000000e+00 -7.012491593459e+00 -4.585886040723e+00 2.838545829537e+01
+8.040000000000e+00 -6.190261807141e+00 -4.528937357421e+00 2.664007079054e+01
+8.080000000000e+00 -5.691511444980e+00 -4.859403667717e+00 2.499101702569e+01
+8.120000000000e+00 -5.520490545546e+00 -5.489242509843e+00 2.355364226573e+01
+8.160000000000e+00 -5.659288788513e+00 -6.375602666397e+00 2.242119060335e+01
+8.200000000000e+00 -6.086767618577e+00 -7.499458478253e+00 2.169300764342e+01
+8.240000000000e+00 -6.781632358572e+00 -8.830589571699e+00 2.148897207063e+01
+8.280000000000e+00 -7.710958508935e+00 -1.028131117546e+01 2.194549054587e+01
+8.320000000000e+00 -8.805823890874e+00 -1.165421604965e+01 2.317620206885e+01
+8.360000000000e+00 -9.930697821314e+00 -1.261476295912e+01 2.517625916927e+01
+8.400000000000e+00 -1.086843894641e+01 -1.275991843730e+01 2.768561228732e+01
+8.440000000000e+00 -1.135964739880e+01 -1.183944822777e+01 3.012814979534e+01
+8.480000000000e+00 -1.121538229158e+01 -1.001527030151e+01 3.180033362976e+01
+8.520000000000e+00 -1.044017055517e+01 -7.858997229591e+00 3.226471515541e+01
+8.560000000000e+00 -9.247753608376e+00 -6.001101437197e+00 3.157569951491e+01
+8.600000000000e+00 -7.944718296970e+00 -4.786962791570e+00 3.011971402835e+01
+8.640000000000e+00 -6.790700984671e+00 -4.239421069119e+00 2.831517747272e+01
+8.680000000000e+00 -5.934352852797e+00 -4.222977100403e+00 2.645704004833e+01
+8.720000000000e+00 -5.426244030265e+00 -4.593419774182e+00 2.471884832539e+01
+8.760000000000e+00 -5.261432141096e+00 -5.259622069618e+00 2.320765233432e+01
+8.800000000000e+00 -5.416486679761e+00 -6.184240327311e+00 2.201129883526e+01
+8.840000000000e+00 -5.869242484279e+00 -7.358163047103e+00 2.122838677550e+01
+8.880000000000e+00 -6.601364565374e+00 -8.762821590974e+00 2.098473826639e+01
+8.920000000000e+00 -7.585513838725e+00 -1.031989346546e+01 2.143248249198e+01
+8.960000000000e+00 -8.757949104127e+00 -1.183000955337e+01 2.271224838854e+01
+9.000000000000e+00 -9.981836823868e+00 -1.293082937021e+01 2.484927804220e+01
+9.040000000000e+00 -1.102401690009e+01 -1.315827448763e+01 2.758923919832e+01
+9.080000000000e+00 -1.159182598134e+01 -1.219565210361e+01 3.030220845007e+01
+9.120000000000e+00 -1.146073538433e+01 -1.019750255795e+01 3.218033557069e+01
+9.160000000000e+00 -1.062466012052e+01 -7.813607795339e+00 3.270962325904e+01
+9.200000000000e+00 -9.321957610654e+00 -5.771489059541e+00 3.195595600233e+01
+9.240000000000e+00 -7.898791218875e+00 -4.456444504392e+00 3.037109374806e+01
+9.280000000000e+00 -6.643491384604e+00 -3.874040296129e+00 2.842782974588e+01
+9.320000000000e+00 -5.714294835898e+00 -3.855067126079e+00 2.644285101948e+01
+9.360000000000e+00 -5.158440178837e+00 -4.231373467414e+00 2.459029638573e+01
+9.400000000000e+00 -4.963462799025e+00 -4.902448646475e+00 2.297047827556e+01
+9.440000000000e+00 -5.099887705652e+00 -5.832864490307e+00 2.166393971702e+01
+9.480000000000e+00 -5.543660480734e+00 -7.023869250151e+00 2.076431807959e+01
+9.520000000000e+00 -6.279937425190e+00 -8.474834863841e+00 2.039821033037e+01
+9.560000000000e+00 -7.290811841167e+00 -1.013155676413e+01 2.073096021813e+01
+9.600000000000e+00 -8.526852510207e+00 -1.181670764586e+01 2.193879038008e+01
+9.640000000000e+00 -9.864480373752e+00 -1.316438900893e+01 2.410931136456e+01
+9.680000000000e+00 -1.106846873944e+01 -1.364651197866e+01 2.705251410557e+01
+9.720000000000e+00 -1.181162518945e+01 -1.281985926218e+01 3.013496790649e+01
+9.760000000000e+00 -1.180547883319e+01 -1.073805722251e+01 3.242390745732e+01
+9.800000000000e+00 -1.099037376653e+01 -8.088226464825e+00 3.323380666959e+01
+9.840000000000e+00 -9.603393076250e+00 -5.743419654403e+00 3.255919352978e+01
+9.880000000000e+00 -8.035668655382e+00 -4.202461324544e+00 3.090463464885e+01
+9.920000000000e+00 -6.626518998981e+00 -3.491033525892e+00 2.882681581762e+01
+9.960000000000e+00 -5.563997005081e+00 -3.406743540148e+00 2.669263766961e+01
+1.000000000000e+01 -4.902687541108e+00 -3.743872921919e+00 2.469085810255e+01
+1.004000000000e+01 -4.625094045771e+00 -4.379187547837e+00 2.291830570839e+01
+1.008000000000e+01 -4.693755507583e+00 -5.270548951358e+00 2.144546555859e+01
+1.012000000000e+01 -5.079538556296e+00 -6.426484614991e+00 2.035418168407e+01
+1.016000000000e+01 -5.769129991156e+00 -7.868484892550e+00 1.976149141054e+01
+1.020000000000e+01 -6.756047216292e+00 -9.582603572814e+00 1.983448511190e+01
+1.024000000000e+01 -8.014934986262e+00 -1.144827067250e+01 2.078185930935e+01
+1.028000000000e+01 -9.456821022471e+00 -1.314798369359e+01 2.278128578126e+01
+1.032000000000e+01 -1.087466933267e+01 -1.412598424055e+01 2.579194665363e+01
+1.036000000000e+01 -1.192565231995e+01 -1.376094352963e+01 2.929792570580e+01
+1.040000000000e+01 -1.223168606884e+01 -1.184028562405e+01 3.228207704175e+01
+1.044000000000e+01 -1.160620391843e+01 -8.945543447577e+00 3.375514484046e+01
+1.048000000000e+01 -1.021808673591e+01 -6.128308192513e+00 3.345288771705e+01
+1.052000000000e+01 -8.493211612519e+00 -4.143046801186e+00 3.186480476176e+01
+1.056000000000e+01 -6.856865571809e+00 -3.132401575513e+00 2.967622081206e+01
+1.060000000000e+01 -5.567291130520e+00 -2.876276548361e+00 2.736518557954e+01
+1.064000000000e+01 -4.710516831470e+00 -3.108377345338e+00 2.516858836611e+01
+1.068000000000e+01 -4.271367429904e+00 -3.656099195774e+00 2.319007799107e+01
+1.072000000000e+01 -4.201760340329e+00 -4.451368894934e+00 2.148866341272e+01
+1.076000000000e+01 -4.460761030322e+00 -5.498417855732e+00 2.012629487361e+01
+1.080000000000e+01 -5.029504845779e+00 -6.836537662866e+00 1.919542449464e+01
+1.084000000000e+01 -5.908611774942e+00 -8.499571493890e+00 1.884114493193e+01
+1.088000000000e+01 -7.100333515592e+00 -1.045657155503e+01 1.927532417063e+01
+1.092000000000e+01 -8.570971345544e+00 -1.251651162103e+01 2.075386003103e+01
+1.096000000000e+01 -1.018954602942e+01 -1.421525087390e+01 2.345153592075e+01
+1.100000000000e+01 -1.166342005068e+01 -1.481502708600e+01 2.717653196709e+01
+1.104000000000e+01 -1.255154169506e+01 -1.366054357673e+01 3.107375250555e+01
+1.108000000000e+01 -1.245756803414e+01 -1.085101595731e+01 3.382550452423e+01
+1.112000000000e+01 -1.132601972169e+01 -7.441172614383e+00 3.454826453511e+01
+1.116000000000e+01 -9.524713373993e+00 -4.641119934413e+00 3.341849363640e+01
+1.120000000000e+01 -7.591009679295e+00 -2.979405783404e+00 3.124497789731e+01
+1.124000000000e+01 -5.932581261312e+00 -2.323746663422e+00 2.874336677566e+01
+1.128000000000e+01 -4.729870649937e+00 -2.327224559043e+00 2.629283203187e+01
+1.132000000000e+01 -3.998037739505e+00 -2.715488322286e+00 2.404160931039e+01
+1.136000000000e+01 -3.681025371819e+00 -3.351209241996e+00 2.204468739740e+01
+1.140000000000e+01 -3.716102979413e+00 -4.204666218711e+00 2.033912954053e+01
+1.144000000000e+01 -4.063936127604e+00 -5.311245816378e+00 1.897875158092e+01
+1.148000000000e+01 -4.715957856556e+00 -6.736047741085e+00 1.805747766596e+01
+1.152000000000e+01 -5.687748027724e+00 -8.536319148354e+00 1.773440319020e+01
+1.156000000000e+01 -6.998502570032e+00 -1.069843719822e+01 1.825593179315e+01
+1.160000000000e+01 -8.627915643364e+00 -1.302294114431e+01 1.993980504744e+01
+1.164000000000e+01 -1.044075638171e+01 -1.497035438718e+01 2.303264079457e+01
+1.168000000000e+01 -1.209973780045e+01 -1.563253559069e+01 2.734322206318e+01
+1.172000000000e+01 -1.307243255731e+01 -1.418407384077e+01 3.182766283354e+01
+1.176000000000e+01 -1.288073629828e+01 -1.079106571449e+01 3.485115916330e+01
+1.180000000000e+01 -1.148863490908e+01 -6.838679816618e+00 3.541452248476e+01
+1.184000000000e+01 -9.380921393652e+00 -3.778014010896e+00 3.390123601220e+01
+1.188000000000e+01 -7.202372850005e+00 -2.098276544717e+00 3.136397948202e+01
+1.192000000000e+01 -5.393819818055e+00 -1.516132836108e+00 2.860374446987e+01
+1.196000000000e+01 -4.114429705011e+00 -1.581379758783e+00 2.597885990107e+01
+1.200000000000e+01 -3.343290842438e+00 -1.982106736570e+00 2.359618090827e+01
+1.204000000000e+01 -2.994618624176e+00 -2.577416224982e+00 2.147828432419e+01
+1.208000000000e+01 -2.986901682330e+00 -3.345011800808e+00 1.963734055645e+01
+1.212000000000e+01 -3.271344825198e+00 -4.331439533485e+00 1.810259248439e+01
+1.216000000000e+01 -3.837828394281e+00 -5.620619930370e+00 1.693848177243e+01
+1.220000000000e+01 -4.710283566569e+00 -7.309601554335e+00 1.626944398032e+01
+1.224000000000e+01 -5.933597789985e+00 -9.468383740149e+00 1.631497726780e+01
+1.228000000000e+01 -7.543634085151e+00 -1.204790304661e+01 1.741957335597e+01
+1.232000000000e+01 -9.501812588777e+00 -1.469961365303e+01 2.000952642295e+01
+1.236000000000e+01 -1.158117665500e+01 -1.656022866410e+01 2.431723232583e+01
+1.240000000000e+01 -1.326032045253e+01 -1.635935597320e+01 2.976534628142e+01
+1.244000000000e+01 -1.383111485552e+01 -1.338861066352e+01 3.456191349090e+01
+1.248000000000e+01 -1.287651666132e+01 -8.685391553064e+00 3.672807111747e+01
+1.252000000000e+01 -1.070100367136e+01 -4.375924364269e+00 3.590948523898e+01
+1.256000000000e+01 -8.099491734027e+00 -1.717261680380e+00 3.332095476613e+01
+1.260000000000e+01 -5.766180962131e+00 -6.081379878877e-01 3.023113311683e+01
+1.264000000000e+01 -4.017365895509e+00 -4.319663265095e-01 2.725863884538e+01
+1.268000000000e+01 -2.873081105803e+00 -6.871524020823e-01 2.456925540045e+01
+1.272000000000e+01 -2.224617518593e+00 -1.114173650563e+00 2.216779980472e+01
+1.276000000000e+01 -1.946626698659e+00 -1.627780849909e+00 2.003135694286e+01
+1.280000000000e+01 -1.945607215468e+00 -2.238904142096e+00 1.814560864729e+01
+1.284000000000e+01 -2.172137965588e+00 -3.008706292042e+00 1.651288542971e+01
+1.288000000000e+01 -2.619017471145e+00 -4.029642492637e+00 1.515999758911e+01
+1.292000000000e+01 -3.316524973130e+00 -5.419948020357e+00 1.415555848644e+01
+1.296000000000e+01 -4.327487596501e+00 -7.315523732162e+00 1.364340266234e+01
+1.300000000000e+01 -5.737198332386e+00 -9.832834814646e+00 1.389728339866e+01
+1.304000000000e+01 -7.622094293688e+00 -1.295089366786e+01 1.538288339100e+01
+1.308000000000e+01 -9.964398644876e+00 -1.623853687255e+01 1.873116825940e+01
+1.312000000000e+01 -1.247998462598e+01 -1.847554905591e+01 2.434283383135e+01
+1.316000000000e+01 -1.443906479198e+01 -1.778491602911e+01 3.136628910898e+01
+1.320000000000e+01 -1.484678352307e+01 -1.331575668641e+01 3.705800359260e+01
+1.324000000000e+01 -1.324492279452e+01 -7.067295135208e+00 3.880016146373e+01
+1.328000000000e+01 -1.027372404691e+01 -2.114229275535e+00 3.687008921480e+01
+1.332000000000e+01 -7.074981098976e+00 4.312252708887e-01 3.337227899675e+01
+1.336000000000e+01 -4.425424904872e+00 1.235733436475e+00 2.979983181203e+01
+1.340000000000e+01 -2.548016481910e+00 1.228649018224e+00 2.662062504536e+01
+1.344000000000e+01 -1.344269783013e+00 9.829709035498e-01 2.384691771452e+01
+1.348000000000e+01 -6.200748489069e-01 7.491917087753e-01 2.140294592776e+01
+1.352000000000e+01 -1.966937061515e-01 6.054293079091e-01 1.922754343059e+01
+1.356000000000e+01 5.727662334703e-02 5.607076930586e-01 1.728091017505e+01
+1.360000000000e+01 2.289910395287e-01 6.070216358547e-01 1.553580037401e+01
+1.364000000000e+01 3.747676308638e-01 7.414278230516e-01 1.397172248245e+01
+1.368000000000e+01 5.336319780553e-01 9.745625687009e-01 1.257288310736e+01
+1.372000000000e+01 7.382879703160e-01 1.334970564331e+00 1.132855329477e+01
+1.376000000000e+01 1.023911801560e+00 1.874007445505e+00 1.023572348417e+01
+1.380000000000e+01 1.436124547682e+00 2.673591407380e+00 9.305603351298e+00
+1.384000000000e+01 2.039509758035e+00 3.857400823828e+00 8.578114623309e+00
+1.388000000000e+01 2.927307378171e+00 5.602815135433e+00 8.153337334295e+00
+1.392000000000e+01 4.230256038529e+00 8.140006153677e+00 8.256940367214e+00
+1.396000000000e+01 6.113752704315e+00 1.169061612493e+01 9.362336822065e+00
+1.400000000000e+01 8.727233983356e+00 1.621401865767e+01 1.235298901608e+01
+1.404000000000e+01 1.201870427447e+01 2.073504795879e+01 1.846185896803e+01
+1.408000000000e+01 1.532767091203e+01 2.246947609095e+01 2.809989183133e+01
+1.412000000000e+01 1.709443694135e+01 1.805535725477e+01 3.819972730750e+01
+1.416000000000e+01 1.582444374678e+01 8.707137501487e+00 4.292147412972e+01
+1.420000000000e+01 1.192627351554e+01 4.651633388780e-01 4.091111588459e+01
+1.424000000000e+01 7.324858418448e+00 -3.598331840253e+00 3.612909828247e+01
+1.428000000000e+01 3.475440822338e+00 -4.715163949078e+00 3.162155058698e+01
+1.432000000000e+01 7.645246408759e-01 -4.700730207158e+00 2.806085098792e+01
+1.436000000000e+01 -1.006159116014e+00 -4.543078670504e+00 2.525600513259e+01
+1.440000000000e+01 -2.177644689007e+00 -4.624813222430e+00 2.298434396383e+01
+1.444000000000e+01 -3.051401525653e+00 -5.065510618950e+00 2.114199463302e+01
+1.448000000000e+01 -3.851168157373e+00 -5.900858457974e+00 1.972081307370e+01
+1.452000000000e+01 -4.734889049731e+00 -7.149379302921e+00 1.878689011758e+01
+1.456000000000e+01 -5.812423811826e+00 -8.813559535842e+00 1.848198679380e+01
+1.460000000000e+01 -7.148521940208e+00 -1.082828731498e+01 1.903002969796e+01
+1.464000000000e+01 -8.738153805363e+00 -1.295461793553e+01 2.070548183806e+01
+1.468000000000e+01 -1.044897957457e+01 -1.465206102407e+01 2.368227539043e+01
+1.472000000000e+01 -1.195883931990e+01 -1.509462685652e+01 2.770018246980e+01
+1.476000000000e+01 -1.278781768789e+01 -1.361403259340e+01 3.175215007487e+01
+1.480000000000e+01 -1.253658286825e+01 -1.045368617883e+01 3.440080053056e+01
+1.484000000000e+01 -1.120946993740e+01 -6.859383490376e+00 3.483017541436e+01
+1.488000000000e+01 -9.253544893074e+00 -4.077352973469e+00 3.340015795177e+01
+1.492000000000e+01 -7.242778678827e+00 -2.531728891413e+00 3.102541714491e+01
+1.496000000000e+01 -5.572569775137e+00 -1.990693072459e+00 2.841715016017e+01
+1.500000000000e+01 -4.393109218600e+00 -2.069127193708e+00 2.591452996878e+01
+1.504000000000e+01 -3.694474271844e+00 -2.493586155064e+00 2.363523147013e+01
+1.508000000000e+01 -3.406682304421e+00 -3.139351344685e+00 2.161774932217e+01
+1.512000000000e+01 -3.461930340616e+00 -3.989068278899e+00 1.989026354633e+01
+1.516000000000e+01 -3.821171492328e+00 -5.088439275740e+00 1.850060443372e+01
+1.520000000000e+01 -4.479394675439e+00 -6.513192577862e+00 1.753807709214e+01
+1.524000000000e+01 -5.458675913287e+00 -8.335279599937e+00 1.715998125000e+01
+1.528000000000e+01 -6.788633714710e+00 -1.056297573005e+01 1.761956560643e+01
+1.532000000000e+01 -8.464162568005e+00 -1.302286344137e+01 1.926231498403e+01
+1.536000000000e+01 -1.036663721817e+01 -1.518334107761e+01 2.239700989260e+01
+1.540000000000e+01 -1.216208305714e+01 -1.607611631845e+01 2.691228089655e+01
+1.544000000000e+01 -1.328358639604e+01 -1.472494082110e+01 3.176862187861e+01
+1.548000000000e+01 -1.318052593238e+01 -1.117945399182e+01 3.516834064912e+01
+1.552000000000e+01 -1.176437774148e+01 -6.916080352947e+00 3.591179971810e+01
+1.556000000000e+01 -9.540636855751e+00 -3.585287964174e+00 3.436658226798e+01
+1.560000000000e+01 -7.217361352261e+00 -1.762103718426e+00 3.170594613471e+01
+1.564000000000e+01 -5.282227469661e+00 -1.127619321565e+00 2.882190181194e+01
+1.568000000000e+01 -3.907752978549e+00 -1.172615992601e+00 2.609694466569e+01
+1.572000000000e+01 -3.065909191415e+00 -1.547435375910e+00 2.363107789058e+01
+1.576000000000e+01 -2.657501291423e+00 -2.093513605131e+00 2.143400537713e+01
+1.580000000000e+01 -2.588206932545e+00 -2.780923777994e+00 1.950477605497e+01
+1.584000000000e+01 -2.798927993218e+00 -3.652645391801e+00 1.785717860618e+01
+1.588000000000e+01 -3.272048423869e+00 -4.792778503656e+00 1.653374643828e+01
+1.592000000000e+01 -4.028011616178e+00 -6.308601658439e+00 1.562623439418e+01
+1.596000000000e+01 -5.116764410119e+00 -8.306876624659e+00 1.530966096788e+01
+1.600000000000e+01 -6.598734105607e+00 -1.083268229543e+01 1.588721491610e+01
+1.604000000000e+01 -8.498268024333e+00 -1.372239307453e+01 1.780936257535e+01
+1.608000000000e+01 -1.070370701776e+01 -1.634605674102e+01 2.153799025661e+01
+1.612000000000e+01 -1.281861291000e+01 -1.743189618617e+01 2.702750329331e+01
+1.616000000000e+01 -1.411110579935e+01 -1.562558036019e+01 3.293339304566e+01
+1.620000000000e+01 -1.385948501767e+01 -1.105302655310e+01 3.682076222886e+01
+1.624000000000e+01 -1.200165743091e+01 -5.856947479346e+00 3.725388161189e+01
+1.628000000000e+01 -9.267646713955e+00 -2.141526927194e+00 3.505093010952e+01
+1.632000000000e+01 -6.555949118307e+00 -3.420186582674e-01 3.184359061706e+01
+1.636000000000e+01 -4.393818214830e+00 1.621262470844e-01 2.862713877818e+01
+1.640000000000e+01 -2.901950443742e+00 4.778397271309e-02 2.571197294643e+01
+1.644000000000e+01 -1.985414103057e+00 -2.866822726136e-01 2.311992194413e+01
+1.648000000000e+01 -1.493488501030e+00 -6.779659996355e-01 2.081147050731e+01
+1.652000000000e+01 -1.296911259846e+00 -1.094322579937e+00 1.875183381391e+01
+1.656000000000e+01 -1.310846933658e+00 -1.566352371304e+00 1.691956597916e+01
+1.660000000000e+01 -1.494327259858e+00 -2.154955957930e+00 1.530585483581e+01
+1.664000000000e+01 -1.843811615354e+00 -2.942777525313e+00 1.391760015245e+01
+1.668000000000e+01 -2.388406675949e+00 -4.037544387417e+00 1.278811877977e+01
+1.672000000000e+01 -3.188496790805e+00 -5.578086399239e+00 1.200046296489e+01
+1.676000000000e+01 -4.335444459117e+00 -7.729571455081e+00 1.173244917554e+01
+1.680000000000e+01 -5.943589536681e+00 -1.063562693673e+01 1.233288199532e+01
+1.684000000000e+01 -8.111110076826e+00 -1.425182909515e+01 1.441021388747e+01
+1.688000000000e+01 -1.080089673397e+01 -1.794860557777e+01 1.878220425751e+01
+1.692000000000e+01 -1.359663774240e+01 -1.999445513143e+01 2.583676001565e+01
+1.696000000000e+01 -1.549068867444e+01 -1.800631421492e+01 3.401892706611e+01
+1.700000000000e+01 -1.529560021624e+01 -1.169972546809e+01 3.949062182972e+01
+1.704000000000e+01 -1.281139803887e+01 -4.520892300365e+00 3.982502674040e+01
+1.708000000000e+01 -9.166140652698e+00 1.787930467285e-01 3.662908578602e+01
+1.712000000000e+01 -5.684247615624e+00 2.117930931223e+00 3.256848043632e+01
+1.716000000000e+01 -3.017032550833e+00 2.513304387219e+00 2.888999810179e+01
+1.720000000000e+01 -1.212584327269e+00 2.375319260054e+00 2.577640760758e+01
+1.724000000000e+01 -6.188338335454e-02 2.209040953455e+00 2.311738143793e+01
+1.728000000000e+01 6.809010627402e-01 2.208156745698e+00 2.080681058205e+01
+1.732000000000e+01 1.217677948524e+00 2.435432467911e+00 1.878634375032e+01
+1.736000000000e+01 1.697012969202e+00 2.921373054261e+00 1.703383952573e+01
+1.740000000000e+01 2.230095943353e+00 3.709691378964e+00 1.555675033082e+01
+1.744000000000e+01 2.911152586166e+00 4.875624137961e+00 1.439988193336e+01
+1.748000000000e+01 3.834198057611e+00 6.527728296710e+00 1.366996307585e+01
+1.752000000000e+01 5.101143401404e+00 8.785583455127e+00 1.358164128705e+01
+1.756000000000e+01 6.810981742606e+00 1.169864987855e+01 1.452225465432e+01
+1.760000000000e+01 9.005437676641e+00 1.503669938146e+01 1.708286240827e+01
+1.764000000000e+01 1.153290710072e+01 1.791470682395e+01 2.185231878401e+01
+1.768000000000e+01 1.384389050410e+01 1.858771770785e+01 2.861779247124e+01
+1.772000000000e+01 1.497031021819e+01 1.548240415605e+01 3.528844283844e+01
+1.776000000000e+01 1.412139430911e+01 9.467427485192e+00 3.873662185869e+01
+1.780000000000e+01 1.152309235139e+01 3.688715989939e+00 3.799007409082e+01
+1.784000000000e+01 8.260473001845e+00 2.138215781234e-01 3.482283058333e+01
+1.788000000000e+01 5.324849443340e+00 -1.141139573772e+00 3.115624633699e+01
+1.792000000000e+01 3.136797574154e+00 -1.353569586044e+00 2.779981367654e+01
+1.796000000000e+01 1.686309638282e+00 -1.156941019185e+00 2.487351389554e+01
+1.800000000000e+01 7.935290860274e-01 -9.101051010940e-01 2.230968152275e+01
+1.804000000000e+01 2.641323013349e-01 -7.428558614374e-01 2.003670829454e+01
+1.808000000000e+01 -5.446793164488e-02 -6.836169361533e-01 1.800705033016e+01
+1.812000000000e+01 -2.671669329184e-01 -7.296195591404e-01 1.618967970133e+01
+1.816000000000e+01 -4.429398987202e-01 -8.786947701839e-01 1.456258040732e+01
+1.820000000000e+01 -6.294725788118e-01 -1.142228115206e+00 1.310972573608e+01
+1.824000000000e+01 -8.658089591559e-01 -1.551325996453e+00 1.182137943321e+01
+1.828000000000e+01 -1.192663002279e+00 -2.162512082065e+00 1.069746977340e+01
+1.832000000000e+01 -1.661590028053e+00 -3.065844025856e+00 9.755883641482e+00
+1.836000000000e+01 -2.344319040531e+00 -4.395701737677e+00 9.050711956125e+00
+1.840000000000e+01 -3.342444839330e+00 -6.339392721375e+00 8.710977619598e+00
+1.844000000000e+01 -4.793762374394e+00 -9.123236177360e+00 9.018123892910e+00
+1.848000000000e+01 -6.859426549183e+00 -1.291155089436e+01 1.053858632555e+01
+1.852000000000e+01 -9.644926221081e+00 -1.746135333918e+01 1.425078100007e+01
+1.856000000000e+01 -1.296081207455e+01 -2.135934480587e+01 2.126522448740e+01
+1.860000000000e+01 -1.590619647156e+01 -2.148915505689e+01 3.120300659060e+01
+1.864000000000e+01 -1.684324758405e+01 -1.543404491171e+01 3.994460617258e+01
+1.868000000000e+01 -1.474910716286e+01 -6.158463868475e+00 4.248174121257e+01
+1.872000000000e+01 -1.059241260690e+01 7.371966151748e-01 3.938934750783e+01
+1.876000000000e+01 -6.241621173426e+00 3.727084892643e+00 3.464414715092e+01
+1.880000000000e+01 -2.798905518998e+00 4.399861245979e+00 3.044793879431e+01
+1.884000000000e+01 -4.366178075772e-01 4.295287302241e+00 2.711547024252e+01
+1.888000000000e+01 1.097253265661e+00 4.175132775212e+00 2.443533018813e+01
+1.892000000000e+01 2.128856961780e+00 4.322816305524e+00 2.222815951572e+01
+1.896000000000e+01 2.930517000854e+00 4.827325229595e+00 2.041993902008e+01
+1.900000000000e+01 3.702226585429e+00 5.723198479350e+00 1.901716993998e+01
+1.904000000000e+01 4.588058529204e+00 7.039972834846e+00 1.809498232109e+01
+1.908000000000e+01 5.693197790448e+00 8.795972932894e+00 1.780707660640e+01
+1.912000000000e+01 7.084464713884e+00 1.094051827106e+01 1.840032667893e+01
+1.916000000000e+01 8.760857059248e+00 1.323384019313e+01 2.018932336286e+01
+1.920000000000e+01 1.058588412969e+01 1.509225871247e+01 2.339585305618e+01
+1.924000000000e+01 1.220940607166e+01 1.558501136218e+01 2.776403134458e+01
+1.928000000000e+01 1.309461020703e+01 1.393788447442e+01 3.217225265537e+01
+1.932000000000e+01 1.279131238417e+01 1.043585497746e+01 3.499035811480e+01
+1.936000000000e+01 1.131501580832e+01 6.523745284764e+00 3.533610238670e+01
+1.940000000000e+01 9.181619243466e+00 3.586656633016e+00 3.369348492277e+01
+1.944000000000e+01 7.027109570777e+00 2.023129387186e+00 3.111648744628e+01
+1.948000000000e+01 5.265757744776e+00 1.515093584299e+00 2.836298117865e+01
+1.952000000000e+01 4.035844079055e+00 1.619476851894e+00 2.576011109404e+01
+1.956000000000e+01 3.307160155715e+00 2.041266047499e+00 2.340263806620e+01
+1.960000000000e+01 2.992734859115e+00 2.652652701437e+00 2.131077690273e+01
+1.964000000000e+01 3.013618608613e+00 3.439170518255e+00 1.949784349639e+01
+1.968000000000e+01 3.324643878408e+00 4.451661404750e+00 1.799590867146e+01
+1.972000000000e+01 3.919120840188e+00 5.776040778973e+00 1.687420778551e+01
+1.976000000000e+01 4.823483126617e+00 7.508488033258e+00 1.626494015478e+01
+1.980000000000e+01 6.083043077905e+00 9.711799386341e+00 1.639883272345e+01
+1.984000000000e+01 7.729408272015e+00 1.231593687234e+01 1.763174776623e+01
+1.988000000000e+01 9.710492968917e+00 1.492939927774e+01 2.038645300061e+01
+1.992000000000e+01 1.177328872753e+01 1.663504239612e+01 2.484374638802e+01
+1.996000000000e+01 1.336836872964e+01 1.616510587519e+01 3.030873146410e+01
+2.000000000000e+01 1.379319962185e+01 1.295180397197e+01 3.490160871004e+01
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/fast/potential_expected.dat b/testsuite/fast/potential_expected.dat
new file mode 100644
index 0000000..3989af8
Binary files /dev/null and b/testsuite/fast/potential_expected.dat differ
diff --git a/testsuite/fast/potential_expected.xsil b/testsuite/fast/potential_expected.xsil
new file mode 100644
index 0000000..ade4a83
--- /dev/null
+++ b/testsuite/fast/potential_expected.xsil
@@ -0,0 +1,318 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 4 ./RbGS</command_line>
+    <xsil_file name="RbGS.xsil" expected="RbGS_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+    <xsil_file name="potential.xsil" expected="potential_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+    <xsil_file name="RbGSa.xsil" expected="RbGSa_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+  </testing>
+
+  <name>RbGS</name>
+  <author>Robin Stevenson</author>
+  <description>
+    Three dimensional harmonic trap Ground state calculation. cigar trap.
+  </description>
+  
+  <features>
+    <halt_non_finite />
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <error_check />
+    <!-- <openmp /> -->
+    <fftw plan="measure" />
+    <!-- <diagnostics /> -->
+	<globals>
+		<![CDATA[
+		/*constants*/
+			const double hbar = 1.054e-34;
+			const double massRb = 1.44316e-25;
+			const double c0OnHbar = 5.16891e-51/hbar; 		//for Rb-87
+			const double c2OnHbar = -2.38868e-53/hbar;         
+
+      const double cd = 2.1501769e-54;  // =mu0 * muB^2 *Gf^2 / 4pi --> this is for rubidium 
+      const double cdOnHbar = 2.1501769e-54/hbar;  // =mu0 * muB^2 *Gf^2 / 4pi --> this is for rubidium 
+      const double gamma1 = 4.39943e10;
+	
+			const double Sqrt2 = pow(2.0, 0.5); 			
+			const double a3dSqrt2 = 3.0/pow(2.0, 0.5); 
+			const double Pi = 3.141592654;   
+
+      /*experimental variables*/
+			const double ratio = 1.0/40.0;
+			const double omegap = 2*3.141592654*3000;
+			const double N0 = 1.0e5;                  //Note this change
+			const double B = 73.0e-7;        
+			const double gamma1B = gamma1*B;
+			const double muOnHbar = 0.0*24411.0;
+		]]>
+    </globals>  
+  </features>
+
+  <driver name="distributed-mpi" />  
+
+
+
+  <geometry>
+    <propagation_dimension>t</propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="32"  domain="(-2.2e-6, 2.2e-6)" />
+      <dimension name="y" lattice="32"  domain="(-2.2e-6, 2.2e-6)" />
+      <dimension name="z" lattice="32"  domain="(-90.0e-6, 90.0e-6)" />
+    </transverse_dimensions>
+  </geometry>
+
+  
+  <vector name="wavefunction" initial_basis="x y z" type="complex">
+    <components>
+      phi1 phi0 phim1
+    </components>
+
+    <initialisation>
+      <![CDATA[	    
+      phi1 = (x<1.0e-6 ? (y<1.0e-6 ? (z<40.0e-6 ? 1.0 : 0.0) : 0.0) : 0.0 );
+      phi0 = 0.0;
+      phim1 = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="potential" type="double">
+    <components>
+      VtrapOnHbar
+    </components>
+    <initialisation>
+      <![CDATA[
+   			//VtrapOnHbar = 0.5* massRb * omegap*omegap*(x*x + y*y + z*z*ratio*ratio);
+   			VtrapOnHbar = x*x+y*y+z*z*ratio*ratio < 2.0*2.0e-12 ? 0.5 * massRb * omegap * omegap *  (x*x+y*y+z*z*ratio*ratio)/hbar-muOnHbar : 0.5 * massRb * omegap * omegap *  2.0*2.0e-12/hbar-muOnHbar;
+      ]]>
+    </initialisation>
+  </vector>
+
+  
+  <computed_vector name="spins" type="complex">
+    <components>
+      Sz Splus Sminus S0
+    </components>
+	  <evaluation>
+	  <dependencies>
+	    wavefunction
+	  </dependencies>
+      <![CDATA[
+			S0 = mod2(phi1) + mod2(phi0) + mod2(phim1);
+			Splus = conj(phi1)*phi0 + conj(phi0)*phim1;
+			Sminus = conj(phi0)*phi1 + conj(phim1)*phi0;
+			//Sx = Sqrt2*(phi1.re * phi0.re - phi1.im * phi0.im + phi0.re * phim1.re - phi0.im * phim1.im);
+			//Sy = Sqrt2*(phim1.im * phi0.re - phim1.re * phi0.im - phi0.re * phi1.im + phi0.im * phi1.re);
+			Sz = mod2(phi1)- mod2(phim1);
+			// Splus = Sx + i*Sy;
+			// Sminus = conj(Splus);
+      ]]>		
+    </evaluation>
+  </computed_vector>  
+
+  <computed_vector type="complex" name="bilinear" dimensions="x y z">
+    <components>b11 bm1m1 b10 b01 bm10 b0m1</components>
+    <evaluation>
+      <dependencies fourier_space="x y z">wavefunction</dependencies>
+        <![CDATA[
+          b11 = mod2(phi1);
+          bm1m1 = mod2(phim1);
+          b10 = conj(phi1)*phi0;
+          b01 = conj(phi0)*phi1;
+          bm10 = conj(phim1)*phi0;
+          b0m1 = conj(phi0)*phim1;
+        ]]>
+    </evaluation>
+  </computed_vector>
+ 
+ 
+  <vector name="DipoleTerms" type="complex" initial_basis="kx ky kz">
+    <components>DA DB DC DCstar DE DEstar</components>
+    <initialisation>
+      <![CDATA[
+        double Ksqd = kx*kx + ky*ky + kz*kz;
+        DA = Ksqd<1.0      ?     0.0*i     :     -4*Pi/3 * (1 - 3 * kz*kz /Ksqd) + 0.0*i;
+        DB = Ksqd<1.0      ?     0.0*i     :     2*Pi/3 * (1 - 3 * kz*kz /Ksqd) + 0.0*i;
+        DC = Ksqd<1.0      ?     0.0*i     :    2* 2*Pi/3 * (kx - i * ky)*kz/Ksqd;
+        DCstar = Ksqd<1.0      ?     0.0*i     :  2*   2*Pi/3 * (kx + i * ky)*kz/Ksqd;
+        DE = Ksqd < 1.0      ?     0.0*i     :     -4*Pi/3 * (kx - i*ky)*(kx - i*ky) / Ksqd;
+        DEstar = Ksqd < 1.0      ?     0.0*i     :     -4*Pi/3 * (kx + i*ky)*(kx + i*ky) / Ksqd;
+      ]]>
+    </initialisation>
+  </vector>
+
+
+  <computed_vector name="dipoles" type="complex" dimensions="x y z">
+    <components>Dz Dplus Dminus</components>
+    <evaluation>
+      <dependencies fourier_space="kx ky kz">DipoleTerms bilinear</dependencies>
+      <![CDATA[
+        Dz = DA*(b11 - bm1m1) - a3dSqrt2 * DC*(b10 + b0m1) - a3dSqrt2 * DCstar*(bm10 + b01);
+        Dplus = DB*(b10 + b0m1) -1.5 * DEstar*(b01 + bm10) - a3dSqrt2 * DCstar*(b11 - bm1m1);
+        Dminus = DB*(b01 + bm10) -1.5 * DE*(b10 + b0m1) - a3dSqrt2 * DC*(b11 - bm1m1);        
+      ]]>
+    </evaluation>
+  </computed_vector>
+
+
+  
+  <computed_vector name="normalisation" dimensions="" type="double">
+    <components>
+      Ncalc
+    </components>
+    <evaluation>
+    <dependencies fourier_space="x y z">wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi1) + mod2(phi0) + mod2(phim1);
+      ]]>
+    </evaluation>
+  </computed_vector>
+ 
+  <sequence>
+    <breakpoint filename="potential.xsil">
+      <dependencies>
+        potential
+      </dependencies>
+    </breakpoint>
+    <integrate algorithm="RK4" interval="15.0e-4" steps="3">
+      <samples>1 1 1 1</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi1 *= sqrt(N0/Ncalc);
+            phi0 *= sqrt(N0/Ncalc);
+            phim1 *= sqrt(N0/Ncalc);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+			      T   = -0.5*hbar*(kx*kx+ky*ky+kz*kz)/massRb;
+          ]]>
+        </operator>
+        <dependencies>potential spins dipoles</dependencies>
+        <integration_vectors>wavefunction</integration_vectors>
+        <![CDATA[
+          dphi1_dt = T[phi1] + ((-VtrapOnHbar)*phi1 -c0OnHbar*S0*phi1 -c2OnHbar*(Sz*phi1 + Sminus*phi0) +gamma1B*phi1 -cdOnHbar*(phi1*Dz + phi0*Dminus));
+          
+          dphi0_dt = T[phi0] + ((-VtrapOnHbar)*phi0 -c0OnHbar*S0*phi0 -c2OnHbar*(Splus*phi1 + Sminus*phim1) -cdOnHbar*(phi1*Dplus + phim1*Dminus));
+          
+          dphim1_dt = T[phim1] + ((-VtrapOnHbar)*phim1 -c0OnHbar*S0*phim1 -c2OnHbar*(-Sz*phim1 + Splus*phi0) -gamma1B*phim1 -cdOnHbar*(-phim1*Dz + phi0*Dplus));
+        ]]>
+      </operators>
+    </integrate>
+    
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi1 *= sqrt(N0/Ncalc);
+            phi0 *= sqrt(N0/Ncalc);
+            phim1 *= sqrt(N0/Ncalc);
+          ]]>
+        </filter>
+
+
+    <breakpoint filename="potential.xsil">
+      <dependencies>
+        potential
+      </dependencies>
+    </breakpoint>
+    <breakpoint filename="RbGSa.xsil">
+      <dependencies>
+        wavefunction
+      </dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="no">
+        <dimension name="x" lattice="16" fourier_space="no" />
+        <dimension name="y" lattice="16" fourier_space="no" />
+        <dimension name="z" fourier_space="no" />
+        <moments>phi1re dens0 densm1 phi1im dens1</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens1 = mod2(phi1);
+          densm1 = mod2(phim1);
+          phi1re = real(phi1);
+          dens0 = mod2(phi0);
+          phi1im = imag(phi1);
+        ]]>
+      </sampling_group>
+
+
+    
+      <sampling_group initial_sample="no">
+        <dimension name="x" lattice="16" fourier_space="yes" />
+        <dimension name="y" lattice="16" fourier_space="yes" />
+        <dimension name="z" fourier_space="yes" />
+        <moments>dens1</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens1 = mod2(phi1);
+        ]]>
+      </sampling_group>
+ 
+      <sampling_group initial_sample="yes">
+        <dimension name="x" lattice="0" fourier_space="no" />
+        <dimension name="y" lattice="0" fourier_space="no" />
+        <dimension name="z" lattice="0" fourier_space="no" />
+        <moments>N1 N0 Nm1</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          N1 = mod2(phi1);
+          N0 = mod2(phi0);
+          Nm1 = mod2(phim1);
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="no">
+        <dimension name="x" lattice="0" fourier_space="no" />
+        <dimension name="y" lattice="0" fourier_space="no" />
+        <dimension name="z" lattice="0" fourier_space="no" />
+        <moments>E1OnHbarRe E1OnHbarIm</moments>
+        <operator kind="ex" constant="no">
+          <operator_names>T2</operator_names>
+          <![CDATA[
+			      T2   = -0.5*hbar*(kx*kx+ky*ky+kz*kz)/massRb;
+          ]]>
+        </operator>       
+        <dependencies>wavefunction potential spins dipoles</dependencies>
+        <![CDATA[
+          E1OnHbarRe =  real(conj(phi1)*(T2[phi1] + (-VtrapOnHbar)*phi1 -c0OnHbar*S0*phi1 -c2OnHbar*(Sz*phi1 + Sminus*phi0) +gamma1B*phi1 -cdOnHbar*(phi1*Dz + phi0*Dminus)));
+          E1OnHbarIm =  imag(conj(phi1)*(T2[phi1] + (-VtrapOnHbar)*phi1 -c0OnHbar*S0*phi1 -c2OnHbar*(Sz*phi1 + Sminus*phi0) +gamma1B*phi1 -cdOnHbar*(phi1*Dz + phi0*Dminus)));
+        ]]>
+      </sampling_group>
+  </output>
+
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x y z VtrapOnHbar 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>32</Dim>
+    <Dim>32</Dim>
+    <Dim>32</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+potential_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/fast/tla.xmds b/testsuite/fast/tla.xmds
new file mode 100644
index 0000000..1b030e0
--- /dev/null
+++ b/testsuite/fast/tla.xmds
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="tla.xsil" expected="tla_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-6" />
+  </testing>
+  <name>tla</name>
+  <author>Unknown</author>
+  <description>
+    Two level atom example simulation. Illustrates a cross-propagating field.
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw plan="patient" />
+    <globals>
+      <![CDATA[
+      const real g = 1.0;
+      const real t0 = 1.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> z </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="t" lattice="10000"  domain="(-10, 15)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="t" type="real">
+    <components>
+      E
+    </components>
+    <initialisation>
+      <![CDATA[
+        E = 2/t0/cosh(t/t0);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <vector name="cross" initial_basis="t" type="real">
+    <components>
+      P N
+    </components>
+    <initialisation>
+      <![CDATA[
+        P = 0.0;
+        N = -1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="4" steps="200">
+      <samples>100 100</samples>
+      <operators>
+        <operator kind="cross_propagation" algorithm="RK4" propagation_dimension="t">
+          <integration_vectors>cross</integration_vectors>
+          <!-- You can have a dependencies tag in here -->
+          <dependencies>main</dependencies>
+          <boundary_condition kind="left">
+            <!-- You can also have a dependencies tag in here -->
+            <!-- like the one shown below, but none are needed -->
+            <!-- in this example -->
+            <!-- <dependencies>cross</dependencies> -->
+            <![CDATA[
+              P = 0.0;
+              N = -1.0;
+            ]]>
+          </boundary_condition>
+          <![CDATA[
+            dP_dt = E*N;
+            dN_dt = -E*P;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dE_dz = g*P;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary" filename="tla.xsil">
+      <sampling_group basis="t(1000)" initial_sample="yes">
+        <moments>pow_dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          pow_dens = E*E;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="t(1000)" initial_sample="no">
+        <moments>P_out N_out</moments>
+        <dependencies>cross</dependencies>
+        <![CDATA[
+          P_out = P;
+          N_out = N;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/fast/tla_expected.xsil b/testsuite/fast/tla_expected.xsil
new file mode 100644
index 0000000..7f2c2ba
--- /dev/null
+++ b/testsuite/fast/tla_expected.xsil
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="tla.xsil" expected="tla_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-6" />
+  </testing>
+  <name>tla</name>
+  <author>Unknown</author>
+  <description>
+    Two level atom example simulation. Illustrates a cross-propagating field.
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw plan="patient" />
+    <globals>
+      <![CDATA[
+      const real g = 1.0;
+      const real t0 = 1.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> z </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="t" lattice="10000"  domain="(-10, 15)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="t" type="real">
+    <components>
+      E
+    </components>
+    <initialisation>
+      <![CDATA[
+        E = 2/t0/cosh(t/t0);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <vector name="cross" initial_basis="t" type="real">
+    <components>
+      P N
+    </components>
+    <initialisation>
+      <![CDATA[
+        P = 0.0;
+        N = -1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="4" steps="200">
+      <samples>100 100</samples>
+      <operators>
+        <operator kind="cross_propagation" algorithm="RK4" propagation_dimension="t">
+          <integration_vectors>cross</integration_vectors>
+          <!-- You can have a dependencies tag in here -->
+          <dependencies>main</dependencies>
+          <boundary_condition kind="left">
+            <!-- You can also have a dependencies tag in here -->
+            <!-- like the one shown below, but none are needed -->
+            <!-- in this example -->
+            <!-- <dependencies>cross</dependencies> -->
+            <![CDATA[
+              P = 0.0;
+              N = -1.0;
+            ]]>
+          </boundary_condition>
+          <![CDATA[
+            dP_dt = E*N;
+            dN_dt = -E*P;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dE_dz = g*P;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary" filename="tla.xsil">
+      <sampling_group basis="t(1000)" initial_sample="yes">
+        <moments>pow_dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          pow_dens = E*E;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="t(1000)" initial_sample="no">
+        <moments>P_out N_out</moments>
+        <dependencies>cross</dependencies>
+        <![CDATA[
+          P_out = P;
+          N_out = N;
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+z t pow_dens error_pow_dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>101</Dim>
+    <Dim>1000</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+tla_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>6</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+z t P_out N_out error_P_out error_N_out 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>100</Dim>
+    <Dim>1000</Dim>
+    <Dim>6</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+tla_expected_mg1.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/fast/tla_expected_mg0.dat b/testsuite/fast/tla_expected_mg0.dat
new file mode 100644
index 0000000..55e1dc3
Binary files /dev/null and b/testsuite/fast/tla_expected_mg0.dat differ
diff --git a/testsuite/fast/tla_expected_mg1.dat b/testsuite/fast/tla_expected_mg1.dat
new file mode 100644
index 0000000..d1727c9
Binary files /dev/null and b/testsuite/fast/tla_expected_mg1.dat differ
diff --git a/testsuite/fast/transverse_integration_in_vector_initialisation.xmds b/testsuite/fast/transverse_integration_in_vector_initialisation.xmds
new file mode 100644
index 0000000..758c280
--- /dev/null
+++ b/testsuite/fast/transverse_integration_in_vector_initialisation.xmds
@@ -0,0 +1,48 @@
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="transverse_integration_in_vector_initialisation.xsil" expected="transverse_integration_in_vector_initialisation_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+
+
+ <name>transverse_integration_in_vector_initialisation</name>
+ <author> Sebastian Wuester (Feb 2012)</author>
+ <description>
+   Solve Master-equation for system density matrix in super-matrix form
+</description>
+
+ <geometry>
+   <propagation_dimension> t </propagation_dimension>
+   <transverse_dimensions>
+    <dimension name="Rpos" type="integer" lattice="3" domain="(0, 2)" />        <!-- atom positions -->  
+    <dimension name="r" type="real" lattice="2" domain="(0,2)" />
+   </transverse_dimensions>
+ </geometry>
+
+ <vector name="atompositions" type="real" initial_space="r" dimensions="r"> 
+   <components> RR </components>
+   <initialisation>  
+         <![CDATA[
+RR = r*r*r*0.2;
+    ]]>
+   </initialisation>
+ </vector>
+
+  <vector name="first_positions" type="real" dimensions="">
+   <components> dummy2 </components>
+   <initialisation>  
+     <dependencies basis="r"> atompositions </dependencies>
+     <![CDATA[
+		dummy2 = RR*r;
+     ]]>
+   </initialisation>
+ </vector>
+
+ <sequence>
+   <breakpoint filename="transverse_integration_in_vector_initialisation.xsil">
+     <dependencies>first_positions</dependencies>
+   </breakpoint>
+   </sequence>
+
+ <output format="hdf5">
+ </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/fast/transverse_integration_in_vector_initialisation_expected.h5 b/testsuite/fast/transverse_integration_in_vector_initialisation_expected.h5
new file mode 100644
index 0000000..a29a344
Binary files /dev/null and b/testsuite/fast/transverse_integration_in_vector_initialisation_expected.h5 differ
diff --git a/testsuite/fast/transverse_integration_in_vector_initialisation_expected.xsil b/testsuite/fast/transverse_integration_in_vector_initialisation_expected.xsil
new file mode 100644
index 0000000..2839b30
--- /dev/null
+++ b/testsuite/fast/transverse_integration_in_vector_initialisation_expected.xsil
@@ -0,0 +1,70 @@
+<simulation xmds-version="2">
+  <testing>
+    <!-- This script has no test XSIL files because it is simply testing that this script compiles -->
+    <xsil_file name="transverse_integration_in_vector_initialisation.xsil" expected="transverse_integration_in_vector_initialisation_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+
+
+ <name>transverse_integration_in_vector_initialisation</name>
+ <author> Sebastian Wuester (Feb 2012)</author>
+ <description>
+   Solve Master-equation for system density matrix in super-matrix form
+</description>
+
+ <geometry>
+   <propagation_dimension> t </propagation_dimension>
+   <transverse_dimensions>
+    <dimension name="Rpos" type="integer" lattice="3" domain="(0, 2)" />        <!-- atom positions -->  
+    <dimension name="r" type="real" lattice="2" domain="(0,2)" />
+   </transverse_dimensions>
+ </geometry>
+
+ <vector name="atompositions" type="real" initial_space="r" dimensions="r"> 
+   <components> RR </components>
+   <initialisation>  
+         <![CDATA[
+RR = r*r*r*0.2;
+    ]]>
+   </initialisation>
+ </vector>
+
+  <vector name="first_positions" type="real" dimensions="">
+   <components> dummy2 </components>
+   <initialisation>  
+     <dependencies basis="r"> atompositions </dependencies>
+     <![CDATA[
+                dummy2 = RR*r;
+     ]]>
+   </initialisation>
+ </vector>
+
+ <sequence>
+   <breakpoint filename="transverse_integration_in_vector_initialisation.xsil">
+     <dependencies>first_positions</dependencies>
+   </breakpoint>
+   </sequence>
+
+ <output format="hdf5">
+ </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">0</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>1</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+dummy2 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>1</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+transverse_integration_in_vector_initialisation_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/fast/vibstring_circle_spectral.xmds b/testsuite/fast/vibstring_circle_spectral.xmds
new file mode 100644
index 0000000..d5f2082
--- /dev/null
+++ b/testsuite/fast/vibstring_circle_spectral.xmds
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="vibstring_circle_spectral.xsil" expected="vibstring_circle_spectral_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+  </testing>
+  <name>vibstring_circle_spectral</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string with Dirichlet boundary conditions on a circle.
+    
+    Modification of vibstring_circle to calculate temporal derivatives in fourier (spectral) space.
+    This runs faster than vibstring_circle on the same grid.
+  </description>
+  
+  <features>
+    <benchmark />
+    <!-- <error_check /> -->
+    <chunked_output size="10KB" />
+    <bing />
+    <fftw plan="patient" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      const real T_mu = T/mu;
+      
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="64"  domain="(-1, 1)" />
+      <dimension name="y" lattice="64"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="boundary" initial_basis="x y" type="real">
+    <components>
+      bc
+    </components>
+    <initialisation>
+      <![CDATA[
+        real r = sqrt(x*x + y*y);
+        real rright = _max_x-width;
+        real rdamping = r > rright ? absorb*(1-cos(M_PI*(r - rright)/width)) : 0.0;
+
+        bc = exp(-rdamping);
+        if (r > _max_x)
+          bc = 0.0;
+        if ( r > rright)
+          bc = 0.0;
+        else
+          bc = 1.0;
+          
+        
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" tolerance="1e-7" interval="4e-2" steps="1000" home_space="k">
+      <samples>5 5 100</samples>
+      <operators>
+        <operator kind="ex" constant="yes" basis="x y">
+          <operator_names>L</operator_names>
+          <![CDATA[
+          real r2 = x*x + y*y;
+          if (r2 > (_max_x - width)*(_max_x-width))
+            L = 0.0;
+          else
+            L = 1.0;
+          ]]>
+        </operator>
+        <integration_vectors basis="kx ky">main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[-T_mu*(kx*kx+ky*ky)*u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x(32) y(32)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx(32) ky(32)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(0)" initial_sample="yes">
+        <moments>energy</moments>
+        <dependencies>main</dependencies>
+        <operator kind="ex" constant="no">
+          <operator_names>Lx Ly</operator_names>
+          <![CDATA[
+            Lx = i*kx;
+            Ly = i*ky;
+          ]]>
+        </operator>
+        <![CDATA[
+          energy = mod2(uDot) + T_mu*mod2(Lx[u]) + T_mu*mod2(Ly[u]);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/fast/vibstring_circle_spectral_expected.xsil b/testsuite/fast/vibstring_circle_spectral_expected.xsil
new file mode 100644
index 0000000..435a238
--- /dev/null
+++ b/testsuite/fast/vibstring_circle_spectral_expected.xsil
@@ -0,0 +1,209 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="vibstring_circle_spectral.xsil" expected="vibstring_circle_spectral_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+  </testing>
+  <name>vibstring_circle_spectral</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string with Dirichlet boundary conditions on a circle.
+    
+    Modification of vibstring_circle to calculate temporal derivatives in fourier (spectral) space.
+    This runs faster than vibstring_circle on the same grid.
+  </description>
+  
+  <features>
+    <benchmark />
+    <!-- <error_check /> -->
+    <bing />
+    <fftw plan="patient" />
+    <openmp />
+    <globals>
+      <![CDATA[
+      const double T = 10.0;
+      const double mass = 1e-3;
+      const double length = 1.0;
+      const double mu = mass/length;
+      const double T_mu = T/mu;
+      
+      const double xmax = _xy_max_x;
+      const double width = 0.1;
+      const double absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="64"  domain="(-1, 1)" />
+      <dimension name="y" lattice="64"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="boundary" initial_basis="x y" type="double">
+    <components>
+      bc
+    </components>
+    <initialisation>
+      <![CDATA[
+        double r = sqrt(x*x + y*y);
+        double rright = xmax-width;
+        double rdamping = r > rright ? absorb*(1-cos(M_PI*(r - rright)/width)) : 0.0;
+
+        bc = exp(-rdamping);
+        if (r > xmax)
+          bc = 0.0;
+        if ( r > rright)
+          bc = 0.0;
+        else
+          bc = 1.0;
+          
+        
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" tolerance="1e-7" interval="4e-2" steps="1000" home_space="k">
+      <samples>5 5 100</samples>
+      <operators>
+        <operator kind="ex" constant="yes" fourier_space="x y">
+          <operator_names>L</operator_names>
+          <![CDATA[
+          double r2 = x*x + y*y;
+          if (r2 > (_max_x - width)*(_max_x-width))
+            L = 0.0;
+          else
+            L = 1.0;
+          ]]>
+        </operator>
+        <integration_vectors fourier_space="kx ky">main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[-T_mu*(kx*kx+ky*ky)*u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <!-- Any dimension not mentioned is assumed to be in real space and its middle element will be sampled -->
+        <!-- Note that this is different default behaviour to the filter operator. To integrate, put in a dimension -->
+        <!-- with zero lattice points. -->
+        <!-- Note that dimensions can be in any order. Not that I can think of a reason why you would want to do that -->
+        <dimension name="x" lattice="32" fourier_space="no" />
+        <dimension name="y" lattice="32" fourier_space="no" />
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u;
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes">
+        <!-- Any dimension not mentioned is assumed to be in real space and its middle element will be sampled -->
+        <!-- Note that this is different default behaviour to the filter operator. To integrate, put in a dimension -->
+        <!-- with zero lattice points. -->
+        <!-- Note that dimensions can be in any order. Not that I can think of a reason why you would want to do that -->
+        <dimension name="x" lattice="32" fourier_space="yes" />
+        <dimension name="y" lattice="32" fourier_space="yes" />
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u;
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes">
+        <!-- Any dimension not mentioned is assumed to be in real space and its middle element will be sampled -->
+        <!-- Note that this is different default behaviour to the filter operator. To integrate, put in a dimension -->
+        <!-- with zero lattice points. -->
+        <!-- Note that dimensions can be in any order. Not that I can think of a reason why you would want to do that -->
+        <dimension name="x" lattice="0" fourier_space="no" />
+        <dimension name="y" lattice="0" fourier_space="no" />
+        <moments>energy</moments>
+        <dependencies>main</dependencies>
+        <operator kind="ex" constant="no">
+          <operator_names>Lx Ly</operator_names>
+          <![CDATA[
+            Lx = i*kx;
+            Ly = i*ky;
+          ]]>
+        </operator>
+        <![CDATA[
+          energy = mod2(uDot) + T_mu*mod2(Lx[u]) + T_mu*mod2(Ly[u]);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t x y amp 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>6</Dim>
+    <Dim>32</Dim>
+    <Dim>32</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+vibstring_circle_spectral_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t kx ky amp 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>6</Dim>
+    <Dim>32</Dim>
+    <Dim>32</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+vibstring_circle_spectral_expected_mg1.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_3">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t energy 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>101</Dim>
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+vibstring_circle_spectral_expected_mg2.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/fast/vibstring_circle_spectral_expected_mg0.dat b/testsuite/fast/vibstring_circle_spectral_expected_mg0.dat
new file mode 100644
index 0000000..4a787ab
Binary files /dev/null and b/testsuite/fast/vibstring_circle_spectral_expected_mg0.dat differ
diff --git a/testsuite/fast/vibstring_circle_spectral_expected_mg1.dat b/testsuite/fast/vibstring_circle_spectral_expected_mg1.dat
new file mode 100644
index 0000000..00715a0
Binary files /dev/null and b/testsuite/fast/vibstring_circle_spectral_expected_mg1.dat differ
diff --git a/testsuite/fast/vibstring_circle_spectral_expected_mg2.dat b/testsuite/fast/vibstring_circle_spectral_expected_mg2.dat
new file mode 100644
index 0000000..cb5563a
Binary files /dev/null and b/testsuite/fast/vibstring_circle_spectral_expected_mg2.dat differ
diff --git a/testsuite/features/arguments.xmds b/testsuite/features/arguments.xmds
new file mode 100644
index 0000000..9e6191b
--- /dev/null
+++ b/testsuite/features/arguments.xmds
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <arguments>--time_factor 2.0 --size 25.0</arguments>
+    <xsil_file name="arguments.xsil" expected="arguments_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>arguments</name>
+  <author>Andy Ferris</author>
+  <description>
+    Simple one-dimensional diffusion with a pointless second dimension thrown in for fun.
+    Uses arguments and argument preprocessing. Essentially the simulation "looks" the
+    same for any given "size", as the interval/etc is scaled to fit the interesting region.
+    The user may use width_scale, time_scale and ratio to zoom out and in...
+  </description>
+  
+  <features>
+    <benchmark />
+    <fftw plan="exhaustive" />
+    <validation kind="run-time"/>
+    <globals>
+      <![CDATA[
+      real minx;
+      real maxx;
+      real miny;
+      real maxy;
+      real width;
+      real time_interval;
+      ]]>
+    </globals>
+    <arguments>
+      <argument name="size" type="real" default_value="20.0"/>
+      <argument name="ratio" type="real" default_value="0.1"/>
+      <argument name="width_factor" type="real" default_value="1.0"/>
+      <argument name="time_factor" type="real" default_value="1.0"/>
+      <![CDATA[
+      minx = -0.5*size;
+      maxx = 0.5*size;
+      miny = -0.5*size*ratio;
+      maxy = 0.5*size*ratio;
+      width = 0.5*sqrt(0.5)*size*ratio*width_factor; // half the simulation size
+      // The time intersting stuff happens scales as width^2
+      time_interval = 20.0 * width*width * time_factor;
+      ]]>
+    </arguments>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="32"  domain="(minx, maxx)" />
+      <dimension name="y" lattice="128" domain="(miny, maxy)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y/(2*width*width));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <!-- This is an interesting simulation because using IP operators means there is NO error due to the algorithm (though there may be numerical error) -->
+    <integrate algorithm="RK4" interval="time_interval" steps="24">
+      <samples>24</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="x ky">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x(0) y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/features/arguments_append_args_to_output_filename.n_1.sigma_2e-6.stringTest_mollusc_expected.h5 b/testsuite/features/arguments_append_args_to_output_filename.n_1.sigma_2e-6.stringTest_mollusc_expected.h5
new file mode 100644
index 0000000..6feb4e8
Binary files /dev/null and b/testsuite/features/arguments_append_args_to_output_filename.n_1.sigma_2e-6.stringTest_mollusc_expected.h5 differ
diff --git a/testsuite/features/arguments_append_args_to_output_filename.n_1.sigma_2e-6.stringTest_mollusc_expected.xsil b/testsuite/features/arguments_append_args_to_output_filename.n_1.sigma_2e-6.stringTest_mollusc_expected.xsil
new file mode 100644
index 0000000..d906d2e
--- /dev/null
+++ b/testsuite/features/arguments_append_args_to_output_filename.n_1.sigma_2e-6.stringTest_mollusc_expected.xsil
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+
+  <testing>
+    <arguments>--sigma 2e-6 --stringTest mollusc</arguments>
+    <xsil_file name="arguments_append_args_to_output_filename.n_1.sigma_2e-6.stringTest_mollusc.xsil" expected="arguments_append_args_to_output_filename.n_1.sigma_2e-6.stringTest_mollusc_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+
+  <name>arguments_append_args_to_output_filename</name>
+  <author>Mattias Johnsson</author>
+  <description>
+    Two level atoms, 1D, two counter propagating lasers, adiabatically
+    eliminated upper level to give one state only.
+    Implements a beam splitter using a pi/2 Bragg pulse 
+  </description>
+  
+  <features>
+    <arguments append_args_to_output_filename = "yes" >
+      <argument name="n"              type="real" default_value="1" />
+      <argument name="sigma"          type="real" default_value="1e-6" />
+      <argument name="stringTest"     type="string" default_value="strDefault" />
+    <![CDATA[
+      if (stringTest != "mollusc") exit(1);
+    ]]>
+    </arguments>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <validation kind="run-time" />
+    <fftw plan="patient" />
+    <globals>
+      <![CDATA[
+         const real hbar = 1.05457148e-34;
+         const real mass = 1.45e-25;
+         const real lambda = 780e-9;
+         const real OmegaAmplitude = 1e4;
+         const real kspread = 4e5;
+
+         const real klight = 2.0*M_PI/lambda; 
+         
+         // Note that katoms and SimTime are merely *declared* here, as the
+         // globals block can't pick up passed-in parameters yet.
+         // Their values are actually *set* in the initialization block.      
+         real katoms = 0;              
+         real SimTime = 0; 
+      ]]>
+    </globals>
+
+  </features>
+  
+<!-- To get periodic boundary conditions need grid (-L,L) where L=j*lambda -->
+<!-- This ensures both the lattice and exp(i*n*k*L) plane waves match at +/- L boundaries -->
+
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="z" lattice="256"  domain="(-3.9e-06, 3.9e-06)" />
+    </transverse_dimensions>
+  </geometry>
+
+  <vector name="potential" initial_basis="z" type="real">
+    <components>
+      V
+    </components>
+    <initialisation>
+      <![CDATA[
+        V  = cos(klight*z)*cos(klight*z);
+      ]]>
+printf("n=%e, OmegaAmplitude=%e\n",n, OmegaAmplitude);
+    </initialisation>
+  </vector>
+
+<!-- 200nK has k-sigma 5.9813e6 for k density, 1.414 this for k amplitude -->
+<!-- 6e4 is 100um BEC width --> 
+ <vector name="wavefunction" initial_basis="kz" type="complex">
+    <components> psi0 </components>
+    <initialisation>
+      <![CDATA[
+        // Set SimTime here because if I do it in the globals block, XMDS2 isn't able to pick
+        // up the passed-in value of sigma at that point
+        SimTime=10.0*sigma;
+        katoms = n*klight;
+
+        // Note +i give momentum kick in the -ve direction, -i in the +ve direction
+        // +i gives initial state with +ve momentum, -i gives initial state with -ve momentum
+        psi0 = exp(-(kz-katoms)*(kz-katoms)/(2.0*(sqrt(2)*kspread)*(sqrt(2)*kspread)));
+        
+        //printf("sigma=%e, SimTime=%e, OmegaAmplitude=%e\n", sigma, SimTime, OmegaAmplitude);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <computed_vector name="pulseshape" dimensions="" type="real">
+    <components>
+      W
+    </components>
+    <evaluation>
+      <![CDATA[
+        W = OmegaAmplitude*exp(-(t-SimTime/2.0)*(t-SimTime/2.0) /(2.0*sigma*sigma));
+      ]]>
+    </evaluation>
+  </computed_vector>
+
+  <sequence>
+    <integrate algorithm="ARK45" interval="10.0*sigma" tolerance="1e-8">
+      <samples>5</samples>
+      <operators>
+        <integration_vectors>wavefunction</integration_vectors> 
+        <dependencies>potential pulseshape</dependencies>
+
+        <operator kind="ip" constant="yes" type="imaginary">
+          <operator_names>Ltt</operator_names>
+          <![CDATA[
+            Ltt = -i*0.5*hbar*kz*kz/mass;
+          ]]>
+        </operator>
+        <![CDATA[
+
+          dpsi0_dt = Ltt[psi0] - i*2.0 * W * V * psi0;
+
+        ]]>
+      </operators>
+
+    </integrate>
+
+
+
+  </sequence>
+
+   <output format="hdf5">
+
+      <sampling_group initial_sample="yes" basis="kz">
+        <moments>densPsi0k</moments>
+        <dependencies>wavefunction</dependencies> 
+        <![CDATA[
+          densPsi0k = mod2(psi0);
+        ]]>
+      </sampling_group>
+
+  </output>
+
+
+<info>
+Script compiled with XMDS2 version 2.1 "Happy Mollusc" (r2616)
+See http://www.xmds.org for more information.
+
+Variables that can be specified on the command line:
+  Command line argument n = 1.000000e+00
+  Command line argument sigma = 2.000000e-06
+  Command line argument stringTest = mollusc
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t kz densPsi0k 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>6</Dim>
+    <Dim>256</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+arguments_append_args_to_output_filename.n_1.sigma_2e-6.stringTest_mollusc_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/features/arguments_append_args_to_output_filename.xmds b/testsuite/features/arguments_append_args_to_output_filename.xmds
new file mode 100644
index 0000000..bc6d9d1
--- /dev/null
+++ b/testsuite/features/arguments_append_args_to_output_filename.xmds
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+
+  <testing>
+    <arguments>--sigma 2e-6 --stringTest mollusc</arguments>
+    <xsil_file name="arguments_append_args_to_output_filename.n_1.sigma_2e-6.stringTest_mollusc.xsil" expected="arguments_append_args_to_output_filename.n_1.sigma_2e-6.stringTest_mollusc_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="break.n_1.sigma_2e-6.stringTest_mollusc.xsil" expected="break.n_1.sigma_2e-6.stringTest_mollusc_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+
+  <name>arguments_append_args_to_output_filename</name>
+  <author>Mattias Johnsson</author>
+  <description>
+    Two level atoms, 1D, two counter propagating lasers, adiabatically
+    eliminated upper level to give one state only.
+    Implements a beam splitter using a pi/2 Bragg pulse 
+  </description>
+  
+  <features>
+    <arguments append_args_to_output_filename = "yes" >
+      <argument name="n"              type="real" default_value="1" />
+      <argument name="sigma"          type="real" default_value="1e-6" />
+      <argument name="stringTest"     type="string" default_value="strDefault" />
+    <![CDATA[
+      if (stringTest != "mollusc") {
+        printf("arguments_append_args_to_output_filename.xmds failed.");
+        printf("Reason: Expected stringTest='mollusc', found stringTest='%s'\n", stringTest.c_str());
+        exit(1);
+      }
+    ]]>
+    </arguments>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <validation kind="run-time" />
+    <globals>
+      <![CDATA[
+         const real hbar = 1.05457148e-34;
+         const real mass = 1.45e-25;
+         const real lambda = 780e-9;
+         const real OmegaAmplitude = 1e4;
+         const real kspread = 4e5;
+
+         const real klight = 2.0*M_PI/lambda; 
+         
+         // Note that katoms and SimTime are merely *declared* here, as the
+         // globals block can't pick up passed-in parameters yet.
+         // Their values are actually *set* in the initialization block.      
+         real katoms = 0;              
+         real SimTime = 0; 
+      ]]>
+    </globals>
+
+  </features>
+  
+<!-- To get periodic boundary conditions need grid (-L,L) where L=j*lambda -->
+<!-- This ensures both the lattice and exp(i*n*k*L) plane waves match at +/- L boundaries -->
+
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="z" lattice="256"  domain="(-3.9e-06, 3.9e-06)" />
+    </transverse_dimensions>
+  </geometry>
+
+  <vector name="potential" initial_basis="z" type="real">
+    <components>
+      V
+    </components>
+    <initialisation>
+      <![CDATA[
+        V  = cos(klight*z)*cos(klight*z);
+      ]]>
+    </initialisation>
+  </vector>
+
+<!-- 200nK has k-sigma 5.9813e6 for k density, 1.414 this for k amplitude -->
+<!-- 6e4 is 100um BEC width --> 
+ <vector name="wavefunction" initial_basis="kz" type="complex">
+    <components> psi0 </components>
+    <initialisation>
+      <![CDATA[
+        // Set SimTime here because if I do it in the globals block, XMDS2 isn't able to pick
+        // up the passed-in value of sigma at that point
+        SimTime=10.0*sigma;
+        katoms = n*klight;
+
+        // Note +i give momentum kick in the -ve direction, -i in the +ve direction
+        // +i gives initial state with +ve momentum, -i gives initial state with -ve momentum
+        psi0 = exp(-(kz-katoms)*(kz-katoms)/(2.0*(sqrt(2)*kspread)*(sqrt(2)*kspread)));
+
+      ]]>
+    </initialisation>
+  </vector>
+
+  <computed_vector name="pulseshape" dimensions="" type="real">
+    <components>
+      W
+    </components>
+    <evaluation>
+      <![CDATA[
+        W = OmegaAmplitude*exp(-(t-SimTime/2.0)*(t-SimTime/2.0) /(2.0*sigma*sigma));
+      ]]>
+    </evaluation>
+  </computed_vector>
+
+  <sequence>
+    <integrate algorithm="ARK45" interval="10.0*sigma" tolerance="1e-8">
+      <samples>5</samples>
+      <operators>
+        <integration_vectors>wavefunction</integration_vectors> 
+        <dependencies>potential pulseshape</dependencies>
+
+        <operator kind="ip" constant="yes" type="imaginary">
+          <operator_names>Ltt</operator_names>
+          <![CDATA[
+            Ltt = -i*0.5*hbar*kz*kz/mass;
+          ]]>
+        </operator>
+        <![CDATA[
+
+          dpsi0_dt = Ltt[psi0] - i*2.0 * W * V * psi0;
+
+        ]]>
+      </operators>
+
+    </integrate>
+
+    <breakpoint filename="break">
+      <dependencies basis="z"> wavefunction </dependencies>
+    </breakpoint>
+
+  </sequence>
+
+   <output format="hdf5">
+
+      <sampling_group initial_sample="yes" basis="kz">
+        <moments>densPsi0k</moments>
+        <dependencies>wavefunction</dependencies> 
+        <![CDATA[
+          densPsi0k = mod2(psi0);
+        ]]>
+      </sampling_group>
+
+  </output>
+
+</simulation>
+
diff --git a/testsuite/features/arguments_expected.xsil b/testsuite/features/arguments_expected.xsil
new file mode 100644
index 0000000..0cc4647
--- /dev/null
+++ b/testsuite/features/arguments_expected.xsil
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <arguments>--time_factor 2.0 --size 25.0</arguments>
+    <xsil_file name="arguments.xsil" expected="arguments_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>arguments</name>
+  <author>Andy Ferris</author>
+  <description>
+    Simple one-dimensional diffusion with a pointless second dimension thrown in for fun.
+    Uses arguments and argument preprocessing. Essentially the simulation "looks" the
+    same for any given "size", as the interval/etc is scaled to fit the interesting region.
+    The user may use width_scale, time_scale and ratio to zoom out and in...
+  </description>
+  
+  <features>
+    <benchmark />
+    <fftw plan="exhaustive" />
+    <validation kind="run-time"/>
+    <globals>
+      <![CDATA[
+      double minx;
+      double maxx;
+      double miny;
+      double maxy;
+      double width;
+      double time_interval;
+      ]]>
+    </globals>
+    <arguments>
+      <argument name="size" type="double" default_value="20.0"/>
+      <argument name="ratio" type="double" default_value="0.1"/>
+      <argument name="width_factor" type="double" default_value="1.0"/>
+      <argument name="time_factor" type="double" default_value="1.0"/>
+      <![CDATA[
+      minx = -0.5*size;
+      maxx = 0.5*size;
+      miny = -0.5*size*ratio;
+      maxy = 0.5*size*ratio;
+      width = 0.5*sqrt(0.5)*size*ratio*width_factor; // half the simulation size
+      // The time intersting stuff happens scales as width^2
+      time_interval = 20.0 * width*width * time_factor;
+      ]]>
+    </arguments>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="32"  domain="(minx, maxx)" />
+      <dimension name="y" lattice="128" domain="(miny, maxy)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y/(2*width*width));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <!-- This is an interesting simulation because using IP operators means there is NO error due to the algorithm (though there may be numerical error) -->
+    <integrate algorithm="RK4" interval="time_interval" steps="24">
+      <samples>24</samples>
+      <operators>
+        <operator kind="ip" constant="yes" fourier_space="x ky">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <!-- Any dimension not mentioned is assumed to be in real space and its middle element will be sampled -->
+        <!-- Note that dimensions can be in any order. Not that I can think of a reason why you would want to do that -->
+        <dimension name="x" lattice="0" fourier_space="x" />
+        <dimension name="y" lattice="128" fourier_space="y" />
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+
+Variables that can be specified on the command line:
+  Command line argument size = 2.500000e+01
+  Command line argument ratio = 1.000000e-01
+  Command line argument width_factor = 1.000000e+00
+  Command line argument time_factor = 2.000000e+00
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t y dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>25</Dim>
+    <Dim>128</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+arguments_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/features/arguments_expected_mg0.dat b/testsuite/features/arguments_expected_mg0.dat
new file mode 100644
index 0000000..b31b9bd
Binary files /dev/null and b/testsuite/features/arguments_expected_mg0.dat differ
diff --git a/testsuite/features/arguments_with_similar_names.xmds b/testsuite/features/arguments_with_similar_names.xmds
new file mode 100644
index 0000000..4e45c5a
--- /dev/null
+++ b/testsuite/features/arguments_with_similar_names.xmds
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <arguments>--E1 2 --E2 2 --E1m 2 --E2p 2 --E2m 2 --E2p 2</arguments>
+    <xsil_file name="arguments_with_similar_names.xsil" expected="arguments_with_similar_names_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>arguments_with_similar_names</name>
+  <author>Eugeniy Mikhailov</author>
+  <description>
+    Simple one-dimensional completely useless simulation to check the similar arguments
+    names clashing.
+  </description>
+  
+  <features>
+    <benchmark />
+    <validation kind="run-time"/>
+    <globals>
+      <![CDATA[
+      real omega;
+      ]]>
+    </globals>
+    <arguments>
+      <argument name="E1" type="real" default_value="1.0"/>
+      <argument name="E2" type="real" default_value="2.0"/>
+      <argument name="E1m" type="real" default_value="5.0"/>
+      <argument name="E1p" type="real" default_value="3.0"/>
+      <argument name="E2m" type="real" default_value="6.0"/>
+      <argument name="E2p" type="real" default_value="4.0"/>
+      <![CDATA[
+      omega =  E1*E2*E1m*E1p*E2m*E2p;
+      ]]>
+    </arguments>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <vector name="position" type="real">
+    <components>
+      x
+    </components>
+    <initialisation>
+      <![CDATA[
+        x=1;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="1" steps="24">
+      <samples>24</samples>
+      <operators>
+        <integration_vectors>position</integration_vectors>
+        <![CDATA[
+          dx_dt = -omega*x;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group  initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>position</dependencies>
+        <![CDATA[
+          dens = x;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/features/arguments_with_similar_names_expected.xsil b/testsuite/features/arguments_with_similar_names_expected.xsil
new file mode 100644
index 0000000..44ea6be
--- /dev/null
+++ b/testsuite/features/arguments_with_similar_names_expected.xsil
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <arguments>--E1 2 --E2 2 --E1m 2 --E2p 2 --E2m 2 --E2p 2</arguments>
+    <xsil_file name="arguments_with_similar_names.xsil" expected="arguments_with_similar_names_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>arguments_with_similar_names</name>
+  <author>Eugeniy Mikhailov</author>
+  <description>
+    Simple one-dimensional completely useless simulation to check the similar arguments
+    names clashing.
+  </description>
+  
+  <features>
+    <benchmark />
+    <validation kind="run-time"/>
+    <globals>
+      <![CDATA[
+      real omega;
+      ]]>
+    </globals>
+    <arguments>
+      <argument name="E1" type="real" default_value="1.0"/>
+      <argument name="E2" type="real" default_value="2.0"/>
+      <argument name="E1m" type="real" default_value="5.0"/>
+      <argument name="E1p" type="real" default_value="3.0"/>
+      <argument name="E2m" type="real" default_value="6.0"/>
+      <argument name="E2p" type="real" default_value="4.0"/>
+      <![CDATA[
+      omega =  E1*E2*E1m*E1p*E2m*E2p;
+      ]]>
+    </arguments>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <vector name="position" type="real">
+    <components>
+      x
+    </components>
+    <initialisation>
+      <![CDATA[
+        x=1;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="1" steps="24">
+      <samples>24</samples>
+      <operators>
+        <integration_vectors>position</integration_vectors>
+        <![CDATA[
+          dx_dt = -omega*x;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group  initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>position</dependencies>
+        <![CDATA[
+          dens = x;
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+
+Variables that can be specified on the command line:
+  Command line argument E1 = 2.000000e+00
+  Command line argument E2 = 2.000000e+00
+  Command line argument E1m = 2.000000e+00
+  Command line argument E1p = 3.000000e+00
+  Command line argument E2m = 2.000000e+00
+  Command line argument E2p = 2.000000e+00
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>25</Dim>
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+arguments_with_similar_names_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/features/arguments_with_similar_names_expected_mg0.dat b/testsuite/features/arguments_with_similar_names_expected_mg0.dat
new file mode 100644
index 0000000..be590e4
Binary files /dev/null and b/testsuite/features/arguments_with_similar_names_expected_mg0.dat differ
diff --git a/testsuite/features/break.n_1.sigma_2e-6.stringTest_mollusc_expected.h5 b/testsuite/features/break.n_1.sigma_2e-6.stringTest_mollusc_expected.h5
new file mode 100644
index 0000000..a46512f
Binary files /dev/null and b/testsuite/features/break.n_1.sigma_2e-6.stringTest_mollusc_expected.h5 differ
diff --git a/testsuite/features/break.n_1.sigma_2e-6.stringTest_mollusc_expected.xsil b/testsuite/features/break.n_1.sigma_2e-6.stringTest_mollusc_expected.xsil
new file mode 100644
index 0000000..ceaf7c9
--- /dev/null
+++ b/testsuite/features/break.n_1.sigma_2e-6.stringTest_mollusc_expected.xsil
@@ -0,0 +1,173 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+
+  <testing>
+    <arguments>--sigma 2e-6 --stringTest mollusc</arguments>
+    <xsil_file name="arguments_append_args_to_output_filename.n_1.sigma_2e-6.stringTest_mollusc.xsil" expected="arguments_append_args_to_output_filename.n_1.sigma_2e-6.stringTest_mollusc_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoint.n_1.sigma_2e-6.stringTest_mollusc.xsil" expected="breakpoint.n_1.sigma_2e-6.stringTest_mollusc_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+
+  <name>arguments_append_args_to_output_filename</name>
+  <author>Mattias Johnsson</author>
+  <description>
+    Two level atoms, 1D, two counter propagating lasers, adiabatically
+    eliminated upper level to give one state only.
+    Implements a beam splitter using a pi/2 Bragg pulse 
+  </description>
+  
+  <features>
+    <arguments append_args_to_output_filename = "yes" >
+      <argument name="n"              type="real" default_value="1" />
+      <argument name="sigma"          type="real" default_value="1e-6" />
+      <argument name="stringTest"     type="string" default_value="strDefault" />
+    <![CDATA[
+      if (stringTest != "mollusc") {
+        printf("arguments_append_args_to_output_filename.xmds failed.");
+        printf("Reason: Expected stringTest='mollusc', found stringTest='%s'\n", stringTest.c_str());
+        exit(1);
+      }
+    ]]>
+    </arguments>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <validation kind="run-time" />
+    <globals>
+      <![CDATA[
+         const real hbar = 1.05457148e-34;
+         const real mass = 1.45e-25;
+         const real lambda = 780e-9;
+         const real OmegaAmplitude = 1e4;
+         const real kspread = 4e5;
+
+         const real klight = 2.0*M_PI/lambda; 
+         
+         // Note that katoms and SimTime are merely *declared* here, as the
+         // globals block can't pick up passed-in parameters yet.
+         // Their values are actually *set* in the initialization block.      
+         real katoms = 0;              
+         real SimTime = 0; 
+      ]]>
+    </globals>
+
+  </features>
+  
+<!-- To get periodic boundary conditions need grid (-L,L) where L=j*lambda -->
+<!-- This ensures both the lattice and exp(i*n*k*L) plane waves match at +/- L boundaries -->
+
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="z" lattice="256"  domain="(-3.9e-06, 3.9e-06)" />
+    </transverse_dimensions>
+  </geometry>
+
+  <vector name="potential" initial_basis="z" type="real">
+    <components>
+      V
+    </components>
+    <initialisation>
+      <![CDATA[
+        V  = cos(klight*z)*cos(klight*z);
+      ]]>
+    </initialisation>
+  </vector>
+
+<!-- 200nK has k-sigma 5.9813e6 for k density, 1.414 this for k amplitude -->
+<!-- 6e4 is 100um BEC width --> 
+ <vector name="wavefunction" initial_basis="kz" type="complex">
+    <components> psi0 </components>
+    <initialisation>
+      <![CDATA[
+        // Set SimTime here because if I do it in the globals block, XMDS2 isn't able to pick
+        // up the passed-in value of sigma at that point
+        SimTime=10.0*sigma;
+        katoms = n*klight;
+
+        // Note +i give momentum kick in the -ve direction, -i in the +ve direction
+        // +i gives initial state with +ve momentum, -i gives initial state with -ve momentum
+        psi0 = exp(-(kz-katoms)*(kz-katoms)/(2.0*(sqrt(2)*kspread)*(sqrt(2)*kspread)));
+
+      ]]>
+    </initialisation>
+  </vector>
+
+  <computed_vector name="pulseshape" dimensions="" type="real">
+    <components>
+      W
+    </components>
+    <evaluation>
+      <![CDATA[
+        W = OmegaAmplitude*exp(-(t-SimTime/2.0)*(t-SimTime/2.0) /(2.0*sigma*sigma));
+      ]]>
+    </evaluation>
+  </computed_vector>
+
+  <sequence>
+    <integrate algorithm="ARK45" interval="10.0*sigma" tolerance="1e-8">
+      <samples>5</samples>
+      <operators>
+        <integration_vectors>wavefunction</integration_vectors> 
+        <dependencies>potential pulseshape</dependencies>
+
+        <operator kind="ip" constant="yes" type="imaginary">
+          <operator_names>Ltt</operator_names>
+          <![CDATA[
+            Ltt = -i*0.5*hbar*kz*kz/mass;
+          ]]>
+        </operator>
+        <![CDATA[
+
+          dpsi0_dt = Ltt[psi0] - i*2.0 * W * V * psi0;
+
+        ]]>
+      </operators>
+
+    </integrate>
+
+    <breakpoint filename="break">
+      <dependencies basis="z"> wavefunction </dependencies>
+    </breakpoint>
+
+  </sequence>
+
+   <output format="hdf5">
+
+      <sampling_group initial_sample="yes" basis="kz">
+        <moments>densPsi0k</moments>
+        <dependencies>wavefunction</dependencies> 
+        <![CDATA[
+          densPsi0k = mod2(psi0);
+        ]]>
+      </sampling_group>
+
+  </output>
+
+
+<info>
+Script compiled with XMDS2 version 2.1 "Happy Mollusc" (r2638)
+See http://www.xmds.org for more information.
+
+Variables that can be specified on the command line:
+  Command line argument n = 1.000000e+00
+  Command line argument sigma = 2.000000e-06
+  Command line argument stringTest = mollusc
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+z psi0R psi0I 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>256</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+break.n_1.sigma_2e-6.stringTest_mollusc_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/features/error_check_multipath.xmds b/testsuite/features/error_check_multipath.xmds
new file mode 100644
index 0000000..5dd43d0
--- /dev/null
+++ b/testsuite/features/error_check_multipath.xmds
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="error_check_multipath.xsil" expected="error_check_multipath_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>error_check_multipath</name>
+  <author>Graham Dennis</author>
+  <description>
+    Check that the bug that was fixed in r2135 doesn't recur. The standard error calculation
+    was broken when error checking was turned on and the multi-path driver was used.
+  </description>
+  
+  <driver name="multi-path" paths="3" />
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <!-- This is an interesting simulation because using IP operators means there is NO error due to the algorithm (though there may be numerical error) -->
+    <integrate algorithm="ARK45" interval="10" steps="24" tolerance="1e-5">
+      <samples>6</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="ky">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/features/error_check_multipath_expected.xsil b/testsuite/features/error_check_multipath_expected.xsil
new file mode 100644
index 0000000..87442d7
--- /dev/null
+++ b/testsuite/features/error_check_multipath_expected.xsil
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="error_check_multipath.xsil" expected="error_check_multipath_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>error_check_multipath</name>
+  <author>Graham Dennis</author>
+  <description>
+    Check that the bug that was fixed in r2135 doesn't recur. The standard error calculation
+    was broken when error checking was turned on and the multi-path driver was used.
+  </description>
+  
+  <driver name="multi-path" paths="3" />
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <!-- This is an interesting simulation because using IP operators means there is NO error due to the algorithm (though there may be numerical error) -->
+    <integrate algorithm="ARK45" interval="10" steps="24" tolerance="1e-5">
+      <samples>6</samples>
+      <operators>
+        <operator kind="ip" constant="yes" fourier_space="ky">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <!-- Any dimension not mentioned is assumed to be in real space and its middle element will be sampled -->
+        <!-- Note that dimensions can be in any order. Not that I can think of a reason why you would want to do that -->
+        <dimension name="y" lattice="128" fourier_space="y" />
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t y mean_dens error_dens stderr_dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>7</Dim>
+    <Dim>128</Dim>
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+error_check_multipath_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/features/error_check_multipath_expected_mg0.dat b/testsuite/features/error_check_multipath_expected_mg0.dat
new file mode 100644
index 0000000..f91d5d2
Binary files /dev/null and b/testsuite/features/error_check_multipath_expected_mg0.dat differ
diff --git a/testsuite/features/halt_non_finite.xmds b/testsuite/features/halt_non_finite.xmds
new file mode 100644
index 0000000..47735d6
--- /dev/null
+++ b/testsuite/features/halt_non_finite.xmds
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="halt_non_finite.xsil" expected="halt_non_finite_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>halt_non_finite</name>
+  <author>Gabriel McManus</author>
+  <description>
+    An ODE with NaN derivatives.
+    Used to test the halt_non_finite feature.
+  </description>
+  
+  <features>
+    <benchmark />
+    <halt_non_finite />
+    <globals>
+      <![CDATA[
+      const real x0 = 1.0;
+      const real t0 = 1.0123456789;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <vector name="main" type="real">
+    <components> x </components>
+    <initialisation>
+      <![CDATA[
+      x = x0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="2" steps="1000">
+      <samples>200</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dx_dt = sqrt(t0 - t);
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <moments>xOut</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          xOut = x;
+        ]]>
+      </sampling_group>
+  </output>
+  
+</simulation>
diff --git a/testsuite/features/halt_non_finite_expected.xsil b/testsuite/features/halt_non_finite_expected.xsil
new file mode 100644
index 0000000..077d2a5
--- /dev/null
+++ b/testsuite/features/halt_non_finite_expected.xsil
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="halt_non_finite.xsil" expected="halt_non_finite_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>halt_non_finite</name>
+  <author>Gabriel McManus</author>
+  <description>
+    An ODE with NaN derivatives.
+    Used to test the halt_non_finite feature.
+  </description>
+  
+  <features>
+    <benchmark />
+    <halt_non_finite />
+    <globals>
+      <![CDATA[
+      const real x0 = 1.0;
+      const real t0 = 1.0123456789;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <vector name="main" type="real">
+    <components> x </components>
+    <initialisation>
+      <![CDATA[
+      x = x0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="2" steps="1000">
+      <samples>200</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dx_dt = sqrt(t0 - t);
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <moments>xOut</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          xOut = x;
+        ]]>
+      </sampling_group>
+  </output>
+  
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t xOut 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>201</Dim>
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+halt_non_finite_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/features/halt_non_finite_expected_mg0.dat b/testsuite/features/halt_non_finite_expected_mg0.dat
new file mode 100644
index 0000000..f156449
Binary files /dev/null and b/testsuite/features/halt_non_finite_expected_mg0.dat differ
diff --git a/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint1_expected.dat b/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint1_expected.dat
new file mode 100644
index 0000000..3ce7e5e
Binary files /dev/null and b/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint1_expected.dat differ
diff --git a/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint1_expected.xsil b/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint1_expected.xsil
new file mode 100644
index 0000000..748526c
--- /dev/null
+++ b/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint1_expected.xsil
@@ -0,0 +1,141 @@
+<?xml version="1.0" ?><simulation xmds-version="2">
+  <testing>
+    <xsil_file absolute_tolerance="1e-8" expected="../transforms/hermitegauss_transform_2d_expected.xsil" name="hermitegauss_transform_2d_chunked_breakpoints.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_transform_2d_chunked_breakpoint1_expected.xsil" name="hermitegauss_transform_2d_chunked_breakpoint1.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_transform_2d_chunked_breakpoint2_expected.xsil" name="hermitegauss_transform_2d_chunked_breakpoint2.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_transform_2d_chunked_breakpoint3_expected.xsil" name="hermitegauss_transform_2d_chunked_breakpoint3.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_transform_2d_chunked_breakpoint4_expected.xsil" name="hermitegauss_transform_2d_chunked_breakpoint4.xsil" relative_tolerance="1e-5"/>
+  </testing>
+
+  <name>hermitegauss_transform_2d_chunked_breakpoints</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the Schroedinger equation in 2D using the hermite-Gauss basis.
+  </description>
+  
+  <features>
+    <chunked_output size="10KB"/>
+    <validation kind="run-time"/>
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension lattice="20" length_scale="sqrt(hbar/(M*omega))" name="x" transform="hermite-gauss"/>
+      <dimension lattice="20" length_scale="sqrt(hbar/(M*omega))" name="y" transform="hermite-gauss"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector initial_basis="x y" name="main" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+        // initial state is the groundstate in the x axis, but shifted by offset
+      psi = pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.5*(M*omega/hbar)*(x - offset)*(x - offset));
+        // and an expanded gaussian in the y axis
+      psi *= pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.25*(M*omega/hbar)*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector dimensions="" name="normalisation" type="real">
+    <components>N integral_y2</components>
+    <evaluation>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        N = mod2(psi);
+        integral_y2 = mod2(psi)*y*y;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="1e-3" steps="400" tolerance="1e-6">
+      <samples>10 1 100</samples>
+      <operators>
+        <operator basis="nx ny" constant="yes" kind="ip">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*(nx + ny + 1.0)*omega;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dpsi_dt = L[psi];
+        ]]>
+      </operators>
+    </integrate>
+        <breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint1.xsil">
+                <dependencies>main</dependencies>
+        </breakpoint>
+        <breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint2.xsil">
+                <dependencies basis="nx ny">main</dependencies>
+        </breakpoint>
+        <breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint3.xsil">
+                <dependencies basis="kx ky">main</dependencies>
+        </breakpoint>
+        <breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint4.xsil">
+                <dependencies basis="x_4f y_4f">main</dependencies>
+        </breakpoint>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="nx ny" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(0)" initial_sample="yes">
+        <moments>mean_x mean_sigmay</moments>
+        <dependencies>main normalisation</dependencies>
+        <![CDATA[
+          mean_x = mod2(psi)*x/N;
+          mean_sigmay = sqrt(integral_y2/N);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x y psiR psiI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>20</Dim>
+    <Dim>20</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+hermitegauss_transform_2d_chunked_breakpoint1_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint2_expected.dat b/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint2_expected.dat
new file mode 100644
index 0000000..41bfd15
Binary files /dev/null and b/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint2_expected.dat differ
diff --git a/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint2_expected.xsil b/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint2_expected.xsil
new file mode 100644
index 0000000..f9a506f
--- /dev/null
+++ b/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint2_expected.xsil
@@ -0,0 +1,141 @@
+<?xml version="1.0" ?><simulation xmds-version="2">
+  <testing>
+    <xsil_file absolute_tolerance="1e-8" expected="../transforms/hermitegauss_transform_2d_expected.xsil" name="hermitegauss_transform_2d_chunked_breakpoints.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_transform_2d_chunked_breakpoint1_expected.xsil" name="hermitegauss_transform_2d_chunked_breakpoint1.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_transform_2d_chunked_breakpoint2_expected.xsil" name="hermitegauss_transform_2d_chunked_breakpoint2.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_transform_2d_chunked_breakpoint3_expected.xsil" name="hermitegauss_transform_2d_chunked_breakpoint3.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_transform_2d_chunked_breakpoint4_expected.xsil" name="hermitegauss_transform_2d_chunked_breakpoint4.xsil" relative_tolerance="1e-5"/>
+  </testing>
+
+  <name>hermitegauss_transform_2d_chunked_breakpoints</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the Schroedinger equation in 2D using the hermite-Gauss basis.
+  </description>
+  
+  <features>
+    <chunked_output size="10KB"/>
+    <validation kind="run-time"/>
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension lattice="20" length_scale="sqrt(hbar/(M*omega))" name="x" transform="hermite-gauss"/>
+      <dimension lattice="20" length_scale="sqrt(hbar/(M*omega))" name="y" transform="hermite-gauss"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector initial_basis="x y" name="main" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+        // initial state is the groundstate in the x axis, but shifted by offset
+      psi = pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.5*(M*omega/hbar)*(x - offset)*(x - offset));
+        // and an expanded gaussian in the y axis
+      psi *= pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.25*(M*omega/hbar)*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector dimensions="" name="normalisation" type="real">
+    <components>N integral_y2</components>
+    <evaluation>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        N = mod2(psi);
+        integral_y2 = mod2(psi)*y*y;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="1e-3" steps="400" tolerance="1e-6">
+      <samples>10 1 100</samples>
+      <operators>
+        <operator basis="nx ny" constant="yes" kind="ip">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*(nx + ny + 1.0)*omega;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dpsi_dt = L[psi];
+        ]]>
+      </operators>
+    </integrate>
+        <breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint1.xsil">
+                <dependencies>main</dependencies>
+        </breakpoint>
+        <breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint2.xsil">
+                <dependencies basis="nx ny">main</dependencies>
+        </breakpoint>
+        <breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint3.xsil">
+                <dependencies basis="kx ky">main</dependencies>
+        </breakpoint>
+        <breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint4.xsil">
+                <dependencies basis="x_4f y_4f">main</dependencies>
+        </breakpoint>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="nx ny" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(0)" initial_sample="yes">
+        <moments>mean_x mean_sigmay</moments>
+        <dependencies>main normalisation</dependencies>
+        <![CDATA[
+          mean_x = mod2(psi)*x/N;
+          mean_sigmay = sqrt(integral_y2/N);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+nx ny psiR psiI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>20</Dim>
+    <Dim>20</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+hermitegauss_transform_2d_chunked_breakpoint2_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint3_expected.dat b/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint3_expected.dat
new file mode 100644
index 0000000..d02d29f
Binary files /dev/null and b/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint3_expected.dat differ
diff --git a/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint3_expected.xsil b/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint3_expected.xsil
new file mode 100644
index 0000000..281d839
--- /dev/null
+++ b/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint3_expected.xsil
@@ -0,0 +1,141 @@
+<?xml version="1.0" ?><simulation xmds-version="2">
+  <testing>
+    <xsil_file absolute_tolerance="1e-8" expected="../transforms/hermitegauss_transform_2d_expected.xsil" name="hermitegauss_transform_2d_chunked_breakpoints.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_transform_2d_chunked_breakpoint1_expected.xsil" name="hermitegauss_transform_2d_chunked_breakpoint1.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_transform_2d_chunked_breakpoint2_expected.xsil" name="hermitegauss_transform_2d_chunked_breakpoint2.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_transform_2d_chunked_breakpoint3_expected.xsil" name="hermitegauss_transform_2d_chunked_breakpoint3.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_transform_2d_chunked_breakpoint4_expected.xsil" name="hermitegauss_transform_2d_chunked_breakpoint4.xsil" relative_tolerance="1e-5"/>
+  </testing>
+
+  <name>hermitegauss_transform_2d_chunked_breakpoints</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the Schroedinger equation in 2D using the hermite-Gauss basis.
+  </description>
+  
+  <features>
+    <chunked_output size="10KB"/>
+    <validation kind="run-time"/>
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension lattice="20" length_scale="sqrt(hbar/(M*omega))" name="x" transform="hermite-gauss"/>
+      <dimension lattice="20" length_scale="sqrt(hbar/(M*omega))" name="y" transform="hermite-gauss"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector initial_basis="x y" name="main" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+        // initial state is the groundstate in the x axis, but shifted by offset
+      psi = pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.5*(M*omega/hbar)*(x - offset)*(x - offset));
+        // and an expanded gaussian in the y axis
+      psi *= pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.25*(M*omega/hbar)*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector dimensions="" name="normalisation" type="real">
+    <components>N integral_y2</components>
+    <evaluation>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        N = mod2(psi);
+        integral_y2 = mod2(psi)*y*y;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="1e-3" steps="400" tolerance="1e-6">
+      <samples>10 1 100</samples>
+      <operators>
+        <operator basis="nx ny" constant="yes" kind="ip">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*(nx + ny + 1.0)*omega;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dpsi_dt = L[psi];
+        ]]>
+      </operators>
+    </integrate>
+        <breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint1.xsil">
+                <dependencies>main</dependencies>
+        </breakpoint>
+        <breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint2.xsil">
+                <dependencies basis="nx ny">main</dependencies>
+        </breakpoint>
+        <breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint3.xsil">
+                <dependencies basis="kx ky">main</dependencies>
+        </breakpoint>
+        <breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint4.xsil">
+                <dependencies basis="x_4f y_4f">main</dependencies>
+        </breakpoint>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="nx ny" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(0)" initial_sample="yes">
+        <moments>mean_x mean_sigmay</moments>
+        <dependencies>main normalisation</dependencies>
+        <![CDATA[
+          mean_x = mod2(psi)*x/N;
+          mean_sigmay = sqrt(integral_y2/N);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+kx ky psiR psiI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>20</Dim>
+    <Dim>20</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+hermitegauss_transform_2d_chunked_breakpoint3_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint4_expected.dat b/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint4_expected.dat
new file mode 100644
index 0000000..9853b54
Binary files /dev/null and b/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint4_expected.dat differ
diff --git a/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint4_expected.xsil b/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint4_expected.xsil
new file mode 100644
index 0000000..e8c5dde
--- /dev/null
+++ b/testsuite/features/hermitegauss_transform_2d_chunked_breakpoint4_expected.xsil
@@ -0,0 +1,141 @@
+<?xml version="1.0" ?><simulation xmds-version="2">
+  <testing>
+    <xsil_file absolute_tolerance="1e-8" expected="../transforms/hermitegauss_transform_2d_expected.xsil" name="hermitegauss_transform_2d_chunked_breakpoints.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_transform_2d_chunked_breakpoint1_expected.xsil" name="hermitegauss_transform_2d_chunked_breakpoint1.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_transform_2d_chunked_breakpoint2_expected.xsil" name="hermitegauss_transform_2d_chunked_breakpoint2.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_transform_2d_chunked_breakpoint3_expected.xsil" name="hermitegauss_transform_2d_chunked_breakpoint3.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_transform_2d_chunked_breakpoint4_expected.xsil" name="hermitegauss_transform_2d_chunked_breakpoint4.xsil" relative_tolerance="1e-5"/>
+  </testing>
+
+  <name>hermitegauss_transform_2d_chunked_breakpoints</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the Schroedinger equation in 2D using the hermite-Gauss basis.
+  </description>
+  
+  <features>
+    <chunked_output size="10KB"/>
+    <validation kind="run-time"/>
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension lattice="20" length_scale="sqrt(hbar/(M*omega))" name="x" transform="hermite-gauss"/>
+      <dimension lattice="20" length_scale="sqrt(hbar/(M*omega))" name="y" transform="hermite-gauss"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector initial_basis="x y" name="main" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+        // initial state is the groundstate in the x axis, but shifted by offset
+      psi = pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.5*(M*omega/hbar)*(x - offset)*(x - offset));
+        // and an expanded gaussian in the y axis
+      psi *= pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.25*(M*omega/hbar)*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector dimensions="" name="normalisation" type="real">
+    <components>N integral_y2</components>
+    <evaluation>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        N = mod2(psi);
+        integral_y2 = mod2(psi)*y*y;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="1e-3" steps="400" tolerance="1e-6">
+      <samples>10 1 100</samples>
+      <operators>
+        <operator basis="nx ny" constant="yes" kind="ip">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*(nx + ny + 1.0)*omega;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dpsi_dt = L[psi];
+        ]]>
+      </operators>
+    </integrate>
+        <breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint1.xsil">
+                <dependencies>main</dependencies>
+        </breakpoint>
+        <breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint2.xsil">
+                <dependencies basis="nx ny">main</dependencies>
+        </breakpoint>
+        <breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint3.xsil">
+                <dependencies basis="kx ky">main</dependencies>
+        </breakpoint>
+        <breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint4.xsil">
+                <dependencies basis="x_4f y_4f">main</dependencies>
+        </breakpoint>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="nx ny" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(0)" initial_sample="yes">
+        <moments>mean_x mean_sigmay</moments>
+        <dependencies>main normalisation</dependencies>
+        <![CDATA[
+          mean_x = mod2(psi)*x/N;
+          mean_sigmay = sqrt(integral_y2/N);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x_4f y_4f psiR psiI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>20</Dim>
+    <Dim>20</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+hermitegauss_transform_2d_chunked_breakpoint4_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/features/hermitegauss_transform_2d_chunked_breakpoints.xmds b/testsuite/features/hermitegauss_transform_2d_chunked_breakpoints.xmds
new file mode 100644
index 0000000..01346e5
--- /dev/null
+++ b/testsuite/features/hermitegauss_transform_2d_chunked_breakpoints.xmds
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="hermitegauss_transform_2d_chunked_breakpoints.xsil" expected="../transforms/hermitegauss_transform_2d_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+    <xsil_file name="hermitegauss_transform_2d_chunked_breakpoint1.xsil" expected="hermitegauss_transform_2d_chunked_breakpoint1_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+    <xsil_file name="hermitegauss_transform_2d_chunked_breakpoint2.xsil" expected="hermitegauss_transform_2d_chunked_breakpoint2_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+    <xsil_file name="hermitegauss_transform_2d_chunked_breakpoint3.xsil" expected="hermitegauss_transform_2d_chunked_breakpoint3_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+    <xsil_file name="hermitegauss_transform_2d_chunked_breakpoint4.xsil" expected="hermitegauss_transform_2d_chunked_breakpoint4_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+  </testing>
+
+  <name>hermitegauss_transform_2d_chunked_breakpoints</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the Schroedinger equation in 2D using the hermite-Gauss basis.
+  </description>
+  
+  <features>
+    <chunked_output size="10KB" />
+    <validation kind="run-time" />
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="20" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+      <dimension name="y" lattice="20" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+        // initial state is the groundstate in the x axis, but shifted by offset
+      psi = pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.5*(M*omega/hbar)*(x - offset)*(x - offset));
+        // and an expanded gaussian in the y axis
+      psi *= pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.25*(M*omega/hbar)*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>N integral_y2</components>
+    <evaluation>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        N = mod2(psi);
+        integral_y2 = mod2(psi)*y*y;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-6" interval="1e-3" steps="400">
+      <samples>10 1 100</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="nx ny">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*(nx + ny + 1.0)*omega;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dpsi_dt = L[psi];
+        ]]>
+      </operators>
+    </integrate>
+	<breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint1.xsil">
+		<dependencies>main</dependencies>
+	</breakpoint>
+	<breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint2.xsil">
+		<dependencies basis="nx ny">main</dependencies>
+	</breakpoint>
+	<breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint3.xsil">
+		<dependencies basis="kx ky">main</dependencies>
+	</breakpoint>
+	<breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint4.xsil">
+		<dependencies basis="x_4f y_4f">main</dependencies>
+	</breakpoint>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="nx ny" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(0)" initial_sample="yes">
+        <moments>mean_x mean_sigmay</moments>
+        <dependencies>main normalisation</dependencies>
+        <![CDATA[
+          mean_x = mod2(psi)*x/N;
+          mean_sigmay = sqrt(integral_y2/N);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/features/hermitegauss_transform_2d_chunked_breakpoints_hdf5.xmds b/testsuite/features/hermitegauss_transform_2d_chunked_breakpoints_hdf5.xmds
new file mode 100644
index 0000000..947117b
--- /dev/null
+++ b/testsuite/features/hermitegauss_transform_2d_chunked_breakpoints_hdf5.xmds
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="hermitegauss_transform_2d_chunked_breakpoints_hdf5.xsil" expected="../transforms/hermitegauss_transform_2d_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+    <xsil_file name="hermitegauss_transform_2d_chunked_breakpoint1_hdf5.xsil" expected="hermitegauss_transform_2d_chunked_breakpoint1_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+    <xsil_file name="hermitegauss_transform_2d_chunked_breakpoint2_hdf5.xsil" expected="hermitegauss_transform_2d_chunked_breakpoint2_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+    <xsil_file name="hermitegauss_transform_2d_chunked_breakpoint3_hdf5.xsil" expected="hermitegauss_transform_2d_chunked_breakpoint3_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+    <xsil_file name="hermitegauss_transform_2d_chunked_breakpoint4_hdf5.xsil" expected="hermitegauss_transform_2d_chunked_breakpoint4_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+  </testing>
+
+  <name>hermitegauss_transform_2d_chunked_breakpoints_hdf5</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the Schroedinger equation in 2D using the hermite-Gauss basis.
+  </description>
+  
+  <features>
+    <chunked_output size="10KB" />
+    <validation kind="run-time" />
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="20" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+      <dimension name="y" lattice="20" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+        // initial state is the groundstate in the x axis, but shifted by offset
+      psi = pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.5*(M*omega/hbar)*(x - offset)*(x - offset));
+        // and an expanded gaussian in the y axis
+      psi *= pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.25*(M*omega/hbar)*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>N integral_y2</components>
+    <evaluation>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        N = mod2(psi);
+        integral_y2 = mod2(psi)*y*y;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-6" interval="1e-3" steps="400">
+      <samples>10 1 100</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="nx ny">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*(nx + ny + 1.0)*omega;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dpsi_dt = L[psi];
+        ]]>
+      </operators>
+    </integrate>
+	<breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint1_hdf5.xsil">
+		<dependencies>main</dependencies>
+	</breakpoint>
+	<breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint2_hdf5.xsil">
+		<dependencies basis="nx ny">main</dependencies>
+	</breakpoint>
+	<breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint3_hdf5.xsil">
+		<dependencies basis="kx ky">main</dependencies>
+	</breakpoint>
+	<breakpoint filename="hermitegauss_transform_2d_chunked_breakpoint4_hdf5.xsil">
+		<dependencies basis="x_4f y_4f">main</dependencies>
+	</breakpoint>
+  </sequence>
+  <output format="hdf5">
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="nx ny" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(0)" initial_sample="yes">
+        <moments>mean_x mean_sigmay</moments>
+        <dependencies>main normalisation</dependencies>
+        <![CDATA[
+          mean_x = mod2(psi)*x/N;
+          mean_sigmay = sqrt(integral_y2/N);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/features/realistic_Rb_and_fields.xmds b/testsuite/features/realistic_Rb_and_fields.xmds
new file mode 100644
index 0000000..a81da3d
--- /dev/null
+++ b/testsuite/features/realistic_Rb_and_fields.xmds
@@ -0,0 +1,641 @@
+<?xml version="1.0"?>
+<simulation xmds-version="2">
+	<testing>
+		<arguments> --Lcell=5e-4</arguments>
+		<xsil_file name="realistic_Rb_and_fields.xsil" expected="realistic_Rb_and_fields_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5">
+			<moment_group number="0" absolute_tolerance="1e-7" relative_tolerance="1e-6" />
+		</xsil_file>
+	</testing>
+
+	<name>realistic_Rb_and_fields</name>
+
+	<author>Eugeniy Mikhailov</author>
+	<description>
+		License GPL.
+
+		Solving simplified Rb atom model
+		with fields propagation along spatial axis Z
+		with Doppler broadening.
+
+
+		We assume four-wave mixing condition when w3-w4=w2-w1 i.e. fields E3 and E4 drive the same
+		resonance as fields E2 and E1.
+
+
+		*              --------------- | F=1, 2P_3/2 >
+		*                \        \    
+		*                 \ E3_r   \    -------- | F=2, 2P_+1/2 >
+		*                  \   E4_r \   /    \
+		*                   \        \ / E2_l \ 
+		*                    \        /        \ E1_l
+		*   | F=2, 2S_1/2 > --------------      \
+		*                               \        \
+		*                                \        \
+		*                               ------------- | F=1, 2S_1/2 >
+		*            
+
+
+		We are solving 
+			dE/dz+(1/c)*dE/dt=i*eta*rho_ij,  where j level is higher than i.
+			Note that E is actually a Rabi frequency of electromagnetic field not the EM field
+		in xmds terms it looks like
+			dE_dz = i*eta*rhoij - 1/c*L[E], here we moved t dependence to Fourier space
+
+		VERY IMPORTANT: all Rabi frequency should be given in [1/s], if you want to
+		normalize it to something else look drho/dt equation.
+		No need to renormalizes eta as long as its express through
+		the upper level decay rate in the same units as Rabi frequency.
+	</description>
+
+	<features>
+		<globals>
+			<![CDATA[
+				// Some numerical constants
+				const double pi = M_PI; 
+
+				// atom related constants
+				//read from Mathematica generated Constants.txt
+//---------------- Constants.txt starts ------------------
+const double ha0 = 2.1471788680034824e10;
+const double ha1 = 2.558764384495815e9;
+const double g1 = 3.612847284945266e7;
+const double ha2 = 5.323020344462938e8;
+const double hb2 = 7.85178251911697e7;
+const double g2 = 3.8117309832741246e7;
+const double lambda1 = 7.949788511562656e-7;
+const double lambda2 = 7.802412096860509e-7;
+const double eta1 = 5.450949336831401e-6;
+const double eta2 = 5.5397657647874e-6;
+const double rt6 = 2.449489742783178;
+const double rt3 = 1.7320508075688772;
+const double rt2 = 1.4142135623730951;
+//---------------- Constants.txt ends   ------------------
+
+				const double c=3.e8;
+				const double k_boltzmann= 1.3806505e-23; // Boltzmann knostant in [J/K]
+				const double lambda=794.7e-9; //wavelength in m
+				// Fields k-vector
+				const double Kvec = 2*M_PI/lambda;  
+				// Simplified k-vectors
+				const double Kvec1 = Kvec, Kvec2=Kvec, Kvec3=Kvec;
+
+				//  ---------  Atom and cell properties -------------------------
+				// range of Maxwell distribution atomic velocities
+				const double mass = (86.909180527 * 1.660538921e-27); // atom mass in [kg] 
+				// above mass expression is written as (expression is isotopic_mass * atomic_mass_unit)
+
+				// Average sqrt(v^2) in Maxwell distribution for one dimension
+				// Maxwell related parameters will be calculated in <arguments> section
+				double v_thermal_averaged=0;
+				// Maxwell distribution velocities range to take in account in [m/s]
+				double V_maxwell_min = 0, V_maxwell_max = 0;
+
+				// repopulation rate (atoms flying in/out the laser beam)  in [1/s]
+				const double gt=0.01 *(2*M_PI*1e6);
+
+				// inner use variables 
+				double probability_v; // will be used as p(v) in Maxwell distribution
+
+			]]>
+		</globals>
+		<validation kind="run-time"/> <!--allows to put ranges as variables-->
+		<benchmark />
+    <arguments>
+			<!-- Rabi frequency divided by 2 in [1/s] -->
+			<!--
+				Had to be very verbal with fields names, since otherwise short options name
+				algorithm runs out of choices
+			-->
+      <argument name="Ep1o_field" type="real" default_value="2*1.5*(2*M_PI*1e6)" />
+      <argument name="Em1o_field" type="real" default_value="2*1.5*(2*M_PI*1e6)" />
+      <argument name="Ep2o_field" type="real" default_value="0.05*(2*M_PI*1e6)" />
+      <argument name="Em2o_field" type="real" default_value="0.05*(2*M_PI*1e6)" />
+      <argument name="Ep3o_field" type="real" default_value="2*3.0*(2*M_PI*1e6)" />
+      <argument name="Em3o_field" type="real" default_value="2*3.0*(2*M_PI*1e6)" />
+      <argument name="Ep4o_field" type="real" default_value=".01*(2*M_PI*1e6)" />
+      <argument name="Em4o_field" type="real" default_value=".01*(2*M_PI*1e6)" />
+			<!-- Fields detuning in [1/s] -->
+      <argument name="delta1"  type="real" default_value="0.0" />
+      <argument name="delta2"  type="real" default_value="0.0" />
+      <argument name="delta3"  type="real" default_value="0.0" />
+			<!--Pulse duration/width [s] -->
+			<argument name="Pwidth"  type="real" default_value="0.1e-6" />
+			<!--  Atom and cell properties -->
+			<!--Cell length [m] -->
+			<argument name="Lcell"  type="real" default_value="1.5e-2" />
+			<!--Density of atoms [1/m^3] -->
+			<argument name="Ndens"  type="real" default_value="1e15" />
+			<!-- Projections of magnetic field in Larmor frequency units [1/s] -->
+			<argument name="WLx"  type="real" default_value="0" />
+			<argument name="WLy"  type="real" default_value="0" />
+			<argument name="WLz"  type="real" default_value="0" />
+			<!--Atoms temperature [K] -->
+			<!--TODO: looks like Temperature > 10 K knocks solver, 
+					 I am guessing detunings are too large and thus it became a stiff equation-->
+			<!--! make sure it is not equal to zero!-->
+			<argument name="Temperature"  type="real" default_value="5" />
+			<!-- This will be executed after arguments/parameters are parsed -->
+			<!-- Read the code Luke: took me a while of reading the xmds2 sources to find it -->
+			<![CDATA[
+				// Average sqrt(v^2) in Maxwell distribution for one dimension
+				if (Temperature == 0)
+					_LOG(_ERROR_LOG_LEVEL, "ERROR: Temperature should be >0 to provide range for Maxwell velocity distribution\n");
+				v_thermal_averaged=sqrt(k_boltzmann*Temperature/mass); 
+				// Maxwell distribution velocities range to take in account in [m/s]
+				// there is almost zero probability for higher velocity p(4*v_av) = 3.3e-04 * p(0)
+				V_maxwell_min = -4*v_thermal_averaged; V_maxwell_max = -V_maxwell_min; 
+			]]>
+    </arguments>
+		<bing />
+		<diagnostics /> 
+		<fftw plan="estimate" threads="1" />
+		<!--<fftw plan="patient" threads="1" />-->
+		<!-- I don't see any speed up on 6 core CPU even if use threads="6" -->
+		<!--<openmp />-->
+		<auto_vectorise />
+		<halt_non_finite />
+	</features>
+
+	<!-- 'z', 't', and 'v'  to have dimensions [m], [s], and [m/s]   -->
+	<geometry>
+		<propagation_dimension> z </propagation_dimension>
+		<transverse_dimensions>
+			<!-- IMPORTANT: looks like having a lot of points in time helps with convergence.
+					 I suspect that time spacing should be small enough to catch
+					 all pulse harmonics and more importantly 1/dt should be larger than
+					 the largest detuning (including Doppler shifts).
+					 Unfortunately calculation time is proportional to lattice size
+					 so we cannot just blindly increase it.
+					 Some rules of thumb:  
+						* lattice="1000"   domain="(-1e-6, 1e-6)" 
+							was good enough detunings up to 155 MHz (980 rad/s) notice that 1/dt=500 MHz
+						* lattice="10000"   domain="(-1e-6, 1e-6)" 
+							works for Doppler averaging in up to 400K for Rb when lasers are zero detuned
+			 -->
+			<dimension name="t"   lattice="10000"   domain="(-1e-6, 1e-6)" />
+			<dimension name="v"   lattice="2"   domain="(V_maxwell_min, V_maxwell_max)" />
+		</transverse_dimensions>
+	</geometry>
+
+	<!-- Rabi frequency --> 
+	<vector name="E_field" type="complex" initial_space="t">
+		 <!--plus/minus circular polarization components-->
+		<components>Ep1 Em1 Ep2 Em2 Ep3 Em3 Ep4 Em4</components>
+		<initialisation>
+			<![CDATA[
+			// Initial (at starting 'z' position) electromagnetic field does not depend on detuning
+			// as well as time
+			Ep1=Ep1o_field;
+			Em1=Em1o_field;
+			Ep2=Ep2o_field*exp(-pow( ((t-0.0)/Pwidth),2) );
+			Em2=Em2o_field*exp(-pow( ((t-0.0)/Pwidth),2) );
+			Ep3=Ep3o_field;
+			Em3=Em3o_field;
+			Ep4=Ep4o_field;
+			Em4=Em4o_field;
+			]]>
+		</initialisation>
+	</vector>
+
+	<!--Maxwell distribution probability p(v)-->
+	<computed_vector name="Maxwell_distribution_probabilities" dimensions="v" type="real">
+		<components>probability_v</components>
+		<evaluation>
+			<![CDATA[
+			// TODO: move to the global space/function. This reevaluated many times since it called from dependency requests but it never changes during  the script lifetime since 'v' is fixed.
+			probability_v=1.0/(v_thermal_averaged*sqrt(2*M_PI)) * exp( - mod2(v/v_thermal_averaged)/2.0 ); 
+			]]>
+		</evaluation>
+	</computed_vector>
+
+	<!--Maxwell distribution norm sum(p(v))
+			 Needed since we sum over the grid instead of true integral,
+			 we also have finite cut off velocities-->
+	<computed_vector name="Maxwell_distribution_probabilities_norm" dimensions="" type="real">
+		<components>probability_v_norm</components>
+		<evaluation>
+			<dependencies basis="v">Maxwell_distribution_probabilities</dependencies>
+			<![CDATA[
+			// TODO: move to the global space/function. This reevaluated many times since it called from dependency requests but it never changes during  the script lifetime since 'v' is fixed.
+			probability_v_norm=probability_v;
+			]]>
+		</evaluation>
+	</computed_vector>
+
+
+	<!-- Averaged across Maxwell distribution fields amplitudes -->
+	<computed_vector name="E_field_avgd" dimensions="t" type="complex">
+		<components>Ep1a Em1a Ep2a Em2a Ep3a Em3a Ep4a Em4a</components>
+		<evaluation>
+			<dependencies basis="v">E_field Maxwell_distribution_probabilities Maxwell_distribution_probabilities_norm</dependencies>
+			<![CDATA[
+			double prob_v_normalized=probability_v/probability_v_norm;
+			Ep1a=Ep1*prob_v_normalized;
+			Em1a=Em1*prob_v_normalized;
+			Ep2a=Ep2*prob_v_normalized;
+			Em2a=Em2*prob_v_normalized;
+			Ep3a=Ep3*prob_v_normalized;
+			Em3a=Em3*prob_v_normalized;
+			Ep4a=Ep4*prob_v_normalized;
+			Em4a=Em4*prob_v_normalized;
+			]]>
+		</evaluation>
+	</computed_vector>
+
+	<vector name="density_matrix" type="complex" initial_space="t">
+		<components>
+			<!-- read from Mathematica generated RbChosenRho.txt -->
+<!-- ############### RbChosenRho.txt starts ################ -->
+r0101 r0109 r0110 r0111 r0112 r0113 r0114 r0115 r0116 r0201 r0202 r0209 r0210 r0211 r0212 r0213 r0214 r0215 r0216 r0301 r0302 r0303 r0309 r0310 r0311 r0312 r0313 r0314 r0315 r0316 r0401 r0402 r0403 r0404 r0409 r0410 r0411 r0412 r0413 r0414 r0415 r0416 r0501 r0502 r0503 r0504 r0505 r0509 r0510 r0511 r0512 r0513 r0514 r0515 r0516 r0601 r0602 r0603 r0604 r0605 r0606 r0609 r0610 r0611 r0612 r0613 r0614 r0615 r0616 r0701 r0702 r0703 r0704 r0705 r0706 r0707 r0709 r0710 r0711 r0712 r0713 r0714  [...]
+<!-- ############### RbChosenRho.txt ends  ################# -->
+		</components>
+		<initialisation>
+			<!--This sets boundary condition at all times and left border of z (i.e. z=0)-->
+			<![CDATA[
+			// Note: 
+			// convergence is really slow if all populations concentrated at the bottom level |1>
+			// this is because if r11=1, everything else is 0 and then every small increment 
+			// seems to be huge and adaptive solver makes smaller and smaller steps.
+			// As quick and dirty fix I reshuffle initial population  
+			// so some of the population sits at the  second ground level |2>
+			// TODO: Fix above. Make the equation of motion for r11 
+			//       and express other level, let's say r44
+			//       through population normalization
+
+			//read from Mathematica generated RbInits.txt
+//---------------- RbInits.txt starts ------------------
+r0101 = 0.125;
+r0109 = 0;
+r0110 = 0;
+r0111 = 0;
+r0112 = 0;
+r0113 = 0;
+r0114 = 0;
+r0115 = 0;
+r0116 = 0;
+r0201 = 0;
+r0202 = 0.125;
+r0209 = 0;
+r0210 = 0;
+r0211 = 0;
+r0212 = 0;
+r0213 = 0;
+r0214 = 0;
+r0215 = 0;
+r0216 = 0;
+r0301 = 0;
+r0302 = 0;
+r0303 = 0.125;
+r0309 = 0;
+r0310 = 0;
+r0311 = 0;
+r0312 = 0;
+r0313 = 0;
+r0314 = 0;
+r0315 = 0;
+r0316 = 0;
+r0401 = 0;
+r0402 = 0;
+r0403 = 0;
+r0404 = 0.125;
+r0409 = 0;
+r0410 = 0;
+r0411 = 0;
+r0412 = 0;
+r0413 = 0;
+r0414 = 0;
+r0415 = 0;
+r0416 = 0;
+r0501 = 0;
+r0502 = 0;
+r0503 = 0;
+r0504 = 0;
+r0505 = 0.125;
+r0509 = 0;
+r0510 = 0;
+r0511 = 0;
+r0512 = 0;
+r0513 = 0;
+r0514 = 0;
+r0515 = 0;
+r0516 = 0;
+r0601 = 0;
+r0602 = 0;
+r0603 = 0;
+r0604 = 0;
+r0605 = 0;
+r0606 = 0.125;
+r0609 = 0;
+r0610 = 0;
+r0611 = 0;
+r0612 = 0;
+r0613 = 0;
+r0614 = 0;
+r0615 = 0;
+r0616 = 0;
+r0701 = 0;
+r0702 = 0;
+r0703 = 0;
+r0704 = 0;
+r0705 = 0;
+r0706 = 0;
+r0707 = 0.125;
+r0709 = 0;
+r0710 = 0;
+r0711 = 0;
+r0712 = 0;
+r0713 = 0;
+r0714 = 0;
+r0715 = 0;
+r0716 = 0;
+r0801 = 0;
+r0802 = 0;
+r0803 = 0;
+r0804 = 0;
+r0805 = 0;
+r0806 = 0;
+r0807 = 0;
+r0808 = 0.125;
+r0809 = 0;
+r0810 = 0;
+r0811 = 0;
+r0812 = 0;
+r0813 = 0;
+r0814 = 0;
+r0815 = 0;
+r0816 = 0;
+r0909 = 0;
+r0912 = 0;
+r0913 = 0;
+r0914 = 0;
+r0915 = 0;
+r0916 = 0;
+r1009 = 0;
+r1010 = 0;
+r1012 = 0;
+r1013 = 0;
+r1014 = 0;
+r1015 = 0;
+r1016 = 0;
+r1109 = 0;
+r1110 = 0;
+r1111 = 0;
+r1112 = 0;
+r1113 = 0;
+r1114 = 0;
+r1115 = 0;
+r1116 = 0;
+r1212 = 0;
+r1312 = 0;
+r1313 = 0;
+r1412 = 0;
+r1413 = 0;
+r1414 = 0;
+r1512 = 0;
+r1513 = 0;
+r1514 = 0;
+r1515 = 0;
+r1612 = 0;
+r1613 = 0;
+r1614 = 0;
+r1615 = 0;
+r1616 = 0;
+//---------------- RbInits.txt ends  ------------------
+			]]>
+		</initialisation>
+	</vector>
+
+	<sequence>
+		<!--For this set of conditions ARK45 is faster than ARK89-->
+		<!--ARK45 is good for small detuning when all frequency like term are close to zero-->
+		<integrate algorithm="ARK45" tolerance="1e-5" interval="Lcell"> 
+		<!--<integrate algorithm="SI" steps="200" interval="Lcell"> -->
+		<!--RK4 is good for large detunings when frequency like term are big, it does not try to be too smart about adaptive step which ARK seems to make too small-->
+		<!--When ARK45 works it about 3 times faster than RK4 with 1000 steps-->
+		<!--<integrate algorithm="RK4" steps="100" interval="1.5e-2">-->
+		<!--SIC algorithm seems to be much slower and needs fine 'z'  step tuning and much finer time grid-->
+		<!--For example I had to quadruple the time grid from 1000 to 4000 when increased z distance from 0.02 to 0.04-->
+
+		<!--<integrate algorithm="SIC" interval="4e-2" steps="200">-->
+
+			<samples>1</samples>
+			<!--<samples>100 100</samples>-->
+			<!--Use the next line for debuging to see velocity dependence. Uncomment/switch on output groups 3,4-->
+			<!--<samples>100 100 100 100</samples>--> 
+			<operators>
+        <operator kind="cross_propagation" algorithm="SI" propagation_dimension="t">
+					<integration_vectors>density_matrix</integration_vectors>
+          <dependencies>E_field_avgd</dependencies>
+          <boundary_condition kind="left">
+						<!--This set boundary condition at all 'z'  and left border of 't' (i.e. min(t))-->
+						<!--
+            <![CDATA[
+							r11 = 0; r22 = 1; r33 = 0; r44 = 0;
+							r12 = 0; r13 = 0; r14 = 0;
+							r23 = 0; r24 = 0;
+							r34 = 0;
+							printf("z= %g, t= %g\n", z, t);
+            ]]>
+						-->
+          </boundary_condition>
+					<![CDATA[
+						// Equations of motions according to Simon's mathematica code
+						//read from Mathematica generated RbEquations.txt
+//---------------- RbEquations.txt starts ------------------
+dr0101_dt = gt/8. - gt*r0101 + (g1*r0909)/2. + (g2*r1212)/3. + (g2*r1313)/6. - i*((conj(Em1a)*conj(r0109))/4. - (conj(Em4a)*conj(r0113))/(4.*rt6) - (Em1a*r0109)/4. + (Em4a*r0113)/(4.*rt6) + r0201*(WLx/2. - (i*WLy)/2.) - conj(r0201)*(WLx/2. + (i*WLy)/2.));
+dr0109_dt = (-(gt*r0109) - (gt + g1)*r0109)/2. - i*(-(conj(Ep1a)*conj(r0301))/(4.*rt6) + (conj(Ep2a)*conj(r0701))/(4.*rt6) - (conj(Em4a)*conj(r0913))/(4.*rt6) - (conj(Em1a)*r0101)/4. + (conj(Em1a)*r0909)/4. + r0209*(WLx/2. - (i*WLy)/2.) - r0110*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0109*(-delta1 - v*Kvec1 - WLz/6.) + r0109*WLz);
+dr0110_dt = (-(gt*r0110) - (gt + g1)*r0110)/2. - i*(-(conj(Em1a)*conj(r0201))/(4.*rt2) - (conj(Ep1a)*conj(r0401))/(4.*rt2) - (conj(Em2a)*conj(r0601))/(4.*rt6) + (conj(Ep2a)*conj(r0801))/(4.*rt6) + (conj(Em1a)*conj(r1009))/4. - (conj(Em4a)*conj(r1013))/(4.*rt6) + (delta1 + v*Kvec1)*r0110 + r0210*(WLx/2. - (i*WLy)/2.) - r0111*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0109*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) + r0110*WLz);
+dr0111_dt = (-(gt*r0111) - (gt + g1)*r0111)/2. - i*(-(conj(Em1a)*conj(r0301))/(4.*rt6) - (conj(Ep1a)*conj(r0501))/4. - (conj(Em2a)*conj(r0701))/(4.*rt6) + (conj(Em1a)*conj(r1109))/4. - (conj(Em4a)*conj(r1113))/(4.*rt6) + r0211*(WLx/2. - (i*WLy)/2.) - r0110*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r0111*(-delta1 - v*Kvec1 + WLz/6.) + r0111*WLz);
+dr0112_dt = (-(gt*r0112) - (gt + g2)*r0112)/2. - i*(-(conj(Ep4a)*conj(r0201))/(4.*rt6) - (conj(Ep3a)*conj(r0601))/(4.*rt2) + (conj(Em1a)*r0912)/4. - (conj(Em4a)*r1312)/(4.*rt6) + r0212*(WLx/2. - (i*WLy)/2.) - r0113*((2*WLx)/3. + (2*i*WLy)/3.) + r0112*WLz - r0112*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr0113_dt = (-(gt*r0113) - (gt + g2)*r0113)/2. - i*(-(conj(Ep4a)*conj(r0301))/8. - (conj(Ep3a)*conj(r0701))/8. + (conj(Em4a)*r0101)/(4.*rt6) + (conj(Em1a)*r0913)/4. - (conj(Em4a)*r1313)/(4.*rt6) - r0112*((2*WLx)/3. - (2*i*WLy)/3.) + r0213*(WLx/2. - (i*WLy)/2.) - r0114*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) - r0113*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (2*WLz)/3.) + r0113*WLz);
+dr0114_dt = (-(gt*r0114) - (gt + g2)*r0114)/2. - i*((conj(Em4a)*conj(r0201))/8. - (conj(Ep4a)*conj(r0401))/8. - (conj(Em3a)*conj(r0601))/(8.*rt3) - (conj(Ep3a)*conj(r0801))/(8.*rt3) - (conj(Em4a)*conj(r1413))/(4.*rt6) - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r0114 + (conj(Em1a)*r0914)/4. + r0214*(WLx/2. - (i*WLy)/2.) - r0113*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0115*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r0114*WLz);
+dr0115_dt = (-(gt*r0115) - (gt + g2)*r0115)/2. - i*((conj(Em4a)*conj(r0301))/8. - (conj(Ep4a)*conj(r0501))/(4.*rt6) - (conj(Em3a)*conj(r0701))/8. - (conj(Em4a)*conj(r1513))/(4.*rt6) + (conj(Em1a)*r0915)/4. + r0215*(WLx/2. - (i*WLy)/2.) - r0116*((2*WLx)/3. + (2*i*WLy)/3.) - r0114*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0115*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (2*WLz)/3.) + r0115*WLz);
+dr0116_dt = (-(gt*r0116) - (gt + g2)*r0116)/2. - i*((conj(Em4a)*conj(r0401))/(4.*rt6) - (conj(Em3a)*conj(r0801))/(4.*rt2) - (conj(Em4a)*conj(r1613))/(4.*rt6) + (conj(Em1a)*r0916)/4. - r0115*((2*WLx)/3. - (2*i*WLy)/3.) + r0216*(WLx/2. - (i*WLy)/2.) - r0116*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) + r0116*WLz);
+dr0201_dt = -(gt*r0201) + (g1*r1009)/(2.*rt2) + (g2*r1312)/6. + (g2*r1413)/(2.*rt6) - i*((conj(Em1a)*conj(r0110))/(4.*rt2) + (conj(Ep4a)*conj(r0112))/(4.*rt6) - (conj(Em4a)*conj(r0114))/8. - (Em1a*r0209)/4. + (Em4a*r0213)/(4.*rt6) + r0101*(WLx/2. + (i*WLy)/2.) - r0202*(WLx/2. + (i*WLy)/2.) + r0301*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - (r0201*WLz)/2.);
+dr0202_dt = gt/8. - gt*r0202 + (g1*r0909)/4. + (g1*r1010)/4. + (g2*r1212)/6. + (g2*r1313)/12. + (g2*r1414)/4. - i*((conj(Em1a)*conj(r0210))/(4.*rt2) + (conj(Ep4a)*conj(r0212))/(4.*rt6) - (conj(Em4a)*conj(r0214))/8. - (Em1a*r0210)/(4.*rt2) - (Ep4a*r0212)/(4.*rt6) + (Em4a*r0214)/8. - r0201*(WLx/2. - (i*WLy)/2.) + conj(r0201)*(WLx/2. + (i*WLy)/2.) + r0302*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - conj(r0302)*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.));
+dr0209_dt = (-(gt*r0209) - (gt + g1)*r0209)/2. - i*(-(conj(Ep1a)*conj(r0302))/(4.*rt6) + (conj(Ep2a)*conj(r0702))/(4.*rt6) + (conj(Ep4a)*conj(r0912))/(4.*rt6) - (conj(Em4a)*conj(r0914))/8. - (conj(Em1a)*r0201)/4. + (conj(Em1a)*r1009)/(4.*rt2) + r0109*(WLx/2. + (i*WLy)/2.) + r0309*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - r0210*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0209*(-delta1 - v*Kvec1 - WLz/6.) + (r0209*WLz)/2.);
+dr0210_dt = (-(gt*r0210) - (gt + g1)*r0210)/2. - i*(-(conj(Ep1a)*conj(r0402))/(4.*rt2) - (conj(Em2a)*conj(r0602))/(4.*rt6) + (conj(Ep2a)*conj(r0802))/(4.*rt6) + (conj(Ep4a)*conj(r1012))/(4.*rt6) - (conj(Em4a)*conj(r1014))/8. - (conj(Em1a)*r0202)/(4.*rt2) + (delta1 + v*Kvec1)*r0210 + (conj(Em1a)*r1010)/(4.*rt2) + r0110*(WLx/2. + (i*WLy)/2.) + r0310*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - r0211*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0209*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) + (r0210*WLz)/2.);
+dr0211_dt = (-(gt*r0211) - (gt + g1)*r0211)/2. - i*(-(conj(Em1a)*conj(r0302))/(4.*rt6) - (conj(Ep1a)*conj(r0502))/4. - (conj(Em2a)*conj(r0702))/(4.*rt6) + (conj(Em1a)*conj(r1110))/(4.*rt2) + (conj(Ep4a)*conj(r1112))/(4.*rt6) - (conj(Em4a)*conj(r1114))/8. + r0111*(WLx/2. + (i*WLy)/2.) + r0311*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - r0210*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r0211*(-delta1 - v*Kvec1 + WLz/6.) + (r0211*WLz)/2.);
+dr0212_dt = (-(gt*r0212) - (gt + g2)*r0212)/2. - i*(-(conj(Ep3a)*conj(r0602))/(4.*rt2) - (conj(Ep4a)*r0202)/(4.*rt6) + (conj(Em1a)*r1012)/(4.*rt2) + (conj(Ep4a)*r1212)/(4.*rt6) - (conj(Em4a)*r1412)/8. + r0112*(WLx/2. + (i*WLy)/2.) - r0213*((2*WLx)/3. + (2*i*WLy)/3.) + r0312*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + (r0212*WLz)/2. - r0212*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr0213_dt = (-(gt*r0213) - (gt + g2)*r0213)/2. - i*(-(conj(Ep4a)*conj(r0302))/8. - (conj(Ep3a)*conj(r0702))/8. + (conj(Ep4a)*conj(r1312))/(4.*rt6) + (conj(Em4a)*r0201)/(4.*rt6) + (conj(Em1a)*r1013)/(4.*rt2) - (conj(Em4a)*r1413)/8. - r0212*((2*WLx)/3. - (2*i*WLy)/3.) + r0113*(WLx/2. + (i*WLy)/2.) - r0214*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r0313*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - r0213*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (2*W [...]
+dr0214_dt = (-(gt*r0214) - (gt + g2)*r0214)/2. - i*(-(conj(Ep4a)*conj(r0402))/8. - (conj(Em3a)*conj(r0602))/(8.*rt3) - (conj(Ep3a)*conj(r0802))/(8.*rt3) + (conj(Ep4a)*conj(r1412))/(4.*rt6) + (conj(Em4a)*r0202)/8. - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r0214 + (conj(Em1a)*r1014)/(4.*rt2) - (conj(Em4a)*r1414)/8. + r0114*(WLx/2. + (i*WLy)/2.) - r0213*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0215*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666 [...]
+dr0215_dt = (-(gt*r0215) - (gt + g2)*r0215)/2. - i*((conj(Em4a)*conj(r0302))/8. - (conj(Ep4a)*conj(r0502))/(4.*rt6) - (conj(Em3a)*conj(r0702))/8. + (conj(Ep4a)*conj(r1512))/(4.*rt6) - (conj(Em4a)*conj(r1514))/8. + (conj(Em1a)*r1015)/(4.*rt2) + r0115*(WLx/2. + (i*WLy)/2.) - r0216*((2*WLx)/3. + (2*i*WLy)/3.) - r0214*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r0315*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - r0215*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*K [...]
+dr0216_dt = (-(gt*r0216) - (gt + g2)*r0216)/2. - i*((conj(Em4a)*conj(r0402))/(4.*rt6) - (conj(Em3a)*conj(r0802))/(4.*rt2) + (conj(Ep4a)*conj(r1612))/(4.*rt6) - (conj(Em4a)*conj(r1614))/8. + (conj(Em1a)*r1016)/(4.*rt2) - r0215*((2*WLx)/3. - (2*i*WLy)/3.) + r0116*(WLx/2. + (i*WLy)/2.) + r0316*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - r0216*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) + (r0216*WLz)/2.);
+dr0301_dt = -(gt*r0301) + (g1*r1109)/(2.*rt6) + (g2*r1513)/(2.*rt6) - i*((conj(Ep1a)*conj(r0109))/(4.*rt6) + (conj(Em1a)*conj(r0111))/(4.*rt6) + (conj(Ep4a)*conj(r0113))/8. - (conj(Em4a)*conj(r0115))/8. - (Em1a*r0309)/4. + (Em4a*r0313)/(4.*rt6) - r0302*(WLx/2. + (i*WLy)/2.) + r0401*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0201*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0301*WLz);
+dr0302_dt = -(gt*r0302) + (g1*r1009)/(2.*rt3) + (g1*r1110)/(4.*rt3) + (g2*r1312)/(2.*rt6) + (g2*r1514)/4. - i*((conj(Ep1a)*conj(r0209))/(4.*rt6) + (conj(Em1a)*conj(r0211))/(4.*rt6) + (conj(Ep4a)*conj(r0213))/8. - (conj(Em4a)*conj(r0215))/8. - (Em1a*r0310)/(4.*rt2) - (Ep4a*r0312)/(4.*rt6) + (Em4a*r0314)/8. - r0301*(WLx/2. - (i*WLy)/2.) + r0402*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0202*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0303*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) [...]
+dr0303_dt = gt/8. - gt*r0303 + (g1*r0909)/12. + (g1*r1010)/3. + (g1*r1111)/12. + (g2*r1313)/4. + (g2*r1515)/4. - i*((conj(Ep1a)*conj(r0309))/(4.*rt6) + (conj(Em1a)*conj(r0311))/(4.*rt6) + (conj(Ep4a)*conj(r0313))/8. - (conj(Em4a)*conj(r0315))/8. - (Ep1a*r0309)/(4.*rt6) - (Em1a*r0311)/(4.*rt6) - (Ep4a*r0313)/8. + (Em4a*r0315)/8. - r0302*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0403*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + conj(r0302)*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.)  [...]
+dr0309_dt = (-(gt*r0309) - (gt + g1)*r0309)/2. - i*((conj(Ep2a)*conj(r0703))/(4.*rt6) + (conj(Ep4a)*conj(r0913))/8. - (conj(Em4a)*conj(r0915))/8. - (conj(Em1a)*r0301)/4. - (conj(Ep1a)*r0303)/(4.*rt6) + (conj(Ep1a)*r0909)/(4.*rt6) + (conj(Em1a)*r1109)/(4.*rt6) + r0409*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0209*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0310*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0309*(-delta1 - v*Kvec1 - WLz/6.));
+dr0310_dt = (-(gt*r0310) - (gt + g1)*r0310)/2. - i*(-(conj(Ep1a)*conj(r0403))/(4.*rt2) - (conj(Em2a)*conj(r0603))/(4.*rt6) + (conj(Ep2a)*conj(r0803))/(4.*rt6) + (conj(Ep1a)*conj(r1009))/(4.*rt6) + (conj(Ep4a)*conj(r1013))/8. - (conj(Em4a)*conj(r1015))/8. - (conj(Em1a)*r0302)/(4.*rt2) + (delta1 + v*Kvec1)*r0310 + (conj(Em1a)*r1110)/(4.*rt6) + r0410*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0210*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0311*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r [...]
+dr0311_dt = (-(gt*r0311) - (gt + g1)*r0311)/2. - i*(-(conj(Ep1a)*conj(r0503))/4. - (conj(Em2a)*conj(r0703))/(4.*rt6) + (conj(Ep1a)*conj(r1109))/(4.*rt6) + (conj(Ep4a)*conj(r1113))/8. - (conj(Em4a)*conj(r1115))/8. - (conj(Em1a)*r0303)/(4.*rt6) + (conj(Em1a)*r1111)/(4.*rt6) + r0411*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0211*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0310*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r0311*(-delta1 - v*Kvec1 + WLz/6.));
+dr0312_dt = (-(gt*r0312) - (gt + g2)*r0312)/2. - i*(-(conj(Ep3a)*conj(r0603))/(4.*rt2) - (conj(Ep4a)*r0302)/(4.*rt6) + (conj(Ep1a)*r0912)/(4.*rt6) + (conj(Em1a)*r1112)/(4.*rt6) + (conj(Ep4a)*r1312)/8. - (conj(Em4a)*r1512)/8. - r0313*((2*WLx)/3. + (2*i*WLy)/3.) + r0412*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0212*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0312*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr0313_dt = (-(gt*r0313) - (gt + g2)*r0313)/2. - i*(-(conj(Ep3a)*conj(r0703))/8. + (conj(Em4a)*r0301)/(4.*rt6) - (conj(Ep4a)*r0303)/8. + (conj(Ep1a)*r0913)/(4.*rt6) + (conj(Em1a)*r1113)/(4.*rt6) + (conj(Ep4a)*r1313)/8. - (conj(Em4a)*r1513)/8. - r0312*((2*WLx)/3. - (2*i*WLy)/3.) - r0314*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r0413*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0213*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0313*(-delta1 + delta2 - delta3 -  [...]
+dr0314_dt = (-(gt*r0314) - (gt + g2)*r0314)/2. - i*(-(conj(Ep4a)*conj(r0403))/8. - (conj(Em3a)*conj(r0603))/(8.*rt3) - (conj(Ep3a)*conj(r0803))/(8.*rt3) + (conj(Ep4a)*conj(r1413))/8. + (conj(Em4a)*r0302)/8. - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r0314 + (conj(Ep1a)*r0914)/(4.*rt6) + (conj(Em1a)*r1114)/(4.*rt6) - (conj(Em4a)*r1514)/8. - r0313*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0315*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666 [...]
+dr0315_dt = (-(gt*r0315) - (gt + g2)*r0315)/2. - i*(-(conj(Ep4a)*conj(r0503))/(4.*rt6) - (conj(Em3a)*conj(r0703))/8. + (conj(Ep4a)*conj(r1513))/8. + (conj(Em4a)*r0303)/8. + (conj(Ep1a)*r0915)/(4.*rt6) + (conj(Em1a)*r1115)/(4.*rt6) - (conj(Em4a)*r1515)/8. - r0316*((2*WLx)/3. + (2*i*WLy)/3.) - r0314*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r0415*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0215*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0315*(-delta1 + delta2 [...]
+dr0316_dt = (-(gt*r0316) - (gt + g2)*r0316)/2. - i*((conj(Em4a)*conj(r0403))/(4.*rt6) - (conj(Em3a)*conj(r0803))/(4.*rt2) + (conj(Ep4a)*conj(r1613))/8. - (conj(Em4a)*conj(r1615))/8. + (conj(Ep1a)*r0916)/(4.*rt6) + (conj(Em1a)*r1116)/(4.*rt6) - r0315*((2*WLx)/3. - (2*i*WLy)/3.) + r0416*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0216*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0316*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.));
+dr0401_dt = -(gt*r0401) - (g2*r1512)/6. + (g2*r1613)/6. - i*((conj(Ep1a)*conj(r0110))/(4.*rt2) + (conj(Ep4a)*conj(r0114))/8. - (conj(Em4a)*conj(r0116))/(4.*rt6) - (Em1a*r0409)/4. + (Em4a*r0413)/(4.*rt6) + r0501*(WLx/2. - (i*WLy)/2.) - r0402*(WLx/2. + (i*WLy)/2.) + r0301*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - (3*r0401*WLz)/2.);
+dr0402_dt = -(gt*r0402) + (g1*r1109)/4. + (g2*r1412)/(2.*rt6) - (g2*r1513)/12. + (g2*r1614)/(2.*rt6) - i*((conj(Ep1a)*conj(r0210))/(4.*rt2) + (conj(Ep4a)*conj(r0214))/8. - (conj(Em4a)*conj(r0216))/(4.*rt6) - (Em1a*r0410)/(4.*rt2) - (Ep4a*r0412)/(4.*rt6) + (Em4a*r0414)/8. - r0401*(WLx/2. - (i*WLy)/2.) + r0502*(WLx/2. - (i*WLy)/2.) + r0302*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0403*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0402*WLz);
+dr0403_dt = -(gt*r0403) + (g1*r1009)/(4.*rt3) + (g1*r1110)/(2.*rt3) + (g2*r1413)/4. + (g2*r1615)/(2.*rt6) - i*((conj(Ep1a)*conj(r0310))/(4.*rt2) + (conj(Ep4a)*conj(r0314))/8. - (conj(Em4a)*conj(r0316))/(4.*rt6) - (Ep1a*r0409)/(4.*rt6) - (Em1a*r0411)/(4.*rt6) - (Ep4a*r0413)/8. + (Em4a*r0415)/8. + r0503*(WLx/2. - (i*WLy)/2.) - r0402*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0303*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0404*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - (r0403*WLz)/2.);
+dr0404_dt = gt/8. - gt*r0404 + (g1*r1010)/4. + (g1*r1111)/4. + (g2*r1414)/4. + (g2*r1515)/12. + (g2*r1616)/6. - i*((conj(Ep1a)*conj(r0410))/(4.*rt2) + (conj(Ep4a)*conj(r0414))/8. - (conj(Em4a)*conj(r0416))/(4.*rt6) - (Ep1a*r0410)/(4.*rt2) - (Ep4a*r0414)/8. + (Em4a*r0416)/(4.*rt6) + r0504*(WLx/2. - (i*WLy)/2.) - conj(r0504)*(WLx/2. + (i*WLy)/2.) - r0403*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + conj(r0403)*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.));
+dr0409_dt = (-(gt*r0409) - (gt + g1)*r0409)/2. - i*((conj(Ep2a)*conj(r0704))/(4.*rt6) + (conj(Ep4a)*conj(r0914))/8. - (conj(Em4a)*conj(r0916))/(4.*rt6) - (conj(Em1a)*r0401)/4. - (conj(Ep1a)*r0403)/(4.*rt6) + (conj(Ep1a)*r1009)/(4.*rt2) + r0509*(WLx/2. - (i*WLy)/2.) + r0309*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0410*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0409*(-delta1 - v*Kvec1 - WLz/6.) - (r0409*WLz)/2.);
+dr0410_dt = (-(gt*r0410) - (gt + g1)*r0410)/2. - i*(-(conj(Em2a)*conj(r0604))/(4.*rt6) + (conj(Ep2a)*conj(r0804))/(4.*rt6) + (conj(Ep4a)*conj(r1014))/8. - (conj(Em4a)*conj(r1016))/(4.*rt6) - (conj(Em1a)*r0402)/(4.*rt2) - (conj(Ep1a)*r0404)/(4.*rt2) + (delta1 + v*Kvec1)*r0410 + (conj(Ep1a)*r1010)/(4.*rt2) + r0510*(WLx/2. - (i*WLy)/2.) + r0310*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0411*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0409*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - (r0410*WLz)/2.);
+dr0411_dt = (-(gt*r0411) - (gt + g1)*r0411)/2. - i*(-(conj(Ep1a)*conj(r0504))/4. - (conj(Em2a)*conj(r0704))/(4.*rt6) + (conj(Ep1a)*conj(r1110))/(4.*rt2) + (conj(Ep4a)*conj(r1114))/8. - (conj(Em4a)*conj(r1116))/(4.*rt6) - (conj(Em1a)*r0403)/(4.*rt6) + r0511*(WLx/2. - (i*WLy)/2.) + r0311*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0410*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r0411*(-delta1 - v*Kvec1 + WLz/6.) - (r0411*WLz)/2.);
+dr0412_dt = (-(gt*r0412) - (gt + g2)*r0412)/2. - i*(-(conj(Ep3a)*conj(r0604))/(4.*rt2) - (conj(Ep4a)*r0402)/(4.*rt6) + (conj(Ep1a)*r1012)/(4.*rt2) + (conj(Ep4a)*r1412)/8. - (conj(Em4a)*r1612)/(4.*rt6) + r0512*(WLx/2. - (i*WLy)/2.) - r0413*((2*WLx)/3. + (2*i*WLy)/3.) + r0312*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - (r0412*WLz)/2. - r0412*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr0413_dt = (-(gt*r0413) - (gt + g2)*r0413)/2. - i*(-(conj(Ep3a)*conj(r0704))/8. + (conj(Em4a)*r0401)/(4.*rt6) - (conj(Ep4a)*r0403)/8. + (conj(Ep1a)*r1013)/(4.*rt2) + (conj(Ep4a)*r1413)/8. - (conj(Em4a)*r1613)/(4.*rt6) - r0412*((2*WLx)/3. - (2*i*WLy)/3.) + r0513*(WLx/2. - (i*WLy)/2.) - r0414*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r0313*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0413*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (2*WLz)/3.) - (r [...]
+dr0414_dt = (-(gt*r0414) - (gt + g2)*r0414)/2. - i*(-(conj(Em3a)*conj(r0604))/(8.*rt3) - (conj(Ep3a)*conj(r0804))/(8.*rt3) + (conj(Em4a)*r0402)/8. - (conj(Ep4a)*r0404)/8. - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r0414 + (conj(Ep1a)*r1014)/(4.*rt2) + (conj(Ep4a)*r1414)/8. - (conj(Em4a)*r1614)/(4.*rt6) + r0514*(WLx/2. - (i*WLy)/2.) - r0413*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0415*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WL [...]
+dr0415_dt = (-(gt*r0415) - (gt + g2)*r0415)/2. - i*(-(conj(Ep4a)*conj(r0504))/(4.*rt6) - (conj(Em3a)*conj(r0704))/8. + (conj(Ep4a)*conj(r1514))/8. + (conj(Em4a)*r0403)/8. + (conj(Ep1a)*r1015)/(4.*rt2) - (conj(Em4a)*r1615)/(4.*rt6) + r0515*(WLx/2. - (i*WLy)/2.) - r0416*((2*WLx)/3. + (2*i*WLy)/3.) - r0414*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r0315*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0415*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (2*W [...]
+dr0416_dt = (-(gt*r0416) - (gt + g2)*r0416)/2. - i*(-(conj(Em3a)*conj(r0804))/(4.*rt2) + (conj(Ep4a)*conj(r1614))/8. + (conj(Em4a)*r0404)/(4.*rt6) + (conj(Ep1a)*r1016)/(4.*rt2) - (conj(Em4a)*r1616)/(4.*rt6) - r0415*((2*WLx)/3. - (2*i*WLy)/3.) + r0516*(WLx/2. - (i*WLy)/2.) + r0316*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0416*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) - (r0416*WLz)/2.);
+dr0501_dt = -(gt*r0501) - (g2*r1612)/3. - i*((conj(Ep1a)*conj(r0111))/4. + (conj(Ep4a)*conj(r0115))/(4.*rt6) - (Em1a*r0509)/4. + (Em4a*r0513)/(4.*rt6) + r0401*(WLx/2. + (i*WLy)/2.) - r0502*(WLx/2. + (i*WLy)/2.) - 2*r0501*WLz);
+dr0502_dt = -(gt*r0502) + (g2*r1512)/6. - (g2*r1613)/6. - i*((conj(Ep1a)*conj(r0211))/4. + (conj(Ep4a)*conj(r0215))/(4.*rt6) - (Em1a*r0510)/(4.*rt2) - (Ep4a*r0512)/(4.*rt6) + (Em4a*r0514)/8. - r0501*(WLx/2. - (i*WLy)/2.) + r0402*(WLx/2. + (i*WLy)/2.) - r0503*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - (3*r0502*WLz)/2.);
+dr0503_dt = -(gt*r0503) + (g1*r1109)/(2.*rt6) + (g2*r1513)/(2.*rt6) - i*((conj(Ep1a)*conj(r0311))/4. + (conj(Ep4a)*conj(r0315))/(4.*rt6) - (Ep1a*r0509)/(4.*rt6) - (Em1a*r0511)/(4.*rt6) - (Ep4a*r0513)/8. + (Em4a*r0515)/8. + r0403*(WLx/2. + (i*WLy)/2.) - r0502*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - r0504*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0503*WLz);
+dr0504_dt = -(gt*r0504) + (g1*r1110)/(2.*rt2) + (g2*r1514)/(2.*rt6) + (g2*r1615)/6. - i*((conj(Ep1a)*conj(r0411))/4. + (conj(Ep4a)*conj(r0415))/(4.*rt6) - (Ep1a*r0510)/(4.*rt2) - (Ep4a*r0514)/8. + (Em4a*r0516)/(4.*rt6) + r0404*(WLx/2. + (i*WLy)/2.) - r0505*(WLx/2. + (i*WLy)/2.) - r0503*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - (r0504*WLz)/2.);
+dr0505_dt = gt/8. - gt*r0505 + (g1*r1111)/2. + (g2*r1515)/6. + (g2*r1616)/3. - i*((conj(Ep1a)*conj(r0511))/4. + (conj(Ep4a)*conj(r0515))/(4.*rt6) - (Ep1a*r0511)/4. - (Ep4a*r0515)/(4.*rt6) - r0504*(WLx/2. - (i*WLy)/2.) + conj(r0504)*(WLx/2. + (i*WLy)/2.));
+dr0509_dt = (-(gt*r0509) - (gt + g1)*r0509)/2. - i*((conj(Ep2a)*conj(r0705))/(4.*rt6) + (conj(Ep4a)*conj(r0915))/(4.*rt6) - (conj(Em1a)*r0501)/4. - (conj(Ep1a)*r0503)/(4.*rt6) + (conj(Ep1a)*r1109)/4. + r0409*(WLx/2. + (i*WLy)/2.) - r0510*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0509*(-delta1 - v*Kvec1 - WLz/6.) - r0509*WLz);
+dr0510_dt = (-(gt*r0510) - (gt + g1)*r0510)/2. - i*(-(conj(Em2a)*conj(r0605))/(4.*rt6) + (conj(Ep2a)*conj(r0805))/(4.*rt6) + (conj(Ep4a)*conj(r1015))/(4.*rt6) - (conj(Em1a)*r0502)/(4.*rt2) - (conj(Ep1a)*r0504)/(4.*rt2) + (delta1 + v*Kvec1)*r0510 + (conj(Ep1a)*r1110)/4. + r0410*(WLx/2. + (i*WLy)/2.) - r0511*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0509*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r0510*WLz);
+dr0511_dt = (-(gt*r0511) - (gt + g1)*r0511)/2. - i*(-(conj(Em2a)*conj(r0705))/(4.*rt6) + (conj(Ep4a)*conj(r1115))/(4.*rt6) - (conj(Em1a)*r0503)/(4.*rt6) - (conj(Ep1a)*r0505)/4. + (conj(Ep1a)*r1111)/4. + r0411*(WLx/2. + (i*WLy)/2.) - r0510*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r0511*(-delta1 - v*Kvec1 + WLz/6.) - r0511*WLz);
+dr0512_dt = (-(gt*r0512) - (gt + g2)*r0512)/2. - i*(-(conj(Ep3a)*conj(r0605))/(4.*rt2) - (conj(Ep4a)*r0502)/(4.*rt6) + (conj(Ep1a)*r1112)/4. + (conj(Ep4a)*r1512)/(4.*rt6) + r0412*(WLx/2. + (i*WLy)/2.) - r0513*((2*WLx)/3. + (2*i*WLy)/3.) - r0512*WLz - r0512*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr0513_dt = (-(gt*r0513) - (gt + g2)*r0513)/2. - i*(-(conj(Ep3a)*conj(r0705))/8. + (conj(Em4a)*r0501)/(4.*rt6) - (conj(Ep4a)*r0503)/8. + (conj(Ep1a)*r1113)/4. + (conj(Ep4a)*r1513)/(4.*rt6) - r0512*((2*WLx)/3. - (2*i*WLy)/3.) + r0413*(WLx/2. + (i*WLy)/2.) - r0514*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) - r0513*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (2*WLz)/3.) - r0513*WLz);
+dr0514_dt = (-(gt*r0514) - (gt + g2)*r0514)/2. - i*(-(conj(Em3a)*conj(r0605))/(8.*rt3) - (conj(Ep3a)*conj(r0805))/(8.*rt3) + (conj(Em4a)*r0502)/8. - (conj(Ep4a)*r0504)/8. - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r0514 + (conj(Ep1a)*r1114)/4. + (conj(Ep4a)*r1514)/(4.*rt6) + r0414*(WLx/2. + (i*WLy)/2.) - r0513*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0515*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) - r0514*WLz);
+dr0515_dt = (-(gt*r0515) - (gt + g2)*r0515)/2. - i*(-(conj(Em3a)*conj(r0705))/8. + (conj(Em4a)*r0503)/8. - (conj(Ep4a)*r0505)/(4.*rt6) + (conj(Ep1a)*r1115)/4. + (conj(Ep4a)*r1515)/(4.*rt6) + r0415*(WLx/2. + (i*WLy)/2.) - r0516*((2*WLx)/3. + (2*i*WLy)/3.) - r0514*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0515*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (2*WLz)/3.) - r0515*WLz);
+dr0516_dt = (-(gt*r0516) - (gt + g2)*r0516)/2. - i*(-(conj(Em3a)*conj(r0805))/(4.*rt2) + (conj(Ep4a)*conj(r1615))/(4.*rt6) + (conj(Em4a)*r0504)/(4.*rt6) + (conj(Ep1a)*r1116)/4. - r0515*((2*WLx)/3. - (2*i*WLy)/3.) + r0416*(WLx/2. + (i*WLy)/2.) - r0516*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) - r0516*WLz);
+dr0601_dt = -(gt*r0601) - i*((conj(Em2a)*conj(r0110))/(4.*rt6) + (conj(Ep3a)*conj(r0112))/(4.*rt2) + (conj(Em3a)*conj(r0114))/(8.*rt3) - (Em1a*r0609)/4. + (Em4a*r0613)/(4.*rt6) - r0602*(WLx/2. + (i*WLy)/2.) + r0701*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0601*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.) - r0601*WLz);
+dr0602_dt = -(gt*r0602) - i*((conj(Em2a)*conj(r0210))/(4.*rt6) + (conj(Ep3a)*conj(r0212))/(4.*rt2) + (conj(Em3a)*conj(r0214))/(8.*rt3) - (Em1a*r0610)/(4.*rt2) - (Ep4a*r0612)/(4.*rt6) + (Em4a*r0614)/8. - r0601*(WLx/2. - (i*WLy)/2.) - r0603*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) + r0702*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0602*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.) - (r0602*WLz)/2.);
+dr0603_dt = -(gt*r0603) - i*((conj(Em2a)*conj(r0310))/(4.*rt6) + (conj(Ep3a)*conj(r0312))/(4.*rt2) + (conj(Em3a)*conj(r0314))/(8.*rt3) - (Ep1a*r0609)/(4.*rt6) - (Em1a*r0611)/(4.*rt6) - (Ep4a*r0613)/8. + (Em4a*r0615)/8. - r0602*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - r0604*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) + r0703*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0603*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.));
+dr0604_dt = -(gt*r0604) - i*((conj(Em2a)*conj(r0410))/(4.*rt6) + (conj(Ep3a)*conj(r0412))/(4.*rt2) + (conj(Em3a)*conj(r0414))/(8.*rt3) - (Ep1a*r0610)/(4.*rt2) - (Ep4a*r0614)/8. + (Em4a*r0616)/(4.*rt6) - r0605*(WLx/2. + (i*WLy)/2.) - r0603*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0704*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0604*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.) + (r0604*WLz)/2.);
+dr0605_dt = -(gt*r0605) - i*((conj(Em2a)*conj(r0510))/(4.*rt6) + (conj(Ep3a)*conj(r0512))/(4.*rt2) + (conj(Em3a)*conj(r0514))/(8.*rt3) - (Ep1a*r0611)/4. - (Ep4a*r0615)/(4.*rt6) - r0604*(WLx/2. - (i*WLy)/2.) + r0705*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0605*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.) + r0605*WLz);
+dr0606_dt = gt/8. - gt*r0606 + (g1*r0909)/12. + (g1*r1010)/12. + (g2*r1212)/2. + (g2*r1313)/4. + (g2*r1414)/12. - i*((conj(Em2a)*conj(r0610))/(4.*rt6) + (conj(Ep3a)*conj(r0612))/(4.*rt2) + (conj(Em3a)*conj(r0614))/(8.*rt3) - (Em2a*r0610)/(4.*rt6) - (Ep3a*r0612)/(4.*rt2) - (Em3a*r0614)/(8.*rt3) - conj(r0706)*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0706*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)));
+dr0609_dt = (-(gt*r0609) - (gt + g1)*r0609)/2. - i*((conj(Ep2a)*conj(r0706))/(4.*rt6) + (conj(Ep3a)*conj(r0912))/(4.*rt2) + (conj(Em3a)*conj(r0914))/(8.*rt3) - (conj(Em1a)*r0601)/4. - (conj(Ep1a)*r0603)/(4.*rt6) + (conj(Em2a)*r1009)/(4.*rt6) - r0610*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) + r0709*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0609*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.) - r0609*(-delta1 - v*Kvec1 - WLz/6.));
+dr0610_dt = (-(gt*r0610) - (gt + g1)*r0610)/2. - i*((conj(Ep2a)*conj(r0806))/(4.*rt6) + (conj(Ep3a)*conj(r1012))/(4.*rt2) + (conj(Em3a)*conj(r1014))/(8.*rt3) - (conj(Em1a)*r0602)/(4.*rt2) - (conj(Ep1a)*r0604)/(4.*rt2) - (conj(Em2a)*r0606)/(4.*rt6) + (delta1 + v*Kvec1)*r0610 + (conj(Em2a)*r1010)/(4.*rt6) - r0611*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0609*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) + r0710*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0610*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.));
+dr0611_dt = (-(gt*r0611) - (gt + g1)*r0611)/2. - i*(-(conj(Em2a)*conj(r0706))/(4.*rt6) + (conj(Em2a)*conj(r1110))/(4.*rt6) + (conj(Ep3a)*conj(r1112))/(4.*rt2) + (conj(Em3a)*conj(r1114))/(8.*rt3) - (conj(Em1a)*r0603)/(4.*rt6) - (conj(Ep1a)*r0605)/4. - r0610*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) + r0711*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0611*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.) - r0611*(-delta1 - v*Kvec1 + WLz/6.));
+dr0612_dt = (-(gt*r0612) - (gt + g2)*r0612)/2. - i*(-(conj(Ep4a)*r0602)/(4.*rt6) - (conj(Ep3a)*r0606)/(4.*rt2) + (conj(Em2a)*r1012)/(4.*rt6) + (conj(Ep3a)*r1212)/(4.*rt2) + (conj(Em3a)*r1412)/(8.*rt3) - r0613*((2*WLx)/3. + (2*i*WLy)/3.) + r0712*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0612*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.) - r0612*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr0613_dt = (-(gt*r0613) - (gt + g2)*r0613)/2. - i*(-(conj(Ep3a)*conj(r0706))/8. + (conj(Ep3a)*conj(r1312))/(4.*rt2) + (conj(Em4a)*r0601)/(4.*rt6) - (conj(Ep4a)*r0603)/8. + (conj(Em2a)*r1013)/(4.*rt6) + (conj(Em3a)*r1413)/(8.*rt3) - r0612*((2*WLx)/3. - (2*i*WLy)/3.) - r0614*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r0713*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0613*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.) - r0613*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 [...]
+dr0614_dt = (-(gt*r0614) - (gt + g2)*r0614)/2. - i*(-(conj(Ep3a)*conj(r0806))/(8.*rt3) + (conj(Ep3a)*conj(r1412))/(4.*rt2) + (conj(Em4a)*r0602)/8. - (conj(Ep4a)*r0604)/8. - (conj(Em3a)*r0606)/(8.*rt3) - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r0614 + (conj(Em2a)*r1014)/(4.*rt6) + (conj(Em3a)*r1414)/(8.*rt3) - r0613*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0615*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r0714*(-WLx/(2.*rt2 [...]
+dr0615_dt = (-(gt*r0615) - (gt + g2)*r0615)/2. - i*(-(conj(Em3a)*conj(r0706))/8. + (conj(Ep3a)*conj(r1512))/(4.*rt2) + (conj(Em3a)*conj(r1514))/(8.*rt3) + (conj(Em4a)*r0603)/8. - (conj(Ep4a)*r0605)/(4.*rt6) + (conj(Em2a)*r1015)/(4.*rt6) - r0616*((2*WLx)/3. + (2*i*WLy)/3.) - r0614*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r0715*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - r0615*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (2*WLz)/3.) + r0615*(-delta1 + delta2 [...]
+dr0616_dt = (-(gt*r0616) - (gt + g2)*r0616)/2. - i*(-(conj(Em3a)*conj(r0806))/(4.*rt2) + (conj(Ep3a)*conj(r1612))/(4.*rt2) + (conj(Em3a)*conj(r1614))/(8.*rt3) + (conj(Em4a)*r0604)/(4.*rt6) + (conj(Em2a)*r1016)/(4.*rt6) - r0615*((2*WLx)/3. - (2*i*WLy)/3.) + r0716*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - r0616*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) + r0616*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.));
+dr0701_dt = -(gt*r0701) - i*(-(conj(Ep2a)*conj(r0109))/(4.*rt6) + (conj(Em2a)*conj(r0111))/(4.*rt6) + (conj(Ep3a)*conj(r0113))/8. + (conj(Em3a)*conj(r0115))/8. + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0701 - (Em1a*r0709)/4. + (Em4a*r0713)/(4.*rt6) - r0702*(WLx/2. + (i*WLy)/2.) + r0601*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0801*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - r0701*WLz);
+dr0702_dt = -(gt*r0702) - i*(-(conj(Ep2a)*conj(r0209))/(4.*rt6) + (conj(Em2a)*conj(r0211))/(4.*rt6) + (conj(Ep3a)*conj(r0213))/8. + (conj(Em3a)*conj(r0215))/8. + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0702 - (Em1a*r0710)/(4.*rt2) - (Ep4a*r0712)/(4.*rt6) + (Em4a*r0714)/8. - r0701*(WLx/2. - (i*WLy)/2.) - r0703*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) + r0602*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0802*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - (r0702*WLz)/2.);
+dr0703_dt = -(gt*r0703) - i*(-(conj(Ep2a)*conj(r0309))/(4.*rt6) + (conj(Em2a)*conj(r0311))/(4.*rt6) + (conj(Ep3a)*conj(r0313))/8. + (conj(Em3a)*conj(r0315))/8. + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0703 - (Ep1a*r0709)/(4.*rt6) - (Em1a*r0711)/(4.*rt6) - (Ep4a*r0713)/8. + (Em4a*r0715)/8. - r0702*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - r0704*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) + r0603*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0803*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)));
+dr0704_dt = -(gt*r0704) - i*(-(conj(Ep2a)*conj(r0409))/(4.*rt6) + (conj(Em2a)*conj(r0411))/(4.*rt6) + (conj(Ep3a)*conj(r0413))/8. + (conj(Em3a)*conj(r0415))/8. + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0704 - (Ep1a*r0710)/(4.*rt2) - (Ep4a*r0714)/8. + (Em4a*r0716)/(4.*rt6) - r0705*(WLx/2. + (i*WLy)/2.) - r0703*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0604*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0804*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + (r0704*WLz)/2.);
+dr0705_dt = -(gt*r0705) - i*(-(conj(Ep2a)*conj(r0509))/(4.*rt6) + (conj(Em2a)*conj(r0511))/(4.*rt6) + (conj(Ep3a)*conj(r0513))/8. + (conj(Em3a)*conj(r0515))/8. + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0705 - (Ep1a*r0711)/4. - (Ep4a*r0715)/(4.*rt6) - r0704*(WLx/2. - (i*WLy)/2.) + r0605*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0805*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0705*WLz);
+dr0706_dt = -(gt*r0706) + (g1*r1110)/12. + (g2*r1312)/(2.*rt2) + (g2*r1413)/(2.*rt3) + (g2*r1514)/(4.*rt3) - i*(-(conj(Ep2a)*conj(r0609))/(4.*rt6) + (conj(Em2a)*conj(r0611))/(4.*rt6) + (conj(Ep3a)*conj(r0613))/8. + (conj(Em3a)*conj(r0615))/8. + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0706 - (Em2a*r0710)/(4.*rt6) - (Ep3a*r0712)/(4.*rt2) - (Em3a*r0714)/(8.*rt3) + r0606*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0707*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0806*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - [...]
+dr0707_dt = gt/8. - gt*r0707 + (g1*r0909)/12. + (g1*r1111)/12. + (g2*r1313)/4. + (g2*r1414)/3. + (g2*r1515)/4. - i*(-(conj(Ep2a)*conj(r0709))/(4.*rt6) + (conj(Em2a)*conj(r0711))/(4.*rt6) + (conj(Ep3a)*conj(r0713))/8. + (conj(Em3a)*conj(r0715))/8. + (Ep2a*r0709)/(4.*rt6) - (Em2a*r0711)/(4.*rt6) - (Ep3a*r0713)/8. - (Em3a*r0715)/8. + conj(r0706)*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - conj(r0807)*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0706*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0807*(-WLx/(2.*rt [...]
+dr0709_dt = (-(gt*r0709) - (gt + g1)*r0709)/2. - i*((conj(Ep3a)*conj(r0913))/8. + (conj(Em3a)*conj(r0915))/8. - (conj(Em1a)*r0701)/4. - (conj(Ep1a)*r0703)/(4.*rt6) + (conj(Ep2a)*r0707)/(4.*rt6) + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0709 - (conj(Ep2a)*r0909)/(4.*rt6) + (conj(Em2a)*r1109)/(4.*rt6) + r0609*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0710*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) + r0809*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - r0709*(-delta1 - v*Kvec1 - WLz/6.));
+dr0710_dt = (-(gt*r0710) - (gt + g1)*r0710)/2. - i*((conj(Ep2a)*conj(r0807))/(4.*rt6) - (conj(Ep2a)*conj(r1009))/(4.*rt6) + (conj(Ep3a)*conj(r1013))/8. + (conj(Em3a)*conj(r1015))/8. - (conj(Em1a)*r0702)/(4.*rt2) - (conj(Ep1a)*r0704)/(4.*rt2) - (conj(Em2a)*r0706)/(4.*rt6) + (delta1 + v*Kvec1)*r0710 + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0710 + (conj(Em2a)*r1110)/(4.*rt6) + r0610*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0711*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0709*(-WLx/(6.*rt2) + (i*WL [...]
+dr0711_dt = (-(gt*r0711) - (gt + g1)*r0711)/2. - i*(-(conj(Ep2a)*conj(r1109))/(4.*rt6) + (conj(Ep3a)*conj(r1113))/8. + (conj(Em3a)*conj(r1115))/8. - (conj(Em1a)*r0703)/(4.*rt6) - (conj(Ep1a)*r0705)/4. - (conj(Em2a)*r0707)/(4.*rt6) + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0711 + (conj(Em2a)*r1111)/(4.*rt6) + r0611*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0710*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) + r0811*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - r0711*(-delta1 - v*Kvec1 + WLz/6.));
+dr0712_dt = (-(gt*r0712) - (gt + g2)*r0712)/2. - i*(-(conj(Ep4a)*r0702)/(4.*rt6) - (conj(Ep3a)*r0706)/(4.*rt2) + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0712 - (conj(Ep2a)*r0912)/(4.*rt6) + (conj(Em2a)*r1112)/(4.*rt6) + (conj(Ep3a)*r1312)/8. + (conj(Em3a)*r1512)/8. - r0713*((2*WLx)/3. + (2*i*WLy)/3.) + r0612*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0812*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - r0712*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr0713_dt = (-(gt*r0713) - (gt + g2)*r0713)/2. - i*((conj(Em4a)*r0701)/(4.*rt6) - (conj(Ep4a)*r0703)/8. - (conj(Ep3a)*r0707)/8. + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0713 - (conj(Ep2a)*r0913)/(4.*rt6) + (conj(Em2a)*r1113)/(4.*rt6) + (conj(Ep3a)*r1313)/8. + (conj(Em3a)*r1513)/8. - r0712*((2*WLx)/3. - (2*i*WLy)/3.) - r0714*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r0613*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0813*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - r0713*(-delta [...]
+dr0714_dt = (-(gt*r0714) - (gt + g2)*r0714)/2. - i*(-(conj(Ep3a)*conj(r0807))/(8.*rt3) + (conj(Ep3a)*conj(r1413))/8. + (conj(Em4a)*r0702)/8. - (conj(Ep4a)*r0704)/8. - (conj(Em3a)*r0706)/(8.*rt3) + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0714 - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r0714 - (conj(Ep2a)*r0914)/(4.*rt6) + (conj(Em2a)*r1114)/(4.*rt6) + (conj(Em3a)*r1514)/8. - r0713*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0715*(sqrt(0.666666666666 [...]
+dr0715_dt = (-(gt*r0715) - (gt + g2)*r0715)/2. - i*((conj(Ep3a)*conj(r1513))/8. + (conj(Em4a)*r0703)/8. - (conj(Ep4a)*r0705)/(4.*rt6) - (conj(Em3a)*r0707)/8. + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0715 - (conj(Ep2a)*r0915)/(4.*rt6) + (conj(Em2a)*r1115)/(4.*rt6) + (conj(Em3a)*r1515)/8. - r0716*((2*WLx)/3. + (2*i*WLy)/3.) - r0714*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r0615*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0815*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - r0715*( [...]
+dr0716_dt = (-(gt*r0716) - (gt + g2)*r0716)/2. - i*(-(conj(Em3a)*conj(r0807))/(4.*rt2) + (conj(Ep3a)*conj(r1613))/8. + (conj(Em3a)*conj(r1615))/8. + (conj(Em4a)*r0704)/(4.*rt6) + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0716 - (conj(Ep2a)*r0916)/(4.*rt6) + (conj(Em2a)*r1116)/(4.*rt6) - r0715*((2*WLx)/3. - (2*i*WLy)/3.) + r0616*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0816*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - r0716*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.));
+dr0801_dt = -(gt*r0801) - i*(-(conj(Ep2a)*conj(r0110))/(4.*rt6) + (conj(Ep3a)*conj(r0114))/(8.*rt3) + (conj(Em3a)*conj(r0116))/(4.*rt2) - (Em1a*r0809)/4. + (Em4a*r0813)/(4.*rt6) - r0802*(WLx/2. + (i*WLy)/2.) + r0701*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0801*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.) - r0801*WLz);
+dr0802_dt = -(gt*r0802) - i*(-(conj(Ep2a)*conj(r0210))/(4.*rt6) + (conj(Ep3a)*conj(r0214))/(8.*rt3) + (conj(Em3a)*conj(r0216))/(4.*rt2) - (Em1a*r0810)/(4.*rt2) - (Ep4a*r0812)/(4.*rt6) + (Em4a*r0814)/8. - r0801*(WLx/2. - (i*WLy)/2.) - r0803*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) + r0702*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0802*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.) - (r0802*WLz)/2.);
+dr0803_dt = -(gt*r0803) - i*(-(conj(Ep2a)*conj(r0310))/(4.*rt6) + (conj(Ep3a)*conj(r0314))/(8.*rt3) + (conj(Em3a)*conj(r0316))/(4.*rt2) - (Ep1a*r0809)/(4.*rt6) - (Em1a*r0811)/(4.*rt6) - (Ep4a*r0813)/8. + (Em4a*r0815)/8. - r0802*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - r0804*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) + r0703*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0803*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.));
+dr0804_dt = -(gt*r0804) - i*(-(conj(Ep2a)*conj(r0410))/(4.*rt6) + (conj(Ep3a)*conj(r0414))/(8.*rt3) + (conj(Em3a)*conj(r0416))/(4.*rt2) - (Ep1a*r0810)/(4.*rt2) - (Ep4a*r0814)/8. + (Em4a*r0816)/(4.*rt6) - r0805*(WLx/2. + (i*WLy)/2.) - r0803*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0704*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0804*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.) + (r0804*WLz)/2.);
+dr0805_dt = -(gt*r0805) - i*(-(conj(Ep2a)*conj(r0510))/(4.*rt6) + (conj(Ep3a)*conj(r0514))/(8.*rt3) + (conj(Em3a)*conj(r0516))/(4.*rt2) - (Ep1a*r0811)/4. - (Ep4a*r0815)/(4.*rt6) - r0804*(WLx/2. - (i*WLy)/2.) + r0705*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0805*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.) + r0805*WLz);
+dr0806_dt = -(gt*r0806) - (g1*r1109)/12. + (g2*r1412)/(2.*rt6) + (g2*r1513)/4. + (g2*r1614)/(2.*rt6) - i*(-(conj(Ep2a)*conj(r0610))/(4.*rt6) + (conj(Ep3a)*conj(r0614))/(8.*rt3) + (conj(Em3a)*conj(r0616))/(4.*rt2) - (Em2a*r0810)/(4.*rt6) - (Ep3a*r0812)/(4.*rt2) - (Em3a*r0814)/(8.*rt3) + r0706*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0807*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0806*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.) + r0806*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.));
+dr0807_dt = -(gt*r0807) + (g1*r1009)/12. + (g2*r1413)/(4.*rt3) + (g2*r1514)/(2.*rt3) + (g2*r1615)/(2.*rt2) - i*(-(conj(Ep2a)*conj(r0710))/(4.*rt6) + (conj(Ep3a)*conj(r0714))/(8.*rt3) + (conj(Em3a)*conj(r0716))/(4.*rt2) - (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0807 + (Ep2a*r0809)/(4.*rt6) - (Em2a*r0811)/(4.*rt6) - (Ep3a*r0813)/8. - (Em3a*r0815)/8. + r0707*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0808*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0806*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0807*(-del [...]
+dr0808_dt = gt/8. - gt*r0808 + (g1*r1010)/12. + (g1*r1111)/12. + (g2*r1414)/12. + (g2*r1515)/4. + (g2*r1616)/2. - i*(-(conj(Ep2a)*conj(r0810))/(4.*rt6) + (conj(Ep3a)*conj(r0814))/(8.*rt3) + (conj(Em3a)*conj(r0816))/(4.*rt2) + (Ep2a*r0810)/(4.*rt6) - (Ep3a*r0814)/(8.*rt3) - (Em3a*r0816)/(4.*rt2) + conj(r0807)*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0807*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)));
+dr0809_dt = (-(gt*r0809) - (gt + g1)*r0809)/2. - i*((conj(Ep3a)*conj(r0914))/(8.*rt3) + (conj(Em3a)*conj(r0916))/(4.*rt2) - (conj(Em1a)*r0801)/4. - (conj(Ep1a)*r0803)/(4.*rt6) + (conj(Ep2a)*r0807)/(4.*rt6) - (conj(Ep2a)*r1009)/(4.*rt6) + r0709*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0810*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0809*(-delta1 - v*Kvec1 - WLz/6.) + r0809*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.));
+dr0810_dt = (-(gt*r0810) - (gt + g1)*r0810)/2. - i*((conj(Ep3a)*conj(r1014))/(8.*rt3) + (conj(Em3a)*conj(r1016))/(4.*rt2) - (conj(Em1a)*r0802)/(4.*rt2) - (conj(Ep1a)*r0804)/(4.*rt2) - (conj(Em2a)*r0806)/(4.*rt6) + (conj(Ep2a)*r0808)/(4.*rt6) + (delta1 + v*Kvec1)*r0810 - (conj(Ep2a)*r1010)/(4.*rt6) + r0710*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0811*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0809*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) + r0810*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.));
+dr0811_dt = (-(gt*r0811) - (gt + g1)*r0811)/2. - i*(-(conj(Ep2a)*conj(r1110))/(4.*rt6) + (conj(Ep3a)*conj(r1114))/(8.*rt3) + (conj(Em3a)*conj(r1116))/(4.*rt2) - (conj(Em1a)*r0803)/(4.*rt6) - (conj(Ep1a)*r0805)/4. - (conj(Em2a)*r0807)/(4.*rt6) + r0711*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0810*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r0811*(-delta1 - v*Kvec1 + WLz/6.) + r0811*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.));
+dr0812_dt = (-(gt*r0812) - (gt + g2)*r0812)/2. - i*(-(conj(Ep4a)*r0802)/(4.*rt6) - (conj(Ep3a)*r0806)/(4.*rt2) - (conj(Ep2a)*r1012)/(4.*rt6) + (conj(Ep3a)*r1412)/(8.*rt3) + (conj(Em3a)*r1612)/(4.*rt2) - r0813*((2*WLx)/3. + (2*i*WLy)/3.) + r0712*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0812*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.) - r0812*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr0813_dt = (-(gt*r0813) - (gt + g2)*r0813)/2. - i*((conj(Em4a)*r0801)/(4.*rt6) - (conj(Ep4a)*r0803)/8. - (conj(Ep3a)*r0807)/8. - (conj(Ep2a)*r1013)/(4.*rt6) + (conj(Ep3a)*r1413)/(8.*rt3) + (conj(Em3a)*r1613)/(4.*rt2) - r0812*((2*WLx)/3. - (2*i*WLy)/3.) - r0814*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r0713*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0813*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.) - r0813*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 +  [...]
+dr0814_dt = (-(gt*r0814) - (gt + g2)*r0814)/2. - i*((conj(Em4a)*r0802)/8. - (conj(Ep4a)*r0804)/8. - (conj(Em3a)*r0806)/(8.*rt3) - (conj(Ep3a)*r0808)/(8.*rt3) - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r0814 - (conj(Ep2a)*r1014)/(4.*rt6) + (conj(Ep3a)*r1414)/(8.*rt3) + (conj(Em3a)*r1614)/(4.*rt2) - r0813*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0815*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r0714*(-WLx/(2.*rt2) - (i*WLy)/( [...]
+dr0815_dt = (-(gt*r0815) - (gt + g2)*r0815)/2. - i*((conj(Ep3a)*conj(r1514))/(8.*rt3) + (conj(Em4a)*r0803)/8. - (conj(Ep4a)*r0805)/(4.*rt6) - (conj(Em3a)*r0807)/8. - (conj(Ep2a)*r1015)/(4.*rt6) + (conj(Em3a)*r1615)/(4.*rt2) - r0816*((2*WLx)/3. + (2*i*WLy)/3.) - r0814*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r0715*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0815*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (2*WLz)/3.) + r0815*(-delta1 + delta2 - v*Kvec1 +  [...]
+dr0816_dt = (-(gt*r0816) - (gt + g2)*r0816)/2. - i*((conj(Ep3a)*conj(r1614))/(8.*rt3) + (conj(Em4a)*r0804)/(4.*rt6) - (conj(Em3a)*r0808)/(4.*rt2) - (conj(Ep2a)*r1016)/(4.*rt6) + (conj(Em3a)*r1616)/(4.*rt2) - r0815*((2*WLx)/3. - (2*i*WLy)/3.) + r0716*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0816*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) + r0816*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.));
+dr0909_dt = -((gt + g1)*r0909) - i*(-(conj(Em1a)*conj(r0109))/4. - (conj(Ep1a)*conj(r0309))/(4.*rt6) + (conj(Ep2a)*conj(r0709))/(4.*rt6) + (Em1a*r0109)/4. + (Ep1a*r0309)/(4.*rt6) - (Ep2a*r0709)/(4.*rt6) - conj(r1009)*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) + r1009*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)));
+dr0912_dt = (-((gt + g1)*r0912) - (gt + g2)*r0912)/2. - i*(-(conj(Ep4a)*conj(r0209))/(4.*rt6) - (conj(Ep3a)*conj(r0609))/(4.*rt2) + (Em1a*r0112)/4. + (Ep1a*r0312)/(4.*rt6) - (Ep2a*r0712)/(4.*rt6) - r0913*((2*WLx)/3. + (2*i*WLy)/3.) + r1012*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) + r0912*(-delta1 - v*Kvec1 - WLz/6.) - r0912*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr0913_dt = (-((gt + g1)*r0913) - (gt + g2)*r0913)/2. - i*((conj(Em4a)*conj(r0109))/(4.*rt6) - (conj(Ep4a)*conj(r0309))/8. - (conj(Ep3a)*conj(r0709))/8. + (Em1a*r0113)/4. + (Ep1a*r0313)/(4.*rt6) - (Ep2a*r0713)/(4.*rt6) - r0912*((2*WLx)/3. - (2*i*WLy)/3.) - r0914*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r1013*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) + r0913*(-delta1 - v*Kvec1 - WLz/6.) - r0913*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (2*WLz)/3.));
+dr0914_dt = (-((gt + g1)*r0914) - (gt + g2)*r0914)/2. - i*((conj(Em4a)*conj(r0209))/8. - (conj(Ep4a)*conj(r0409))/8. - (conj(Em3a)*conj(r0609))/(8.*rt3) - (conj(Ep3a)*conj(r0809))/(8.*rt3) + (Em1a*r0114)/4. + (Ep1a*r0314)/(4.*rt6) - (Ep2a*r0714)/(4.*rt6) - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r0914 - r0913*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0915*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r1014*(-WLx/(6.*rt2) + (i [...]
+dr0915_dt = (-((gt + g1)*r0915) - (gt + g2)*r0915)/2. - i*((conj(Em4a)*conj(r0309))/8. - (conj(Ep4a)*conj(r0509))/(4.*rt6) - (conj(Em3a)*conj(r0709))/8. + (Em1a*r0115)/4. + (Ep1a*r0315)/(4.*rt6) - (Ep2a*r0715)/(4.*rt6) - r0916*((2*WLx)/3. + (2*i*WLy)/3.) - r0914*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r1015*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r0915*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (2*WLz)/3.) + r0915*(-delta1 - v*Kvec1 - WLz/6.));
+dr0916_dt = (-((gt + g1)*r0916) - (gt + g2)*r0916)/2. - i*((conj(Em4a)*conj(r0409))/(4.*rt6) - (conj(Em3a)*conj(r0809))/(4.*rt2) + (Em1a*r0116)/4. + (Ep1a*r0316)/(4.*rt6) - (Ep2a*r0716)/(4.*rt6) - r0915*((2*WLx)/3. - (2*i*WLy)/3.) + r1016*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r0916*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) + r0916*(-delta1 - v*Kvec1 - WLz/6.));
+dr1009_dt = -((gt + g1)*r1009) - i*(-(conj(Em1a)*conj(r0110))/4. - (conj(Ep1a)*conj(r0310))/(4.*rt6) + (conj(Ep2a)*conj(r0710))/(4.*rt6) + (Em1a*r0209)/(4.*rt2) + (Ep1a*r0409)/(4.*rt2) + (Em2a*r0609)/(4.*rt6) - (Ep2a*r0809)/(4.*rt6) - (delta1 + v*Kvec1)*r1009 + r0909*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r1010*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) + r1109*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r1009*(-delta1 - v*Kvec1 - WLz/6.));
+dr1010_dt = -((gt + g1)*r1010) - i*(-(conj(Em1a)*conj(r0210))/(4.*rt2) - (conj(Ep1a)*conj(r0410))/(4.*rt2) - (conj(Em2a)*conj(r0610))/(4.*rt6) + (conj(Ep2a)*conj(r0810))/(4.*rt6) + (Em1a*r0210)/(4.*rt2) + (Ep1a*r0410)/(4.*rt2) + (Em2a*r0610)/(4.*rt6) - (Ep2a*r0810)/(4.*rt6) + conj(r1009)*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - conj(r1110)*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r1009*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) + r1110*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)));
+dr1012_dt = (-((gt + g1)*r1012) - (gt + g2)*r1012)/2. - i*(-(conj(Ep4a)*conj(r0210))/(4.*rt6) - (conj(Ep3a)*conj(r0610))/(4.*rt2) + (Em1a*r0212)/(4.*rt2) + (Ep1a*r0412)/(4.*rt2) + (Em2a*r0612)/(4.*rt6) - (Ep2a*r0812)/(4.*rt6) - (delta1 + v*Kvec1)*r1012 - r1013*((2*WLx)/3. + (2*i*WLy)/3.) + r0912*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) + r1112*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r1012*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr1013_dt = (-((gt + g1)*r1013) - (gt + g2)*r1013)/2. - i*((conj(Em4a)*conj(r0110))/(4.*rt6) - (conj(Ep4a)*conj(r0310))/8. - (conj(Ep3a)*conj(r0710))/8. + (Em1a*r0213)/(4.*rt2) + (Ep1a*r0413)/(4.*rt2) + (Em2a*r0613)/(4.*rt6) - (Ep2a*r0813)/(4.*rt6) - (delta1 + v*Kvec1)*r1013 - r1012*((2*WLx)/3. - (2*i*WLy)/3.) - r1014*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r0913*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) + r1113*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r1013*(-delta1 + del [...]
+dr1014_dt = (-((gt + g1)*r1014) - (gt + g2)*r1014)/2. - i*((conj(Em4a)*conj(r0210))/8. - (conj(Ep4a)*conj(r0410))/8. - (conj(Em3a)*conj(r0610))/(8.*rt3) - (conj(Ep3a)*conj(r0810))/(8.*rt3) + (Em1a*r0214)/(4.*rt2) + (Ep1a*r0414)/(4.*rt2) + (Em2a*r0614)/(4.*rt6) - (Ep2a*r0814)/(4.*rt6) - (delta1 + v*Kvec1)*r1014 - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r1014 - r1013*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r1015*(sqrt(0.6666666666666666)*WLx + sq [...]
+dr1015_dt = (-((gt + g1)*r1015) - (gt + g2)*r1015)/2. - i*((conj(Em4a)*conj(r0310))/8. - (conj(Ep4a)*conj(r0510))/(4.*rt6) - (conj(Em3a)*conj(r0710))/8. + (Em1a*r0215)/(4.*rt2) + (Ep1a*r0415)/(4.*rt2) + (Em2a*r0615)/(4.*rt6) - (Ep2a*r0815)/(4.*rt6) - (delta1 + v*Kvec1)*r1015 - r1016*((2*WLx)/3. + (2*i*WLy)/3.) - r1014*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r0915*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) + r1115*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r1015*(-delta1 + del [...]
+dr1016_dt = (-((gt + g1)*r1016) - (gt + g2)*r1016)/2. - i*((conj(Em4a)*conj(r0410))/(4.*rt6) - (conj(Em3a)*conj(r0810))/(4.*rt2) + (Em1a*r0216)/(4.*rt2) + (Ep1a*r0416)/(4.*rt2) + (Em2a*r0616)/(4.*rt6) - (Ep2a*r0816)/(4.*rt6) - (delta1 + v*Kvec1)*r1016 - r1015*((2*WLx)/3. - (2*i*WLy)/3.) + r0916*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) + r1116*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r1016*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.));
+dr1109_dt = -((gt + g1)*r1109) - i*(-(conj(Em1a)*conj(r0111))/4. - (conj(Ep1a)*conj(r0311))/(4.*rt6) + (conj(Ep2a)*conj(r0711))/(4.*rt6) + (Em1a*r0309)/(4.*rt6) + (Ep1a*r0509)/4. + (Em2a*r0709)/(4.*rt6) + r1009*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r1110*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r1109*(-delta1 - v*Kvec1 - WLz/6.) + r1109*(-delta1 - v*Kvec1 + WLz/6.));
+dr1110_dt = -((gt + g1)*r1110) - i*(-(conj(Em1a)*conj(r0211))/(4.*rt2) - (conj(Ep1a)*conj(r0411))/(4.*rt2) - (conj(Em2a)*conj(r0611))/(4.*rt6) + (conj(Ep2a)*conj(r0811))/(4.*rt6) + (Em1a*r0310)/(4.*rt6) + (Ep1a*r0510)/4. + (Em2a*r0710)/(4.*rt6) + (delta1 + v*Kvec1)*r1110 + r1010*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r1111*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r1109*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) + r1110*(-delta1 - v*Kvec1 + WLz/6.));
+dr1111_dt = -((gt + g1)*r1111) - i*(-(conj(Em1a)*conj(r0311))/(4.*rt6) - (conj(Ep1a)*conj(r0511))/4. - (conj(Em2a)*conj(r0711))/(4.*rt6) + (Em1a*r0311)/(4.*rt6) + (Ep1a*r0511)/4. + (Em2a*r0711)/(4.*rt6) + conj(r1110)*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r1110*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)));
+dr1112_dt = (-((gt + g1)*r1112) - (gt + g2)*r1112)/2. - i*(-(conj(Ep4a)*conj(r0211))/(4.*rt6) - (conj(Ep3a)*conj(r0611))/(4.*rt2) + (Em1a*r0312)/(4.*rt6) + (Ep1a*r0512)/4. + (Em2a*r0712)/(4.*rt6) - r1113*((2*WLx)/3. + (2*i*WLy)/3.) + r1012*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) + r1112*(-delta1 - v*Kvec1 + WLz/6.) - r1112*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr1113_dt = (-((gt + g1)*r1113) - (gt + g2)*r1113)/2. - i*((conj(Em4a)*conj(r0111))/(4.*rt6) - (conj(Ep4a)*conj(r0311))/8. - (conj(Ep3a)*conj(r0711))/8. + (Em1a*r0313)/(4.*rt6) + (Ep1a*r0513)/4. + (Em2a*r0713)/(4.*rt6) - r1112*((2*WLx)/3. - (2*i*WLy)/3.) - r1114*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r1013*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) + r1113*(-delta1 - v*Kvec1 + WLz/6.) - r1113*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (2*WLz)/3.));
+dr1114_dt = (-((gt + g1)*r1114) - (gt + g2)*r1114)/2. - i*((conj(Em4a)*conj(r0211))/8. - (conj(Ep4a)*conj(r0411))/8. - (conj(Em3a)*conj(r0611))/(8.*rt3) - (conj(Ep3a)*conj(r0811))/(8.*rt3) + (Em1a*r0314)/(4.*rt6) + (Ep1a*r0514)/4. + (Em2a*r0714)/(4.*rt6) - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r1114 - r1113*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r1115*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r1014*(-WLx/(6.*rt2) - (i [...]
+dr1115_dt = (-((gt + g1)*r1115) - (gt + g2)*r1115)/2. - i*((conj(Em4a)*conj(r0311))/8. - (conj(Ep4a)*conj(r0511))/(4.*rt6) - (conj(Em3a)*conj(r0711))/8. + (Em1a*r0315)/(4.*rt6) + (Ep1a*r0515)/4. + (Em2a*r0715)/(4.*rt6) - r1116*((2*WLx)/3. + (2*i*WLy)/3.) - r1114*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r1015*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r1115*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (2*WLz)/3.) + r1115*(-delta1 - v*Kvec1 + WLz/6.));
+dr1116_dt = (-((gt + g1)*r1116) - (gt + g2)*r1116)/2. - i*((conj(Em4a)*conj(r0411))/(4.*rt6) - (conj(Em3a)*conj(r0811))/(4.*rt2) + (Em1a*r0316)/(4.*rt6) + (Ep1a*r0516)/4. + (Em2a*r0716)/(4.*rt6) - r1115*((2*WLx)/3. - (2*i*WLy)/3.) + r1016*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r1116*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) + r1116*(-delta1 - v*Kvec1 + WLz/6.));
+dr1212_dt = -((gt + g2)*r1212) - i*(-(conj(Ep4a)*conj(r0212))/(4.*rt6) - (conj(Ep3a)*conj(r0612))/(4.*rt2) + (Ep4a*r0212)/(4.*rt6) + (Ep3a*r0612)/(4.*rt2) + r1312*((2*WLx)/3. - (2*i*WLy)/3.) - conj(r1312)*((2*WLx)/3. + (2*i*WLy)/3.));
+dr1312_dt = -((gt + g2)*r1312) - i*(-(conj(Ep4a)*conj(r0213))/(4.*rt6) - (conj(Ep3a)*conj(r0613))/(4.*rt2) - (Em4a*r0112)/(4.*rt6) + (Ep4a*r0312)/8. + (Ep3a*r0712)/8. + r1212*((2*WLx)/3. + (2*i*WLy)/3.) - r1313*((2*WLx)/3. + (2*i*WLy)/3.) + r1412*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r1312*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (2*WLz)/3.) - r1312*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr1313_dt = -((gt + g2)*r1313) - i*((conj(Em4a)*conj(r0113))/(4.*rt6) - (conj(Ep4a)*conj(r0313))/8. - (conj(Ep3a)*conj(r0713))/8. - (Em4a*r0113)/(4.*rt6) + (Ep4a*r0313)/8. + (Ep3a*r0713)/8. - r1312*((2*WLx)/3. - (2*i*WLy)/3.) + conj(r1312)*((2*WLx)/3. + (2*i*WLy)/3.) + r1413*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - conj(r1413)*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy));
+dr1412_dt = -((gt + g2)*r1412) - i*(-(conj(Ep4a)*conj(r0214))/(4.*rt6) - (conj(Ep3a)*conj(r0614))/(4.*rt2) - (Em4a*r0212)/8. + (Ep4a*r0412)/8. + (Em3a*r0612)/(8.*rt3) + (Ep3a*r0812)/(8.*rt3) + (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r1412 - r1413*((2*WLx)/3. + (2*i*WLy)/3.) + r1512*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r1312*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) - r1412*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2  [...]
+dr1413_dt = -((gt + g2)*r1413) - i*((conj(Em4a)*conj(r0114))/(4.*rt6) - (conj(Ep4a)*conj(r0314))/8. - (conj(Ep3a)*conj(r0714))/8. - (Em4a*r0213)/8. + (Ep4a*r0413)/8. + (Em3a*r0613)/(8.*rt3) + (Ep3a*r0813)/(8.*rt3) + (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r1413 - r1412*((2*WLx)/3. - (2*i*WLy)/3.) + r1513*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r1313*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) - r1414*(sqrt(0.6666666666666666 [...]
+dr1414_dt = -((gt + g2)*r1414) - i*((conj(Em4a)*conj(r0214))/8. - (conj(Ep4a)*conj(r0414))/8. - (conj(Em3a)*conj(r0614))/(8.*rt3) - (conj(Ep3a)*conj(r0814))/(8.*rt3) - (Em4a*r0214)/8. + (Ep4a*r0414)/8. + (Em3a*r0614)/(8.*rt3) + (Ep3a*r0814)/(8.*rt3) - r1413*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r1514*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + conj(r1413)*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) - conj(r1514)*(sqrt( [...]
+dr1512_dt = -((gt + g2)*r1512) - i*(-(conj(Ep4a)*conj(r0215))/(4.*rt6) - (conj(Ep3a)*conj(r0615))/(4.*rt2) - (Em4a*r0312)/8. + (Ep4a*r0512)/(4.*rt6) + (Em3a*r0712)/8. + r1612*((2*WLx)/3. - (2*i*WLy)/3.) - r1513*((2*WLx)/3. + (2*i*WLy)/3.) + r1412*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r1512*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (2*WLz)/3.) - r1512*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr1513_dt = -((gt + g2)*r1513) - i*((conj(Em4a)*conj(r0115))/(4.*rt6) - (conj(Ep4a)*conj(r0315))/8. - (conj(Ep3a)*conj(r0715))/8. - (Em4a*r0313)/8. + (Ep4a*r0513)/(4.*rt6) + (Em3a*r0713)/8. - r1512*((2*WLx)/3. - (2*i*WLy)/3.) + r1613*((2*WLx)/3. - (2*i*WLy)/3.) + r1413*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) - r1514*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r1513*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (2*WLz)/3.) - r1513 [...]
+dr1514_dt = -((gt + g2)*r1514) - i*((conj(Em4a)*conj(r0215))/8. - (conj(Ep4a)*conj(r0415))/8. - (conj(Em3a)*conj(r0615))/(8.*rt3) - (conj(Ep3a)*conj(r0815))/(8.*rt3) - (Em4a*r0314)/8. + (Ep4a*r0514)/(4.*rt6) + (Em3a*r0714)/8. - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r1514 + r1614*((2*WLx)/3. - (2*i*WLy)/3.) - r1513*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r1414*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) - r1515*(sqrt(0.6666 [...]
+dr1515_dt = -((gt + g2)*r1515) - i*((conj(Em4a)*conj(r0315))/8. - (conj(Ep4a)*conj(r0515))/(4.*rt6) - (conj(Em3a)*conj(r0715))/8. - (Em4a*r0315)/8. + (Ep4a*r0515)/(4.*rt6) + (Em3a*r0715)/8. + r1615*((2*WLx)/3. - (2*i*WLy)/3.) - conj(r1615)*((2*WLx)/3. + (2*i*WLy)/3.) - r1514*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + conj(r1514)*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy));
+dr1612_dt = -((gt + g2)*r1612) - i*(-(conj(Ep4a)*conj(r0216))/(4.*rt6) - (conj(Ep3a)*conj(r0616))/(4.*rt2) - (Em4a*r0412)/(4.*rt6) + (Em3a*r0812)/(4.*rt2) + r1512*((2*WLx)/3. + (2*i*WLy)/3.) - r1613*((2*WLx)/3. + (2*i*WLy)/3.) + r1612*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) - r1612*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr1613_dt = -((gt + g2)*r1613) - i*((conj(Em4a)*conj(r0116))/(4.*rt6) - (conj(Ep4a)*conj(r0316))/8. - (conj(Ep3a)*conj(r0716))/8. - (Em4a*r0413)/(4.*rt6) + (Em3a*r0813)/(4.*rt2) - r1612*((2*WLx)/3. - (2*i*WLy)/3.) + r1513*((2*WLx)/3. + (2*i*WLy)/3.) - r1614*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r1613*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) - r1613*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (2*WLz)/3.));
+dr1614_dt = -((gt + g2)*r1614) - i*((conj(Em4a)*conj(r0216))/8. - (conj(Ep4a)*conj(r0416))/8. - (conj(Em3a)*conj(r0616))/(8.*rt3) - (conj(Ep3a)*conj(r0816))/(8.*rt3) - (Em4a*r0414)/(4.*rt6) + (Em3a*r0814)/(4.*rt2) - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r1614 + r1514*((2*WLx)/3. + (2*i*WLy)/3.) - r1613*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r1615*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r1614*(-delta1 + delta2 - delt [...]
+dr1615_dt = -((gt + g2)*r1615) - i*((conj(Em4a)*conj(r0316))/8. - (conj(Ep4a)*conj(r0516))/(4.*rt6) - (conj(Em3a)*conj(r0716))/8. - (Em4a*r0415)/(4.*rt6) + (Em3a*r0815)/(4.*rt2) + r1515*((2*WLx)/3. + (2*i*WLy)/3.) - r1616*((2*WLx)/3. + (2*i*WLy)/3.) - r1614*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r1615*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) - r1615*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (2*WLz)/3.));
+dr1616_dt = -((gt + g2)*r1616) - i*((conj(Em4a)*conj(r0416))/(4.*rt6) - (conj(Em3a)*conj(r0816))/(4.*rt2) - (Em4a*r0416)/(4.*rt6) + (Em3a*r0816)/(4.*rt2) - r1615*((2*WLx)/3. - (2*i*WLy)/3.) + conj(r1615)*((2*WLx)/3. + (2*i*WLy)/3.));
+//---------------- RbEquations.txt ends  ------------------
+					]]>
+        </operator>
+				<!--
+							 According to xmds2 docs operator kind="ip" should be faster
+							 but our codes runs about 5% to 10% slower with it.
+							 Maybe because we very close to the stiff condition so I use "ex" kind
+							 <operator kind="ip" constant="yes">
+					 -->
+				<operator kind="ex" constant="yes" type="imaginary">
+					<operator_names>Lt</operator_names>
+					<![CDATA[
+					Lt = -i/c*kt;
+					]]>
+				</operator>
+        <integration_vectors>E_field</integration_vectors>
+				<dependencies>density_matrix</dependencies>
+				<![CDATA[
+				//read from Mathematica generated RbPropEquations.txt
+//---------------- RbPropEquations.txt starts ------------------
+dEp1_dz = -((i*Ndens*(rt2*conj(r0309) + rt6*(conj(r0410) + rt2*conj(r0511)))*eta1)/(rt2*rt6)) - Lt[Ep1];
+dEm1_dz = -((i*Ndens*(rt2*rt6*conj(r0109) + rt6*conj(r0210) + rt2*conj(r0311))*eta1)/(rt2*rt6)) - Lt[Em1];
+dEp2_dz = (i*Ndens*(conj(r0709) + conj(r0810))*eta1)/rt6 - Lt[Ep2];
+dEm2_dz = -((i*Ndens*(conj(r0610) + conj(r0711))*eta1)/rt6) - Lt[Em2];
+dEp3_dz = -((i*Ndens*(rt2*rt3*conj(r0612) + rt3*conj(r0713) + conj(r0814))*eta2)/rt3) - Lt[Ep3];
+dEm3_dz = -((i*Ndens*(conj(r0614) + rt3*(conj(r0715) + rt2*conj(r0816)))*eta2)/rt3) - Lt[Em3];
+dEp4_dz = -((i*Ndens*(rt2*conj(r0212) + rt3*conj(r0313) + rt3*conj(r0414) + rt2*conj(r0515))*eta2)/rt3) - Lt[Ep4];
+dEm4_dz = (i*Ndens*(rt2*conj(r0113) + rt3*conj(r0214) + rt3*conj(r0315) + rt2*conj(r0416))*eta2)/rt3 - Lt[Em4];
+//---------------- RbPropEquations.txt ends  ------------------
+				]]>
+			</operators>
+		</integrate>
+	</sequence>
+
+
+
+	<!-- The output to generate -->
+	<output format="binary" filename="realistic_Rb_and_fields.xsil">
+		<group>
+      <sampling basis="t(1000) " initial_sample="yes">
+				<dependencies>E_field_avgd</dependencies>
+				<moments>Ip1_out Im1_out Ip2_out Im2_out Ip3_out Im3_out Ip4_out Im4_out</moments>
+				<![CDATA[
+				Ip1_out = mod2(Ep1a);
+				Im1_out = mod2(Em1a);
+				Ip2_out = mod2(Ep2a);
+				Im2_out = mod2(Em2a);
+				Ip3_out = mod2(Ep3a);
+				Im3_out = mod2(Em3a);
+				Ip4_out = mod2(Ep4a);
+				Im4_out = mod2(Em4a);
+				]]>
+			</sampling>
+		</group>
+	</output>
+
+</simulation>
+	
+<!-- 
+vim: ts=2 sw=2 foldmethod=indent: 
+-->
diff --git a/testsuite/features/realistic_Rb_and_fields_expected.xsil b/testsuite/features/realistic_Rb_and_fields_expected.xsil
new file mode 100644
index 0000000..c115312
--- /dev/null
+++ b/testsuite/features/realistic_Rb_and_fields_expected.xsil
@@ -0,0 +1,680 @@
+<?xml version="1.0"?>
+<simulation xmds-version="2">
+        <testing>
+                <arguments> --Lcell=5e-4</arguments>
+                <xsil_file name="realistic_Rb_and_fields.xsil" expected="realistic_Rb_and_fields_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5">
+                        <moment_group number="0" absolute_tolerance="1e-7" relative_tolerance="1e-6" />
+                </xsil_file>
+        </testing>
+
+        <name>realistic_Rb_and_fields</name>
+
+        <author>Eugeniy Mikhailov</author>
+        <description>
+                License GPL.
+
+                Solving simplified Rb atom model
+                with fields propagation along spatial axis Z
+                with Doppler broadening.
+
+
+                We assume four-wave mixing condition when w3-w4=w2-w1 i.e. fields E3 and E4 drive the same
+                resonance as fields E2 and E1.
+
+
+                *              --------------- | F=1, 2P_3/2 >
+                *                \        \    
+                *                 \ E3_r   \    -------- | F=2, 2P_+1/2 >
+                *                  \   E4_r \   /    \
+                *                   \        \ / E2_l \ 
+                *                    \        /        \ E1_l
+                *   | F=2, 2S_1/2 > --------------      \
+                *                               \        \
+                *                                \        \
+                *                               ------------- | F=1, 2S_1/2 >
+                *            
+
+
+                We are solving 
+                        dE/dz+(1/c)*dE/dt=i*eta*rho_ij,  where j level is higher than i.
+                        Note that E is actually a Rabi frequency of electromagnetic field not the EM field
+                in xmds terms it looks like
+                        dE_dz = i*eta*rhoij - 1/c*L[E], here we moved t dependence to Fourier space
+
+                VERY IMPORTANT: all Rabi frequency should be given in [1/s], if you want to
+                normalize it to something else look drho/dt equation.
+                No need to renormalizes eta as long as its express through
+                the upper level decay rate in the same units as Rabi frequency.
+        </description>
+
+        <features>
+                <globals>
+                        <![CDATA[
+                                // Some numerical constants
+                                const double pi = M_PI; 
+
+                                // atom related constants
+                                //read from Mathematica generated Constants.txt
+//---------------- Constants.txt starts ------------------
+const double ha0 = 2.1471788680034824e10;
+const double ha1 = 2.558764384495815e9;
+const double g1 = 3.612847284945266e7;
+const double ha2 = 5.323020344462938e8;
+const double hb2 = 7.85178251911697e7;
+const double g2 = 3.8117309832741246e7;
+const double lambda1 = 7.949788511562656e-7;
+const double lambda2 = 7.802412096860509e-7;
+const double eta1 = 5.450949336831401e-6;
+const double eta2 = 5.5397657647874e-6;
+const double rt6 = 2.449489742783178;
+const double rt3 = 1.7320508075688772;
+const double rt2 = 1.4142135623730951;
+//---------------- Constants.txt ends   ------------------
+
+                                const double c=3.e8;
+                                const double k_boltzmann= 1.3806505e-23; // Boltzmann knostant in [J/K]
+                                const double lambda=794.7e-9; //wavelength in m
+                                // Fields k-vector
+                                const double Kvec = 2*M_PI/lambda;  
+                                // Simplified k-vectors
+                                const double Kvec1 = Kvec, Kvec2=Kvec, Kvec3=Kvec;
+
+                                //  ---------  Atom and cell properties -------------------------
+                                // range of Maxwell distribution atomic velocities
+                                const double mass = (86.909180527 * 1.660538921e-27); // atom mass in [kg] 
+                                // above mass expression is written as (expression is isotopic_mass * atomic_mass_unit)
+
+                                // Average sqrt(v^2) in Maxwell distribution for one dimension
+                                // Maxwell related parameters will be calculated in <arguments> section
+                                double v_thermal_averaged=0;
+                                // Maxwell distribution velocities range to take in account in [m/s]
+                                double V_maxwell_min = 0, V_maxwell_max = 0;
+
+                                // repopulation rate (atoms flying in/out the laser beam)  in [1/s]
+                                const double gt=0.01 *(2*M_PI*1e6);
+
+                                // inner use variables 
+                                double probability_v; // will be used as p(v) in Maxwell distribution
+
+                        ]]>
+                </globals>
+                <validation kind="run-time"/> <!--allows to put ranges as variables-->
+                <benchmark />
+    <arguments>
+                        <!-- Rabi frequency divided by 2 in [1/s] -->
+                        <!--
+                                Had to be very verbal with fields names, since otherwise short options name
+                                algorithm runs out of choices
+                        -->
+      <argument name="Ep1o_field" type="real" default_value="2*1.5*(2*M_PI*1e6)" />
+      <argument name="Em1o_field" type="real" default_value="2*1.5*(2*M_PI*1e6)" />
+      <argument name="Ep2o_field" type="real" default_value="0.05*(2*M_PI*1e6)" />
+      <argument name="Em2o_field" type="real" default_value="0.05*(2*M_PI*1e6)" />
+      <argument name="Ep3o_field" type="real" default_value="2*3.0*(2*M_PI*1e6)" />
+      <argument name="Em3o_field" type="real" default_value="2*3.0*(2*M_PI*1e6)" />
+      <argument name="Ep4o_field" type="real" default_value=".01*(2*M_PI*1e6)" />
+      <argument name="Em4o_field" type="real" default_value=".01*(2*M_PI*1e6)" />
+                        <!-- Fields detuning in [1/s] -->
+      <argument name="delta1"  type="real" default_value="0.0" />
+      <argument name="delta2"  type="real" default_value="0.0" />
+      <argument name="delta3"  type="real" default_value="0.0" />
+                        <!--Pulse duration/width [s] -->
+                        <argument name="Pwidth"  type="real" default_value="0.1e-6" />
+                        <!--  Atom and cell properties -->
+                        <!--Cell length [m] -->
+                        <argument name="Lcell"  type="real" default_value="1.5e-2" />
+                        <!--Density of atoms [1/m^3] -->
+                        <argument name="Ndens"  type="real" default_value="1e15" />
+                        <!-- Projections of magnetic field in Larmor frequency units [1/s] -->
+                        <argument name="WLx"  type="real" default_value="0" />
+                        <argument name="WLy"  type="real" default_value="0" />
+                        <argument name="WLz"  type="real" default_value="0" />
+                        <!--Atoms temperature [K] -->
+                        <!--TODO: looks like Temperature > 10 K knocks solver, 
+                                         I am guessing detunings are too large and thus it became a stiff equation-->
+                        <!--! make sure it is not equal to zero!-->
+                        <argument name="Temperature"  type="real" default_value="5" />
+                        <!-- This will be executed after arguments/parameters are parsed -->
+                        <!-- Read the code Luke: took me a while of reading the xmds2 sources to find it -->
+                        <![CDATA[
+                                // Average sqrt(v^2) in Maxwell distribution for one dimension
+                                if (Temperature == 0)
+                                        _LOG(_ERROR_LOG_LEVEL, "ERROR: Temperature should be >0 to provide range for Maxwell velocity distribution\n");
+                                v_thermal_averaged=sqrt(k_boltzmann*Temperature/mass); 
+                                // Maxwell distribution velocities range to take in account in [m/s]
+                                // there is almost zero probability for higher velocity p(4*v_av) = 3.3e-04 * p(0)
+                                V_maxwell_min = -4*v_thermal_averaged; V_maxwell_max = -V_maxwell_min; 
+                        ]]>
+    </arguments>
+                <bing />
+                <diagnostics /> 
+                <fftw plan="estimate" threads="1" />
+                <!--<fftw plan="patient" threads="1" />-->
+                <!-- I don't see any speed up on 6 core CPU even if use threads="6" -->
+                <!--<openmp />-->
+                <auto_vectorise />
+                <halt_non_finite />
+        </features>
+
+        <!-- 'z', 't', and 'v'  to have dimensions [m], [s], and [m/s]   -->
+        <geometry>
+                <propagation_dimension> z </propagation_dimension>
+                <transverse_dimensions>
+                        <!-- IMPORTANT: looks like having a lot of points in time helps with convergence.
+                                         I suspect that time spacing should be small enough to catch
+                                         all pulse harmonics and more importantly 1/dt should be larger than
+                                         the largest detuning (including Doppler shifts).
+                                         Unfortunately calculation time is proportional to lattice size
+                                         so we cannot just blindly increase it.
+                                         Some rules of thumb:  
+                                                * lattice="1000"   domain="(-1e-6, 1e-6)" 
+                                                        was good enough detunings up to 155 MHz (980 rad/s) notice that 1/dt=500 MHz
+                                                * lattice="10000"   domain="(-1e-6, 1e-6)" 
+                                                        works for Doppler averaging in up to 400K for Rb when lasers are zero detuned
+                         -->
+                        <dimension name="t"   lattice="10000"   domain="(-1e-6, 1e-6)" />
+                        <dimension name="v"   lattice="2"   domain="(V_maxwell_min, V_maxwell_max)" />
+                </transverse_dimensions>
+        </geometry>
+
+        <!-- Rabi frequency --> 
+        <vector name="E_field" type="complex" initial_space="t">
+                 <!--plus/minus circular polarization components-->
+                <components>Ep1 Em1 Ep2 Em2 Ep3 Em3 Ep4 Em4</components>
+                <initialisation>
+                        <![CDATA[
+                        // Initial (at starting 'z' position) electromagnetic field does not depend on detuning
+                        // as well as time
+                        Ep1=Ep1o_field;
+                        Em1=Em1o_field;
+                        Ep2=Ep2o_field*exp(-pow( ((t-0.0)/Pwidth),2) );
+                        Em2=Em2o_field*exp(-pow( ((t-0.0)/Pwidth),2) );
+                        Ep3=Ep3o_field;
+                        Em3=Em3o_field;
+                        Ep4=Ep4o_field;
+                        Em4=Em4o_field;
+                        ]]>
+                </initialisation>
+        </vector>
+
+        <!--Maxwell distribution probability p(v)-->
+        <computed_vector name="Maxwell_distribution_probabilities" dimensions="v" type="real">
+                <components>probability_v</components>
+                <evaluation>
+                        <![CDATA[
+                        // TODO: move to the global space/function. This reevaluated many times since it called from dependency requests but it never changes during  the script lifetime since 'v' is fixed.
+                        probability_v=1.0/(v_thermal_averaged*sqrt(2*M_PI)) * exp( - mod2(v/v_thermal_averaged)/2.0 ); 
+                        ]]>
+                </evaluation>
+        </computed_vector>
+
+        <!--Maxwell distribution norm sum(p(v))
+                         Needed since we sum over the grid instead of true integral,
+                         we also have finite cut off velocities-->
+        <computed_vector name="Maxwell_distribution_probabilities_norm" dimensions="" type="real">
+                <components>probability_v_norm</components>
+                <evaluation>
+                        <dependencies basis="v">Maxwell_distribution_probabilities</dependencies>
+                        <![CDATA[
+                        // TODO: move to the global space/function. This reevaluated many times since it called from dependency requests but it never changes during  the script lifetime since 'v' is fixed.
+                        probability_v_norm=probability_v;
+                        ]]>
+                </evaluation>
+        </computed_vector>
+
+
+        <!-- Averaged across Maxwell distribution fields amplitudes -->
+        <computed_vector name="E_field_avgd" dimensions="t" type="complex">
+                <components>Ep1a Em1a Ep2a Em2a Ep3a Em3a Ep4a Em4a</components>
+                <evaluation>
+                        <dependencies basis="v">E_field Maxwell_distribution_probabilities Maxwell_distribution_probabilities_norm</dependencies>
+                        <![CDATA[
+                        double prob_v_normalized=probability_v/probability_v_norm;
+                        Ep1a=Ep1*prob_v_normalized;
+                        Em1a=Em1*prob_v_normalized;
+                        Ep2a=Ep2*prob_v_normalized;
+                        Em2a=Em2*prob_v_normalized;
+                        Ep3a=Ep3*prob_v_normalized;
+                        Em3a=Em3*prob_v_normalized;
+                        Ep4a=Ep4*prob_v_normalized;
+                        Em4a=Em4*prob_v_normalized;
+                        ]]>
+                </evaluation>
+        </computed_vector>
+
+        <vector name="density_matrix" type="complex" initial_space="t">
+                <components>
+                        <!-- read from Mathematica generated RbChosenRho.txt -->
+<!-- ############### RbChosenRho.txt starts ################ -->
+r0101 r0109 r0110 r0111 r0112 r0113 r0114 r0115 r0116 r0201 r0202 r0209 r0210 r0211 r0212 r0213 r0214 r0215 r0216 r0301 r0302 r0303 r0309 r0310 r0311 r0312 r0313 r0314 r0315 r0316 r0401 r0402 r0403 r0404 r0409 r0410 r0411 r0412 r0413 r0414 r0415 r0416 r0501 r0502 r0503 r0504 r0505 r0509 r0510 r0511 r0512 r0513 r0514 r0515 r0516 r0601 r0602 r0603 r0604 r0605 r0606 r0609 r0610 r0611 r0612 r0613 r0614 r0615 r0616 r0701 r0702 r0703 r0704 r0705 r0706 r0707 r0709 r0710 r0711 r0712 r0713 r0714  [...]
+<!-- ############### RbChosenRho.txt ends  ################# -->
+                </components>
+                <initialisation>
+                        <!--This sets boundary condition at all times and left border of z (i.e. z=0)-->
+                        <![CDATA[
+                        // Note: 
+                        // convergence is really slow if all populations concentrated at the bottom level |1>
+                        // this is because if r11=1, everything else is 0 and then every small increment 
+                        // seems to be huge and adaptive solver makes smaller and smaller steps.
+                        // As quick and dirty fix I reshuffle initial population  
+                        // so some of the population sits at the  second ground level |2>
+                        // TODO: Fix above. Make the equation of motion for r11 
+                        //       and express other level, let's say r44
+                        //       through population normalization
+
+                        //read from Mathematica generated RbInits.txt
+//---------------- RbInits.txt starts ------------------
+r0101 = 0.125;
+r0109 = 0;
+r0110 = 0;
+r0111 = 0;
+r0112 = 0;
+r0113 = 0;
+r0114 = 0;
+r0115 = 0;
+r0116 = 0;
+r0201 = 0;
+r0202 = 0.125;
+r0209 = 0;
+r0210 = 0;
+r0211 = 0;
+r0212 = 0;
+r0213 = 0;
+r0214 = 0;
+r0215 = 0;
+r0216 = 0;
+r0301 = 0;
+r0302 = 0;
+r0303 = 0.125;
+r0309 = 0;
+r0310 = 0;
+r0311 = 0;
+r0312 = 0;
+r0313 = 0;
+r0314 = 0;
+r0315 = 0;
+r0316 = 0;
+r0401 = 0;
+r0402 = 0;
+r0403 = 0;
+r0404 = 0.125;
+r0409 = 0;
+r0410 = 0;
+r0411 = 0;
+r0412 = 0;
+r0413 = 0;
+r0414 = 0;
+r0415 = 0;
+r0416 = 0;
+r0501 = 0;
+r0502 = 0;
+r0503 = 0;
+r0504 = 0;
+r0505 = 0.125;
+r0509 = 0;
+r0510 = 0;
+r0511 = 0;
+r0512 = 0;
+r0513 = 0;
+r0514 = 0;
+r0515 = 0;
+r0516 = 0;
+r0601 = 0;
+r0602 = 0;
+r0603 = 0;
+r0604 = 0;
+r0605 = 0;
+r0606 = 0.125;
+r0609 = 0;
+r0610 = 0;
+r0611 = 0;
+r0612 = 0;
+r0613 = 0;
+r0614 = 0;
+r0615 = 0;
+r0616 = 0;
+r0701 = 0;
+r0702 = 0;
+r0703 = 0;
+r0704 = 0;
+r0705 = 0;
+r0706 = 0;
+r0707 = 0.125;
+r0709 = 0;
+r0710 = 0;
+r0711 = 0;
+r0712 = 0;
+r0713 = 0;
+r0714 = 0;
+r0715 = 0;
+r0716 = 0;
+r0801 = 0;
+r0802 = 0;
+r0803 = 0;
+r0804 = 0;
+r0805 = 0;
+r0806 = 0;
+r0807 = 0;
+r0808 = 0.125;
+r0809 = 0;
+r0810 = 0;
+r0811 = 0;
+r0812 = 0;
+r0813 = 0;
+r0814 = 0;
+r0815 = 0;
+r0816 = 0;
+r0909 = 0;
+r0912 = 0;
+r0913 = 0;
+r0914 = 0;
+r0915 = 0;
+r0916 = 0;
+r1009 = 0;
+r1010 = 0;
+r1012 = 0;
+r1013 = 0;
+r1014 = 0;
+r1015 = 0;
+r1016 = 0;
+r1109 = 0;
+r1110 = 0;
+r1111 = 0;
+r1112 = 0;
+r1113 = 0;
+r1114 = 0;
+r1115 = 0;
+r1116 = 0;
+r1212 = 0;
+r1312 = 0;
+r1313 = 0;
+r1412 = 0;
+r1413 = 0;
+r1414 = 0;
+r1512 = 0;
+r1513 = 0;
+r1514 = 0;
+r1515 = 0;
+r1612 = 0;
+r1613 = 0;
+r1614 = 0;
+r1615 = 0;
+r1616 = 0;
+//---------------- RbInits.txt ends  ------------------
+                        ]]>
+                </initialisation>
+        </vector>
+
+        <sequence>
+                <!--For this set of conditions ARK45 is faster than ARK89-->
+                <!--ARK45 is good for small detuning when all frequency like term are close to zero-->
+                <integrate algorithm="ARK45" tolerance="1e-5" interval="Lcell"> 
+                <!--<integrate algorithm="SI" steps="200" interval="Lcell"> -->
+                <!--RK4 is good for large detunings when frequency like term are big, it does not try to be too smart about adaptive step which ARK seems to make too small-->
+                <!--When ARK45 works it about 3 times faster than RK4 with 1000 steps-->
+                <!--<integrate algorithm="RK4" steps="100" interval="1.5e-2">-->
+                <!--SIC algorithm seems to be much slower and needs fine 'z'  step tuning and much finer time grid-->
+                <!--For example I had to quadruple the time grid from 1000 to 4000 when increased z distance from 0.02 to 0.04-->
+
+                <!--<integrate algorithm="SIC" interval="4e-2" steps="200">-->
+
+                        <samples>1</samples>
+                        <!--<samples>100 100</samples>-->
+                        <!--Use the next line for debuging to see velocity dependence. Uncomment/switch on output groups 3,4-->
+                        <!--<samples>100 100 100 100</samples>--> 
+                        <operators>
+        <operator kind="cross_propagation" algorithm="SI" propagation_dimension="t">
+                                        <integration_vectors>density_matrix</integration_vectors>
+          <dependencies>E_field_avgd</dependencies>
+          <boundary_condition kind="left">
+                                                <!--This set boundary condition at all 'z'  and left border of 't' (i.e. min(t))-->
+                                                <!--
+            <![CDATA[
+                                                        r11 = 0; r22 = 1; r33 = 0; r44 = 0;
+                                                        r12 = 0; r13 = 0; r14 = 0;
+                                                        r23 = 0; r24 = 0;
+                                                        r34 = 0;
+                                                        printf("z= %g, t= %g\n", z, t);
+            ]]>
+                                                -->
+          </boundary_condition>
+                                        <![CDATA[
+                                                // Equations of motions according to Simon's mathematica code
+                                                //read from Mathematica generated RbEquations.txt
+//---------------- RbEquations.txt starts ------------------
+dr0101_dt = gt/8. - gt*r0101 + (g1*r0909)/2. + (g2*r1212)/3. + (g2*r1313)/6. - i*((conj(Em1a)*conj(r0109))/4. - (conj(Em4a)*conj(r0113))/(4.*rt6) - (Em1a*r0109)/4. + (Em4a*r0113)/(4.*rt6) + r0201*(WLx/2. - (i*WLy)/2.) - conj(r0201)*(WLx/2. + (i*WLy)/2.));
+dr0109_dt = (-(gt*r0109) - (gt + g1)*r0109)/2. - i*(-(conj(Ep1a)*conj(r0301))/(4.*rt6) + (conj(Ep2a)*conj(r0701))/(4.*rt6) - (conj(Em4a)*conj(r0913))/(4.*rt6) - (conj(Em1a)*r0101)/4. + (conj(Em1a)*r0909)/4. + r0209*(WLx/2. - (i*WLy)/2.) - r0110*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0109*(-delta1 - v*Kvec1 - WLz/6.) + r0109*WLz);
+dr0110_dt = (-(gt*r0110) - (gt + g1)*r0110)/2. - i*(-(conj(Em1a)*conj(r0201))/(4.*rt2) - (conj(Ep1a)*conj(r0401))/(4.*rt2) - (conj(Em2a)*conj(r0601))/(4.*rt6) + (conj(Ep2a)*conj(r0801))/(4.*rt6) + (conj(Em1a)*conj(r1009))/4. - (conj(Em4a)*conj(r1013))/(4.*rt6) + (delta1 + v*Kvec1)*r0110 + r0210*(WLx/2. - (i*WLy)/2.) - r0111*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0109*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) + r0110*WLz);
+dr0111_dt = (-(gt*r0111) - (gt + g1)*r0111)/2. - i*(-(conj(Em1a)*conj(r0301))/(4.*rt6) - (conj(Ep1a)*conj(r0501))/4. - (conj(Em2a)*conj(r0701))/(4.*rt6) + (conj(Em1a)*conj(r1109))/4. - (conj(Em4a)*conj(r1113))/(4.*rt6) + r0211*(WLx/2. - (i*WLy)/2.) - r0110*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r0111*(-delta1 - v*Kvec1 + WLz/6.) + r0111*WLz);
+dr0112_dt = (-(gt*r0112) - (gt + g2)*r0112)/2. - i*(-(conj(Ep4a)*conj(r0201))/(4.*rt6) - (conj(Ep3a)*conj(r0601))/(4.*rt2) + (conj(Em1a)*r0912)/4. - (conj(Em4a)*r1312)/(4.*rt6) + r0212*(WLx/2. - (i*WLy)/2.) - r0113*((2*WLx)/3. + (2*i*WLy)/3.) + r0112*WLz - r0112*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr0113_dt = (-(gt*r0113) - (gt + g2)*r0113)/2. - i*(-(conj(Ep4a)*conj(r0301))/8. - (conj(Ep3a)*conj(r0701))/8. + (conj(Em4a)*r0101)/(4.*rt6) + (conj(Em1a)*r0913)/4. - (conj(Em4a)*r1313)/(4.*rt6) - r0112*((2*WLx)/3. - (2*i*WLy)/3.) + r0213*(WLx/2. - (i*WLy)/2.) - r0114*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) - r0113*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (2*WLz)/3.) + r0113*WLz);
+dr0114_dt = (-(gt*r0114) - (gt + g2)*r0114)/2. - i*((conj(Em4a)*conj(r0201))/8. - (conj(Ep4a)*conj(r0401))/8. - (conj(Em3a)*conj(r0601))/(8.*rt3) - (conj(Ep3a)*conj(r0801))/(8.*rt3) - (conj(Em4a)*conj(r1413))/(4.*rt6) - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r0114 + (conj(Em1a)*r0914)/4. + r0214*(WLx/2. - (i*WLy)/2.) - r0113*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0115*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r0114*WLz);
+dr0115_dt = (-(gt*r0115) - (gt + g2)*r0115)/2. - i*((conj(Em4a)*conj(r0301))/8. - (conj(Ep4a)*conj(r0501))/(4.*rt6) - (conj(Em3a)*conj(r0701))/8. - (conj(Em4a)*conj(r1513))/(4.*rt6) + (conj(Em1a)*r0915)/4. + r0215*(WLx/2. - (i*WLy)/2.) - r0116*((2*WLx)/3. + (2*i*WLy)/3.) - r0114*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0115*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (2*WLz)/3.) + r0115*WLz);
+dr0116_dt = (-(gt*r0116) - (gt + g2)*r0116)/2. - i*((conj(Em4a)*conj(r0401))/(4.*rt6) - (conj(Em3a)*conj(r0801))/(4.*rt2) - (conj(Em4a)*conj(r1613))/(4.*rt6) + (conj(Em1a)*r0916)/4. - r0115*((2*WLx)/3. - (2*i*WLy)/3.) + r0216*(WLx/2. - (i*WLy)/2.) - r0116*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) + r0116*WLz);
+dr0201_dt = -(gt*r0201) + (g1*r1009)/(2.*rt2) + (g2*r1312)/6. + (g2*r1413)/(2.*rt6) - i*((conj(Em1a)*conj(r0110))/(4.*rt2) + (conj(Ep4a)*conj(r0112))/(4.*rt6) - (conj(Em4a)*conj(r0114))/8. - (Em1a*r0209)/4. + (Em4a*r0213)/(4.*rt6) + r0101*(WLx/2. + (i*WLy)/2.) - r0202*(WLx/2. + (i*WLy)/2.) + r0301*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - (r0201*WLz)/2.);
+dr0202_dt = gt/8. - gt*r0202 + (g1*r0909)/4. + (g1*r1010)/4. + (g2*r1212)/6. + (g2*r1313)/12. + (g2*r1414)/4. - i*((conj(Em1a)*conj(r0210))/(4.*rt2) + (conj(Ep4a)*conj(r0212))/(4.*rt6) - (conj(Em4a)*conj(r0214))/8. - (Em1a*r0210)/(4.*rt2) - (Ep4a*r0212)/(4.*rt6) + (Em4a*r0214)/8. - r0201*(WLx/2. - (i*WLy)/2.) + conj(r0201)*(WLx/2. + (i*WLy)/2.) + r0302*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - conj(r0302)*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.));
+dr0209_dt = (-(gt*r0209) - (gt + g1)*r0209)/2. - i*(-(conj(Ep1a)*conj(r0302))/(4.*rt6) + (conj(Ep2a)*conj(r0702))/(4.*rt6) + (conj(Ep4a)*conj(r0912))/(4.*rt6) - (conj(Em4a)*conj(r0914))/8. - (conj(Em1a)*r0201)/4. + (conj(Em1a)*r1009)/(4.*rt2) + r0109*(WLx/2. + (i*WLy)/2.) + r0309*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - r0210*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0209*(-delta1 - v*Kvec1 - WLz/6.) + (r0209*WLz)/2.);
+dr0210_dt = (-(gt*r0210) - (gt + g1)*r0210)/2. - i*(-(conj(Ep1a)*conj(r0402))/(4.*rt2) - (conj(Em2a)*conj(r0602))/(4.*rt6) + (conj(Ep2a)*conj(r0802))/(4.*rt6) + (conj(Ep4a)*conj(r1012))/(4.*rt6) - (conj(Em4a)*conj(r1014))/8. - (conj(Em1a)*r0202)/(4.*rt2) + (delta1 + v*Kvec1)*r0210 + (conj(Em1a)*r1010)/(4.*rt2) + r0110*(WLx/2. + (i*WLy)/2.) + r0310*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - r0211*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0209*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) + (r0210*WLz)/2.);
+dr0211_dt = (-(gt*r0211) - (gt + g1)*r0211)/2. - i*(-(conj(Em1a)*conj(r0302))/(4.*rt6) - (conj(Ep1a)*conj(r0502))/4. - (conj(Em2a)*conj(r0702))/(4.*rt6) + (conj(Em1a)*conj(r1110))/(4.*rt2) + (conj(Ep4a)*conj(r1112))/(4.*rt6) - (conj(Em4a)*conj(r1114))/8. + r0111*(WLx/2. + (i*WLy)/2.) + r0311*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - r0210*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r0211*(-delta1 - v*Kvec1 + WLz/6.) + (r0211*WLz)/2.);
+dr0212_dt = (-(gt*r0212) - (gt + g2)*r0212)/2. - i*(-(conj(Ep3a)*conj(r0602))/(4.*rt2) - (conj(Ep4a)*r0202)/(4.*rt6) + (conj(Em1a)*r1012)/(4.*rt2) + (conj(Ep4a)*r1212)/(4.*rt6) - (conj(Em4a)*r1412)/8. + r0112*(WLx/2. + (i*WLy)/2.) - r0213*((2*WLx)/3. + (2*i*WLy)/3.) + r0312*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + (r0212*WLz)/2. - r0212*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr0213_dt = (-(gt*r0213) - (gt + g2)*r0213)/2. - i*(-(conj(Ep4a)*conj(r0302))/8. - (conj(Ep3a)*conj(r0702))/8. + (conj(Ep4a)*conj(r1312))/(4.*rt6) + (conj(Em4a)*r0201)/(4.*rt6) + (conj(Em1a)*r1013)/(4.*rt2) - (conj(Em4a)*r1413)/8. - r0212*((2*WLx)/3. - (2*i*WLy)/3.) + r0113*(WLx/2. + (i*WLy)/2.) - r0214*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r0313*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - r0213*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (2*W [...]
+dr0214_dt = (-(gt*r0214) - (gt + g2)*r0214)/2. - i*(-(conj(Ep4a)*conj(r0402))/8. - (conj(Em3a)*conj(r0602))/(8.*rt3) - (conj(Ep3a)*conj(r0802))/(8.*rt3) + (conj(Ep4a)*conj(r1412))/(4.*rt6) + (conj(Em4a)*r0202)/8. - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r0214 + (conj(Em1a)*r1014)/(4.*rt2) - (conj(Em4a)*r1414)/8. + r0114*(WLx/2. + (i*WLy)/2.) - r0213*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0215*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666 [...]
+dr0215_dt = (-(gt*r0215) - (gt + g2)*r0215)/2. - i*((conj(Em4a)*conj(r0302))/8. - (conj(Ep4a)*conj(r0502))/(4.*rt6) - (conj(Em3a)*conj(r0702))/8. + (conj(Ep4a)*conj(r1512))/(4.*rt6) - (conj(Em4a)*conj(r1514))/8. + (conj(Em1a)*r1015)/(4.*rt2) + r0115*(WLx/2. + (i*WLy)/2.) - r0216*((2*WLx)/3. + (2*i*WLy)/3.) - r0214*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r0315*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - r0215*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*K [...]
+dr0216_dt = (-(gt*r0216) - (gt + g2)*r0216)/2. - i*((conj(Em4a)*conj(r0402))/(4.*rt6) - (conj(Em3a)*conj(r0802))/(4.*rt2) + (conj(Ep4a)*conj(r1612))/(4.*rt6) - (conj(Em4a)*conj(r1614))/8. + (conj(Em1a)*r1016)/(4.*rt2) - r0215*((2*WLx)/3. - (2*i*WLy)/3.) + r0116*(WLx/2. + (i*WLy)/2.) + r0316*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - r0216*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) + (r0216*WLz)/2.);
+dr0301_dt = -(gt*r0301) + (g1*r1109)/(2.*rt6) + (g2*r1513)/(2.*rt6) - i*((conj(Ep1a)*conj(r0109))/(4.*rt6) + (conj(Em1a)*conj(r0111))/(4.*rt6) + (conj(Ep4a)*conj(r0113))/8. - (conj(Em4a)*conj(r0115))/8. - (Em1a*r0309)/4. + (Em4a*r0313)/(4.*rt6) - r0302*(WLx/2. + (i*WLy)/2.) + r0401*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0201*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0301*WLz);
+dr0302_dt = -(gt*r0302) + (g1*r1009)/(2.*rt3) + (g1*r1110)/(4.*rt3) + (g2*r1312)/(2.*rt6) + (g2*r1514)/4. - i*((conj(Ep1a)*conj(r0209))/(4.*rt6) + (conj(Em1a)*conj(r0211))/(4.*rt6) + (conj(Ep4a)*conj(r0213))/8. - (conj(Em4a)*conj(r0215))/8. - (Em1a*r0310)/(4.*rt2) - (Ep4a*r0312)/(4.*rt6) + (Em4a*r0314)/8. - r0301*(WLx/2. - (i*WLy)/2.) + r0402*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0202*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0303*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) [...]
+dr0303_dt = gt/8. - gt*r0303 + (g1*r0909)/12. + (g1*r1010)/3. + (g1*r1111)/12. + (g2*r1313)/4. + (g2*r1515)/4. - i*((conj(Ep1a)*conj(r0309))/(4.*rt6) + (conj(Em1a)*conj(r0311))/(4.*rt6) + (conj(Ep4a)*conj(r0313))/8. - (conj(Em4a)*conj(r0315))/8. - (Ep1a*r0309)/(4.*rt6) - (Em1a*r0311)/(4.*rt6) - (Ep4a*r0313)/8. + (Em4a*r0315)/8. - r0302*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0403*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + conj(r0302)*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.)  [...]
+dr0309_dt = (-(gt*r0309) - (gt + g1)*r0309)/2. - i*((conj(Ep2a)*conj(r0703))/(4.*rt6) + (conj(Ep4a)*conj(r0913))/8. - (conj(Em4a)*conj(r0915))/8. - (conj(Em1a)*r0301)/4. - (conj(Ep1a)*r0303)/(4.*rt6) + (conj(Ep1a)*r0909)/(4.*rt6) + (conj(Em1a)*r1109)/(4.*rt6) + r0409*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0209*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0310*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0309*(-delta1 - v*Kvec1 - WLz/6.));
+dr0310_dt = (-(gt*r0310) - (gt + g1)*r0310)/2. - i*(-(conj(Ep1a)*conj(r0403))/(4.*rt2) - (conj(Em2a)*conj(r0603))/(4.*rt6) + (conj(Ep2a)*conj(r0803))/(4.*rt6) + (conj(Ep1a)*conj(r1009))/(4.*rt6) + (conj(Ep4a)*conj(r1013))/8. - (conj(Em4a)*conj(r1015))/8. - (conj(Em1a)*r0302)/(4.*rt2) + (delta1 + v*Kvec1)*r0310 + (conj(Em1a)*r1110)/(4.*rt6) + r0410*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0210*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0311*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r [...]
+dr0311_dt = (-(gt*r0311) - (gt + g1)*r0311)/2. - i*(-(conj(Ep1a)*conj(r0503))/4. - (conj(Em2a)*conj(r0703))/(4.*rt6) + (conj(Ep1a)*conj(r1109))/(4.*rt6) + (conj(Ep4a)*conj(r1113))/8. - (conj(Em4a)*conj(r1115))/8. - (conj(Em1a)*r0303)/(4.*rt6) + (conj(Em1a)*r1111)/(4.*rt6) + r0411*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0211*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0310*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r0311*(-delta1 - v*Kvec1 + WLz/6.));
+dr0312_dt = (-(gt*r0312) - (gt + g2)*r0312)/2. - i*(-(conj(Ep3a)*conj(r0603))/(4.*rt2) - (conj(Ep4a)*r0302)/(4.*rt6) + (conj(Ep1a)*r0912)/(4.*rt6) + (conj(Em1a)*r1112)/(4.*rt6) + (conj(Ep4a)*r1312)/8. - (conj(Em4a)*r1512)/8. - r0313*((2*WLx)/3. + (2*i*WLy)/3.) + r0412*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0212*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0312*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr0313_dt = (-(gt*r0313) - (gt + g2)*r0313)/2. - i*(-(conj(Ep3a)*conj(r0703))/8. + (conj(Em4a)*r0301)/(4.*rt6) - (conj(Ep4a)*r0303)/8. + (conj(Ep1a)*r0913)/(4.*rt6) + (conj(Em1a)*r1113)/(4.*rt6) + (conj(Ep4a)*r1313)/8. - (conj(Em4a)*r1513)/8. - r0312*((2*WLx)/3. - (2*i*WLy)/3.) - r0314*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r0413*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0213*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0313*(-delta1 + delta2 - delta3 -  [...]
+dr0314_dt = (-(gt*r0314) - (gt + g2)*r0314)/2. - i*(-(conj(Ep4a)*conj(r0403))/8. - (conj(Em3a)*conj(r0603))/(8.*rt3) - (conj(Ep3a)*conj(r0803))/(8.*rt3) + (conj(Ep4a)*conj(r1413))/8. + (conj(Em4a)*r0302)/8. - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r0314 + (conj(Ep1a)*r0914)/(4.*rt6) + (conj(Em1a)*r1114)/(4.*rt6) - (conj(Em4a)*r1514)/8. - r0313*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0315*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666 [...]
+dr0315_dt = (-(gt*r0315) - (gt + g2)*r0315)/2. - i*(-(conj(Ep4a)*conj(r0503))/(4.*rt6) - (conj(Em3a)*conj(r0703))/8. + (conj(Ep4a)*conj(r1513))/8. + (conj(Em4a)*r0303)/8. + (conj(Ep1a)*r0915)/(4.*rt6) + (conj(Em1a)*r1115)/(4.*rt6) - (conj(Em4a)*r1515)/8. - r0316*((2*WLx)/3. + (2*i*WLy)/3.) - r0314*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r0415*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0215*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0315*(-delta1 + delta2 [...]
+dr0316_dt = (-(gt*r0316) - (gt + g2)*r0316)/2. - i*((conj(Em4a)*conj(r0403))/(4.*rt6) - (conj(Em3a)*conj(r0803))/(4.*rt2) + (conj(Ep4a)*conj(r1613))/8. - (conj(Em4a)*conj(r1615))/8. + (conj(Ep1a)*r0916)/(4.*rt6) + (conj(Em1a)*r1116)/(4.*rt6) - r0315*((2*WLx)/3. - (2*i*WLy)/3.) + r0416*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0216*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0316*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.));
+dr0401_dt = -(gt*r0401) - (g2*r1512)/6. + (g2*r1613)/6. - i*((conj(Ep1a)*conj(r0110))/(4.*rt2) + (conj(Ep4a)*conj(r0114))/8. - (conj(Em4a)*conj(r0116))/(4.*rt6) - (Em1a*r0409)/4. + (Em4a*r0413)/(4.*rt6) + r0501*(WLx/2. - (i*WLy)/2.) - r0402*(WLx/2. + (i*WLy)/2.) + r0301*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - (3*r0401*WLz)/2.);
+dr0402_dt = -(gt*r0402) + (g1*r1109)/4. + (g2*r1412)/(2.*rt6) - (g2*r1513)/12. + (g2*r1614)/(2.*rt6) - i*((conj(Ep1a)*conj(r0210))/(4.*rt2) + (conj(Ep4a)*conj(r0214))/8. - (conj(Em4a)*conj(r0216))/(4.*rt6) - (Em1a*r0410)/(4.*rt2) - (Ep4a*r0412)/(4.*rt6) + (Em4a*r0414)/8. - r0401*(WLx/2. - (i*WLy)/2.) + r0502*(WLx/2. - (i*WLy)/2.) + r0302*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0403*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0402*WLz);
+dr0403_dt = -(gt*r0403) + (g1*r1009)/(4.*rt3) + (g1*r1110)/(2.*rt3) + (g2*r1413)/4. + (g2*r1615)/(2.*rt6) - i*((conj(Ep1a)*conj(r0310))/(4.*rt2) + (conj(Ep4a)*conj(r0314))/8. - (conj(Em4a)*conj(r0316))/(4.*rt6) - (Ep1a*r0409)/(4.*rt6) - (Em1a*r0411)/(4.*rt6) - (Ep4a*r0413)/8. + (Em4a*r0415)/8. + r0503*(WLx/2. - (i*WLy)/2.) - r0402*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0303*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0404*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - (r0403*WLz)/2.);
+dr0404_dt = gt/8. - gt*r0404 + (g1*r1010)/4. + (g1*r1111)/4. + (g2*r1414)/4. + (g2*r1515)/12. + (g2*r1616)/6. - i*((conj(Ep1a)*conj(r0410))/(4.*rt2) + (conj(Ep4a)*conj(r0414))/8. - (conj(Em4a)*conj(r0416))/(4.*rt6) - (Ep1a*r0410)/(4.*rt2) - (Ep4a*r0414)/8. + (Em4a*r0416)/(4.*rt6) + r0504*(WLx/2. - (i*WLy)/2.) - conj(r0504)*(WLx/2. + (i*WLy)/2.) - r0403*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + conj(r0403)*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.));
+dr0409_dt = (-(gt*r0409) - (gt + g1)*r0409)/2. - i*((conj(Ep2a)*conj(r0704))/(4.*rt6) + (conj(Ep4a)*conj(r0914))/8. - (conj(Em4a)*conj(r0916))/(4.*rt6) - (conj(Em1a)*r0401)/4. - (conj(Ep1a)*r0403)/(4.*rt6) + (conj(Ep1a)*r1009)/(4.*rt2) + r0509*(WLx/2. - (i*WLy)/2.) + r0309*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0410*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0409*(-delta1 - v*Kvec1 - WLz/6.) - (r0409*WLz)/2.);
+dr0410_dt = (-(gt*r0410) - (gt + g1)*r0410)/2. - i*(-(conj(Em2a)*conj(r0604))/(4.*rt6) + (conj(Ep2a)*conj(r0804))/(4.*rt6) + (conj(Ep4a)*conj(r1014))/8. - (conj(Em4a)*conj(r1016))/(4.*rt6) - (conj(Em1a)*r0402)/(4.*rt2) - (conj(Ep1a)*r0404)/(4.*rt2) + (delta1 + v*Kvec1)*r0410 + (conj(Ep1a)*r1010)/(4.*rt2) + r0510*(WLx/2. - (i*WLy)/2.) + r0310*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0411*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0409*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - (r0410*WLz)/2.);
+dr0411_dt = (-(gt*r0411) - (gt + g1)*r0411)/2. - i*(-(conj(Ep1a)*conj(r0504))/4. - (conj(Em2a)*conj(r0704))/(4.*rt6) + (conj(Ep1a)*conj(r1110))/(4.*rt2) + (conj(Ep4a)*conj(r1114))/8. - (conj(Em4a)*conj(r1116))/(4.*rt6) - (conj(Em1a)*r0403)/(4.*rt6) + r0511*(WLx/2. - (i*WLy)/2.) + r0311*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0410*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r0411*(-delta1 - v*Kvec1 + WLz/6.) - (r0411*WLz)/2.);
+dr0412_dt = (-(gt*r0412) - (gt + g2)*r0412)/2. - i*(-(conj(Ep3a)*conj(r0604))/(4.*rt2) - (conj(Ep4a)*r0402)/(4.*rt6) + (conj(Ep1a)*r1012)/(4.*rt2) + (conj(Ep4a)*r1412)/8. - (conj(Em4a)*r1612)/(4.*rt6) + r0512*(WLx/2. - (i*WLy)/2.) - r0413*((2*WLx)/3. + (2*i*WLy)/3.) + r0312*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - (r0412*WLz)/2. - r0412*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr0413_dt = (-(gt*r0413) - (gt + g2)*r0413)/2. - i*(-(conj(Ep3a)*conj(r0704))/8. + (conj(Em4a)*r0401)/(4.*rt6) - (conj(Ep4a)*r0403)/8. + (conj(Ep1a)*r1013)/(4.*rt2) + (conj(Ep4a)*r1413)/8. - (conj(Em4a)*r1613)/(4.*rt6) - r0412*((2*WLx)/3. - (2*i*WLy)/3.) + r0513*(WLx/2. - (i*WLy)/2.) - r0414*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r0313*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0413*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (2*WLz)/3.) - (r [...]
+dr0414_dt = (-(gt*r0414) - (gt + g2)*r0414)/2. - i*(-(conj(Em3a)*conj(r0604))/(8.*rt3) - (conj(Ep3a)*conj(r0804))/(8.*rt3) + (conj(Em4a)*r0402)/8. - (conj(Ep4a)*r0404)/8. - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r0414 + (conj(Ep1a)*r1014)/(4.*rt2) + (conj(Ep4a)*r1414)/8. - (conj(Em4a)*r1614)/(4.*rt6) + r0514*(WLx/2. - (i*WLy)/2.) - r0413*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0415*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WL [...]
+dr0415_dt = (-(gt*r0415) - (gt + g2)*r0415)/2. - i*(-(conj(Ep4a)*conj(r0504))/(4.*rt6) - (conj(Em3a)*conj(r0704))/8. + (conj(Ep4a)*conj(r1514))/8. + (conj(Em4a)*r0403)/8. + (conj(Ep1a)*r1015)/(4.*rt2) - (conj(Em4a)*r1615)/(4.*rt6) + r0515*(WLx/2. - (i*WLy)/2.) - r0416*((2*WLx)/3. + (2*i*WLy)/3.) - r0414*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r0315*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0415*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (2*W [...]
+dr0416_dt = (-(gt*r0416) - (gt + g2)*r0416)/2. - i*(-(conj(Em3a)*conj(r0804))/(4.*rt2) + (conj(Ep4a)*conj(r1614))/8. + (conj(Em4a)*r0404)/(4.*rt6) + (conj(Ep1a)*r1016)/(4.*rt2) - (conj(Em4a)*r1616)/(4.*rt6) - r0415*((2*WLx)/3. - (2*i*WLy)/3.) + r0516*(WLx/2. - (i*WLy)/2.) + r0316*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0416*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) - (r0416*WLz)/2.);
+dr0501_dt = -(gt*r0501) - (g2*r1612)/3. - i*((conj(Ep1a)*conj(r0111))/4. + (conj(Ep4a)*conj(r0115))/(4.*rt6) - (Em1a*r0509)/4. + (Em4a*r0513)/(4.*rt6) + r0401*(WLx/2. + (i*WLy)/2.) - r0502*(WLx/2. + (i*WLy)/2.) - 2*r0501*WLz);
+dr0502_dt = -(gt*r0502) + (g2*r1512)/6. - (g2*r1613)/6. - i*((conj(Ep1a)*conj(r0211))/4. + (conj(Ep4a)*conj(r0215))/(4.*rt6) - (Em1a*r0510)/(4.*rt2) - (Ep4a*r0512)/(4.*rt6) + (Em4a*r0514)/8. - r0501*(WLx/2. - (i*WLy)/2.) + r0402*(WLx/2. + (i*WLy)/2.) - r0503*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - (3*r0502*WLz)/2.);
+dr0503_dt = -(gt*r0503) + (g1*r1109)/(2.*rt6) + (g2*r1513)/(2.*rt6) - i*((conj(Ep1a)*conj(r0311))/4. + (conj(Ep4a)*conj(r0315))/(4.*rt6) - (Ep1a*r0509)/(4.*rt6) - (Em1a*r0511)/(4.*rt6) - (Ep4a*r0513)/8. + (Em4a*r0515)/8. + r0403*(WLx/2. + (i*WLy)/2.) - r0502*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - r0504*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) - r0503*WLz);
+dr0504_dt = -(gt*r0504) + (g1*r1110)/(2.*rt2) + (g2*r1514)/(2.*rt6) + (g2*r1615)/6. - i*((conj(Ep1a)*conj(r0411))/4. + (conj(Ep4a)*conj(r0415))/(4.*rt6) - (Ep1a*r0510)/(4.*rt2) - (Ep4a*r0514)/8. + (Em4a*r0516)/(4.*rt6) + r0404*(WLx/2. + (i*WLy)/2.) - r0505*(WLx/2. + (i*WLy)/2.) - r0503*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - (r0504*WLz)/2.);
+dr0505_dt = gt/8. - gt*r0505 + (g1*r1111)/2. + (g2*r1515)/6. + (g2*r1616)/3. - i*((conj(Ep1a)*conj(r0511))/4. + (conj(Ep4a)*conj(r0515))/(4.*rt6) - (Ep1a*r0511)/4. - (Ep4a*r0515)/(4.*rt6) - r0504*(WLx/2. - (i*WLy)/2.) + conj(r0504)*(WLx/2. + (i*WLy)/2.));
+dr0509_dt = (-(gt*r0509) - (gt + g1)*r0509)/2. - i*((conj(Ep2a)*conj(r0705))/(4.*rt6) + (conj(Ep4a)*conj(r0915))/(4.*rt6) - (conj(Em1a)*r0501)/4. - (conj(Ep1a)*r0503)/(4.*rt6) + (conj(Ep1a)*r1109)/4. + r0409*(WLx/2. + (i*WLy)/2.) - r0510*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0509*(-delta1 - v*Kvec1 - WLz/6.) - r0509*WLz);
+dr0510_dt = (-(gt*r0510) - (gt + g1)*r0510)/2. - i*(-(conj(Em2a)*conj(r0605))/(4.*rt6) + (conj(Ep2a)*conj(r0805))/(4.*rt6) + (conj(Ep4a)*conj(r1015))/(4.*rt6) - (conj(Em1a)*r0502)/(4.*rt2) - (conj(Ep1a)*r0504)/(4.*rt2) + (delta1 + v*Kvec1)*r0510 + (conj(Ep1a)*r1110)/4. + r0410*(WLx/2. + (i*WLy)/2.) - r0511*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0509*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r0510*WLz);
+dr0511_dt = (-(gt*r0511) - (gt + g1)*r0511)/2. - i*(-(conj(Em2a)*conj(r0705))/(4.*rt6) + (conj(Ep4a)*conj(r1115))/(4.*rt6) - (conj(Em1a)*r0503)/(4.*rt6) - (conj(Ep1a)*r0505)/4. + (conj(Ep1a)*r1111)/4. + r0411*(WLx/2. + (i*WLy)/2.) - r0510*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r0511*(-delta1 - v*Kvec1 + WLz/6.) - r0511*WLz);
+dr0512_dt = (-(gt*r0512) - (gt + g2)*r0512)/2. - i*(-(conj(Ep3a)*conj(r0605))/(4.*rt2) - (conj(Ep4a)*r0502)/(4.*rt6) + (conj(Ep1a)*r1112)/4. + (conj(Ep4a)*r1512)/(4.*rt6) + r0412*(WLx/2. + (i*WLy)/2.) - r0513*((2*WLx)/3. + (2*i*WLy)/3.) - r0512*WLz - r0512*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr0513_dt = (-(gt*r0513) - (gt + g2)*r0513)/2. - i*(-(conj(Ep3a)*conj(r0705))/8. + (conj(Em4a)*r0501)/(4.*rt6) - (conj(Ep4a)*r0503)/8. + (conj(Ep1a)*r1113)/4. + (conj(Ep4a)*r1513)/(4.*rt6) - r0512*((2*WLx)/3. - (2*i*WLy)/3.) + r0413*(WLx/2. + (i*WLy)/2.) - r0514*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) - r0513*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (2*WLz)/3.) - r0513*WLz);
+dr0514_dt = (-(gt*r0514) - (gt + g2)*r0514)/2. - i*(-(conj(Em3a)*conj(r0605))/(8.*rt3) - (conj(Ep3a)*conj(r0805))/(8.*rt3) + (conj(Em4a)*r0502)/8. - (conj(Ep4a)*r0504)/8. - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r0514 + (conj(Ep1a)*r1114)/4. + (conj(Ep4a)*r1514)/(4.*rt6) + r0414*(WLx/2. + (i*WLy)/2.) - r0513*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0515*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) - r0514*WLz);
+dr0515_dt = (-(gt*r0515) - (gt + g2)*r0515)/2. - i*(-(conj(Em3a)*conj(r0705))/8. + (conj(Em4a)*r0503)/8. - (conj(Ep4a)*r0505)/(4.*rt6) + (conj(Ep1a)*r1115)/4. + (conj(Ep4a)*r1515)/(4.*rt6) + r0415*(WLx/2. + (i*WLy)/2.) - r0516*((2*WLx)/3. + (2*i*WLy)/3.) - r0514*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0515*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (2*WLz)/3.) - r0515*WLz);
+dr0516_dt = (-(gt*r0516) - (gt + g2)*r0516)/2. - i*(-(conj(Em3a)*conj(r0805))/(4.*rt2) + (conj(Ep4a)*conj(r1615))/(4.*rt6) + (conj(Em4a)*r0504)/(4.*rt6) + (conj(Ep1a)*r1116)/4. - r0515*((2*WLx)/3. - (2*i*WLy)/3.) + r0416*(WLx/2. + (i*WLy)/2.) - r0516*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) - r0516*WLz);
+dr0601_dt = -(gt*r0601) - i*((conj(Em2a)*conj(r0110))/(4.*rt6) + (conj(Ep3a)*conj(r0112))/(4.*rt2) + (conj(Em3a)*conj(r0114))/(8.*rt3) - (Em1a*r0609)/4. + (Em4a*r0613)/(4.*rt6) - r0602*(WLx/2. + (i*WLy)/2.) + r0701*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0601*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.) - r0601*WLz);
+dr0602_dt = -(gt*r0602) - i*((conj(Em2a)*conj(r0210))/(4.*rt6) + (conj(Ep3a)*conj(r0212))/(4.*rt2) + (conj(Em3a)*conj(r0214))/(8.*rt3) - (Em1a*r0610)/(4.*rt2) - (Ep4a*r0612)/(4.*rt6) + (Em4a*r0614)/8. - r0601*(WLx/2. - (i*WLy)/2.) - r0603*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) + r0702*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0602*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.) - (r0602*WLz)/2.);
+dr0603_dt = -(gt*r0603) - i*((conj(Em2a)*conj(r0310))/(4.*rt6) + (conj(Ep3a)*conj(r0312))/(4.*rt2) + (conj(Em3a)*conj(r0314))/(8.*rt3) - (Ep1a*r0609)/(4.*rt6) - (Em1a*r0611)/(4.*rt6) - (Ep4a*r0613)/8. + (Em4a*r0615)/8. - r0602*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - r0604*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) + r0703*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0603*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.));
+dr0604_dt = -(gt*r0604) - i*((conj(Em2a)*conj(r0410))/(4.*rt6) + (conj(Ep3a)*conj(r0412))/(4.*rt2) + (conj(Em3a)*conj(r0414))/(8.*rt3) - (Ep1a*r0610)/(4.*rt2) - (Ep4a*r0614)/8. + (Em4a*r0616)/(4.*rt6) - r0605*(WLx/2. + (i*WLy)/2.) - r0603*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0704*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0604*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.) + (r0604*WLz)/2.);
+dr0605_dt = -(gt*r0605) - i*((conj(Em2a)*conj(r0510))/(4.*rt6) + (conj(Ep3a)*conj(r0512))/(4.*rt2) + (conj(Em3a)*conj(r0514))/(8.*rt3) - (Ep1a*r0611)/4. - (Ep4a*r0615)/(4.*rt6) - r0604*(WLx/2. - (i*WLy)/2.) + r0705*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0605*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.) + r0605*WLz);
+dr0606_dt = gt/8. - gt*r0606 + (g1*r0909)/12. + (g1*r1010)/12. + (g2*r1212)/2. + (g2*r1313)/4. + (g2*r1414)/12. - i*((conj(Em2a)*conj(r0610))/(4.*rt6) + (conj(Ep3a)*conj(r0612))/(4.*rt2) + (conj(Em3a)*conj(r0614))/(8.*rt3) - (Em2a*r0610)/(4.*rt6) - (Ep3a*r0612)/(4.*rt2) - (Em3a*r0614)/(8.*rt3) - conj(r0706)*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0706*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)));
+dr0609_dt = (-(gt*r0609) - (gt + g1)*r0609)/2. - i*((conj(Ep2a)*conj(r0706))/(4.*rt6) + (conj(Ep3a)*conj(r0912))/(4.*rt2) + (conj(Em3a)*conj(r0914))/(8.*rt3) - (conj(Em1a)*r0601)/4. - (conj(Ep1a)*r0603)/(4.*rt6) + (conj(Em2a)*r1009)/(4.*rt6) - r0610*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) + r0709*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0609*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.) - r0609*(-delta1 - v*Kvec1 - WLz/6.));
+dr0610_dt = (-(gt*r0610) - (gt + g1)*r0610)/2. - i*((conj(Ep2a)*conj(r0806))/(4.*rt6) + (conj(Ep3a)*conj(r1012))/(4.*rt2) + (conj(Em3a)*conj(r1014))/(8.*rt3) - (conj(Em1a)*r0602)/(4.*rt2) - (conj(Ep1a)*r0604)/(4.*rt2) - (conj(Em2a)*r0606)/(4.*rt6) + (delta1 + v*Kvec1)*r0610 + (conj(Em2a)*r1010)/(4.*rt6) - r0611*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0609*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) + r0710*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0610*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.));
+dr0611_dt = (-(gt*r0611) - (gt + g1)*r0611)/2. - i*(-(conj(Em2a)*conj(r0706))/(4.*rt6) + (conj(Em2a)*conj(r1110))/(4.*rt6) + (conj(Ep3a)*conj(r1112))/(4.*rt2) + (conj(Em3a)*conj(r1114))/(8.*rt3) - (conj(Em1a)*r0603)/(4.*rt6) - (conj(Ep1a)*r0605)/4. - r0610*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) + r0711*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0611*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.) - r0611*(-delta1 - v*Kvec1 + WLz/6.));
+dr0612_dt = (-(gt*r0612) - (gt + g2)*r0612)/2. - i*(-(conj(Ep4a)*r0602)/(4.*rt6) - (conj(Ep3a)*r0606)/(4.*rt2) + (conj(Em2a)*r1012)/(4.*rt6) + (conj(Ep3a)*r1212)/(4.*rt2) + (conj(Em3a)*r1412)/(8.*rt3) - r0613*((2*WLx)/3. + (2*i*WLy)/3.) + r0712*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0612*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.) - r0612*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr0613_dt = (-(gt*r0613) - (gt + g2)*r0613)/2. - i*(-(conj(Ep3a)*conj(r0706))/8. + (conj(Ep3a)*conj(r1312))/(4.*rt2) + (conj(Em4a)*r0601)/(4.*rt6) - (conj(Ep4a)*r0603)/8. + (conj(Em2a)*r1013)/(4.*rt6) + (conj(Em3a)*r1413)/(8.*rt3) - r0612*((2*WLx)/3. - (2*i*WLy)/3.) - r0614*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r0713*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0613*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.) - r0613*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 [...]
+dr0614_dt = (-(gt*r0614) - (gt + g2)*r0614)/2. - i*(-(conj(Ep3a)*conj(r0806))/(8.*rt3) + (conj(Ep3a)*conj(r1412))/(4.*rt2) + (conj(Em4a)*r0602)/8. - (conj(Ep4a)*r0604)/8. - (conj(Em3a)*r0606)/(8.*rt3) - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r0614 + (conj(Em2a)*r1014)/(4.*rt6) + (conj(Em3a)*r1414)/(8.*rt3) - r0613*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0615*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r0714*(-WLx/(2.*rt2 [...]
+dr0615_dt = (-(gt*r0615) - (gt + g2)*r0615)/2. - i*(-(conj(Em3a)*conj(r0706))/8. + (conj(Ep3a)*conj(r1512))/(4.*rt2) + (conj(Em3a)*conj(r1514))/(8.*rt3) + (conj(Em4a)*r0603)/8. - (conj(Ep4a)*r0605)/(4.*rt6) + (conj(Em2a)*r1015)/(4.*rt6) - r0616*((2*WLx)/3. + (2*i*WLy)/3.) - r0614*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r0715*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - r0615*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (2*WLz)/3.) + r0615*(-delta1 + delta2 [...]
+dr0616_dt = (-(gt*r0616) - (gt + g2)*r0616)/2. - i*(-(conj(Em3a)*conj(r0806))/(4.*rt2) + (conj(Ep3a)*conj(r1612))/(4.*rt2) + (conj(Em3a)*conj(r1614))/(8.*rt3) + (conj(Em4a)*r0604)/(4.*rt6) + (conj(Em2a)*r1016)/(4.*rt6) - r0615*((2*WLx)/3. - (2*i*WLy)/3.) + r0716*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - r0616*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) + r0616*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.));
+dr0701_dt = -(gt*r0701) - i*(-(conj(Ep2a)*conj(r0109))/(4.*rt6) + (conj(Em2a)*conj(r0111))/(4.*rt6) + (conj(Ep3a)*conj(r0113))/8. + (conj(Em3a)*conj(r0115))/8. + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0701 - (Em1a*r0709)/4. + (Em4a*r0713)/(4.*rt6) - r0702*(WLx/2. + (i*WLy)/2.) + r0601*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0801*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - r0701*WLz);
+dr0702_dt = -(gt*r0702) - i*(-(conj(Ep2a)*conj(r0209))/(4.*rt6) + (conj(Em2a)*conj(r0211))/(4.*rt6) + (conj(Ep3a)*conj(r0213))/8. + (conj(Em3a)*conj(r0215))/8. + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0702 - (Em1a*r0710)/(4.*rt2) - (Ep4a*r0712)/(4.*rt6) + (Em4a*r0714)/8. - r0701*(WLx/2. - (i*WLy)/2.) - r0703*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) + r0602*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0802*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - (r0702*WLz)/2.);
+dr0703_dt = -(gt*r0703) - i*(-(conj(Ep2a)*conj(r0309))/(4.*rt6) + (conj(Em2a)*conj(r0311))/(4.*rt6) + (conj(Ep3a)*conj(r0313))/8. + (conj(Em3a)*conj(r0315))/8. + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0703 - (Ep1a*r0709)/(4.*rt6) - (Em1a*r0711)/(4.*rt6) - (Ep4a*r0713)/8. + (Em4a*r0715)/8. - r0702*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - r0704*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) + r0603*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0803*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)));
+dr0704_dt = -(gt*r0704) - i*(-(conj(Ep2a)*conj(r0409))/(4.*rt6) + (conj(Em2a)*conj(r0411))/(4.*rt6) + (conj(Ep3a)*conj(r0413))/8. + (conj(Em3a)*conj(r0415))/8. + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0704 - (Ep1a*r0710)/(4.*rt2) - (Ep4a*r0714)/8. + (Em4a*r0716)/(4.*rt6) - r0705*(WLx/2. + (i*WLy)/2.) - r0703*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0604*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0804*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + (r0704*WLz)/2.);
+dr0705_dt = -(gt*r0705) - i*(-(conj(Ep2a)*conj(r0509))/(4.*rt6) + (conj(Em2a)*conj(r0511))/(4.*rt6) + (conj(Ep3a)*conj(r0513))/8. + (conj(Em3a)*conj(r0515))/8. + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0705 - (Ep1a*r0711)/4. - (Ep4a*r0715)/(4.*rt6) - r0704*(WLx/2. - (i*WLy)/2.) + r0605*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0805*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0705*WLz);
+dr0706_dt = -(gt*r0706) + (g1*r1110)/12. + (g2*r1312)/(2.*rt2) + (g2*r1413)/(2.*rt3) + (g2*r1514)/(4.*rt3) - i*(-(conj(Ep2a)*conj(r0609))/(4.*rt6) + (conj(Em2a)*conj(r0611))/(4.*rt6) + (conj(Ep3a)*conj(r0613))/8. + (conj(Em3a)*conj(r0615))/8. + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0706 - (Em2a*r0710)/(4.*rt6) - (Ep3a*r0712)/(4.*rt2) - (Em3a*r0714)/(8.*rt3) + r0606*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0707*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0806*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - [...]
+dr0707_dt = gt/8. - gt*r0707 + (g1*r0909)/12. + (g1*r1111)/12. + (g2*r1313)/4. + (g2*r1414)/3. + (g2*r1515)/4. - i*(-(conj(Ep2a)*conj(r0709))/(4.*rt6) + (conj(Em2a)*conj(r0711))/(4.*rt6) + (conj(Ep3a)*conj(r0713))/8. + (conj(Em3a)*conj(r0715))/8. + (Ep2a*r0709)/(4.*rt6) - (Em2a*r0711)/(4.*rt6) - (Ep3a*r0713)/8. - (Em3a*r0715)/8. + conj(r0706)*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - conj(r0807)*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0706*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0807*(-WLx/(2.*rt [...]
+dr0709_dt = (-(gt*r0709) - (gt + g1)*r0709)/2. - i*((conj(Ep3a)*conj(r0913))/8. + (conj(Em3a)*conj(r0915))/8. - (conj(Em1a)*r0701)/4. - (conj(Ep1a)*r0703)/(4.*rt6) + (conj(Ep2a)*r0707)/(4.*rt6) + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0709 - (conj(Ep2a)*r0909)/(4.*rt6) + (conj(Em2a)*r1109)/(4.*rt6) + r0609*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0710*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) + r0809*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - r0709*(-delta1 - v*Kvec1 - WLz/6.));
+dr0710_dt = (-(gt*r0710) - (gt + g1)*r0710)/2. - i*((conj(Ep2a)*conj(r0807))/(4.*rt6) - (conj(Ep2a)*conj(r1009))/(4.*rt6) + (conj(Ep3a)*conj(r1013))/8. + (conj(Em3a)*conj(r1015))/8. - (conj(Em1a)*r0702)/(4.*rt2) - (conj(Ep1a)*r0704)/(4.*rt2) - (conj(Em2a)*r0706)/(4.*rt6) + (delta1 + v*Kvec1)*r0710 + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0710 + (conj(Em2a)*r1110)/(4.*rt6) + r0610*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0711*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0709*(-WLx/(6.*rt2) + (i*WL [...]
+dr0711_dt = (-(gt*r0711) - (gt + g1)*r0711)/2. - i*(-(conj(Ep2a)*conj(r1109))/(4.*rt6) + (conj(Ep3a)*conj(r1113))/8. + (conj(Em3a)*conj(r1115))/8. - (conj(Em1a)*r0703)/(4.*rt6) - (conj(Ep1a)*r0705)/4. - (conj(Em2a)*r0707)/(4.*rt6) + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0711 + (conj(Em2a)*r1111)/(4.*rt6) + r0611*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0710*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) + r0811*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - r0711*(-delta1 - v*Kvec1 + WLz/6.));
+dr0712_dt = (-(gt*r0712) - (gt + g2)*r0712)/2. - i*(-(conj(Ep4a)*r0702)/(4.*rt6) - (conj(Ep3a)*r0706)/(4.*rt2) + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0712 - (conj(Ep2a)*r0912)/(4.*rt6) + (conj(Em2a)*r1112)/(4.*rt6) + (conj(Ep3a)*r1312)/8. + (conj(Em3a)*r1512)/8. - r0713*((2*WLx)/3. + (2*i*WLy)/3.) + r0612*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0812*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - r0712*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr0713_dt = (-(gt*r0713) - (gt + g2)*r0713)/2. - i*((conj(Em4a)*r0701)/(4.*rt6) - (conj(Ep4a)*r0703)/8. - (conj(Ep3a)*r0707)/8. + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0713 - (conj(Ep2a)*r0913)/(4.*rt6) + (conj(Em2a)*r1113)/(4.*rt6) + (conj(Ep3a)*r1313)/8. + (conj(Em3a)*r1513)/8. - r0712*((2*WLx)/3. - (2*i*WLy)/3.) - r0714*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r0613*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0813*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - r0713*(-delta [...]
+dr0714_dt = (-(gt*r0714) - (gt + g2)*r0714)/2. - i*(-(conj(Ep3a)*conj(r0807))/(8.*rt3) + (conj(Ep3a)*conj(r1413))/8. + (conj(Em4a)*r0702)/8. - (conj(Ep4a)*r0704)/8. - (conj(Em3a)*r0706)/(8.*rt3) + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0714 - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r0714 - (conj(Ep2a)*r0914)/(4.*rt6) + (conj(Em2a)*r1114)/(4.*rt6) + (conj(Em3a)*r1514)/8. - r0713*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0715*(sqrt(0.666666666666 [...]
+dr0715_dt = (-(gt*r0715) - (gt + g2)*r0715)/2. - i*((conj(Ep3a)*conj(r1513))/8. + (conj(Em4a)*r0703)/8. - (conj(Ep4a)*r0705)/(4.*rt6) - (conj(Em3a)*r0707)/8. + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0715 - (conj(Ep2a)*r0915)/(4.*rt6) + (conj(Em2a)*r1115)/(4.*rt6) + (conj(Em3a)*r1515)/8. - r0716*((2*WLx)/3. + (2*i*WLy)/3.) - r0714*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r0615*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0815*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - r0715*( [...]
+dr0716_dt = (-(gt*r0716) - (gt + g2)*r0716)/2. - i*(-(conj(Em3a)*conj(r0807))/(4.*rt2) + (conj(Ep3a)*conj(r1613))/8. + (conj(Em3a)*conj(r1615))/8. + (conj(Em4a)*r0704)/(4.*rt6) + (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0716 - (conj(Ep2a)*r0916)/(4.*rt6) + (conj(Em2a)*r1116)/(4.*rt6) - r0715*((2*WLx)/3. - (2*i*WLy)/3.) + r0616*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0816*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) - r0716*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.));
+dr0801_dt = -(gt*r0801) - i*(-(conj(Ep2a)*conj(r0110))/(4.*rt6) + (conj(Ep3a)*conj(r0114))/(8.*rt3) + (conj(Em3a)*conj(r0116))/(4.*rt2) - (Em1a*r0809)/4. + (Em4a*r0813)/(4.*rt6) - r0802*(WLx/2. + (i*WLy)/2.) + r0701*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0801*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.) - r0801*WLz);
+dr0802_dt = -(gt*r0802) - i*(-(conj(Ep2a)*conj(r0210))/(4.*rt6) + (conj(Ep3a)*conj(r0214))/(8.*rt3) + (conj(Em3a)*conj(r0216))/(4.*rt2) - (Em1a*r0810)/(4.*rt2) - (Ep4a*r0812)/(4.*rt6) + (Em4a*r0814)/8. - r0801*(WLx/2. - (i*WLy)/2.) - r0803*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) + r0702*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0802*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.) - (r0802*WLz)/2.);
+dr0803_dt = -(gt*r0803) - i*(-(conj(Ep2a)*conj(r0310))/(4.*rt6) + (conj(Ep3a)*conj(r0314))/(8.*rt3) + (conj(Em3a)*conj(r0316))/(4.*rt2) - (Ep1a*r0809)/(4.*rt6) - (Em1a*r0811)/(4.*rt6) - (Ep4a*r0813)/8. + (Em4a*r0815)/8. - r0802*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) - r0804*((sqrt(1.5)*WLx)/2. + (sqrt(1.5)*i*WLy)/2.) + r0703*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0803*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.));
+dr0804_dt = -(gt*r0804) - i*(-(conj(Ep2a)*conj(r0410))/(4.*rt6) + (conj(Ep3a)*conj(r0414))/(8.*rt3) + (conj(Em3a)*conj(r0416))/(4.*rt2) - (Ep1a*r0810)/(4.*rt2) - (Ep4a*r0814)/8. + (Em4a*r0816)/(4.*rt6) - r0805*(WLx/2. + (i*WLy)/2.) - r0803*((sqrt(1.5)*WLx)/2. - (sqrt(1.5)*i*WLy)/2.) + r0704*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0804*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.) + (r0804*WLz)/2.);
+dr0805_dt = -(gt*r0805) - i*(-(conj(Ep2a)*conj(r0510))/(4.*rt6) + (conj(Ep3a)*conj(r0514))/(8.*rt3) + (conj(Em3a)*conj(r0516))/(4.*rt2) - (Ep1a*r0811)/4. - (Ep4a*r0815)/(4.*rt6) - r0804*(WLx/2. - (i*WLy)/2.) + r0705*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0805*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.) + r0805*WLz);
+dr0806_dt = -(gt*r0806) - (g1*r1109)/12. + (g2*r1412)/(2.*rt6) + (g2*r1513)/4. + (g2*r1614)/(2.*rt6) - i*(-(conj(Ep2a)*conj(r0610))/(4.*rt6) + (conj(Ep3a)*conj(r0614))/(8.*rt3) + (conj(Em3a)*conj(r0616))/(4.*rt2) - (Em2a*r0810)/(4.*rt6) - (Ep3a*r0812)/(4.*rt2) - (Em3a*r0814)/(8.*rt3) + r0706*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0807*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0806*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 - WLz/2.) + r0806*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.));
+dr0807_dt = -(gt*r0807) + (g1*r1009)/12. + (g2*r1413)/(4.*rt3) + (g2*r1514)/(2.*rt3) + (g2*r1615)/(2.*rt2) - i*(-(conj(Ep2a)*conj(r0710))/(4.*rt6) + (conj(Ep3a)*conj(r0714))/(8.*rt3) + (conj(Em3a)*conj(r0716))/(4.*rt2) - (-delta1 + delta2 - v*Kvec1 + v*Kvec2)*r0807 + (Ep2a*r0809)/(4.*rt6) - (Em2a*r0811)/(4.*rt6) - (Ep3a*r0813)/8. - (Em3a*r0815)/8. + r0707*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0808*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0806*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)) + r0807*(-del [...]
+dr0808_dt = gt/8. - gt*r0808 + (g1*r1010)/12. + (g1*r1111)/12. + (g2*r1414)/12. + (g2*r1515)/4. + (g2*r1616)/2. - i*(-(conj(Ep2a)*conj(r0810))/(4.*rt6) + (conj(Ep3a)*conj(r0814))/(8.*rt3) + (conj(Em3a)*conj(r0816))/(4.*rt2) + (Ep2a*r0810)/(4.*rt6) - (Ep3a*r0814)/(8.*rt3) - (Em3a*r0816)/(4.*rt2) + conj(r0807)*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0807*(-WLx/(2.*rt2) + (i*WLy)/(2.*rt2)));
+dr0809_dt = (-(gt*r0809) - (gt + g1)*r0809)/2. - i*((conj(Ep3a)*conj(r0914))/(8.*rt3) + (conj(Em3a)*conj(r0916))/(4.*rt2) - (conj(Em1a)*r0801)/4. - (conj(Ep1a)*r0803)/(4.*rt6) + (conj(Ep2a)*r0807)/(4.*rt6) - (conj(Ep2a)*r1009)/(4.*rt6) + r0709*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0810*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0809*(-delta1 - v*Kvec1 - WLz/6.) + r0809*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.));
+dr0810_dt = (-(gt*r0810) - (gt + g1)*r0810)/2. - i*((conj(Ep3a)*conj(r1014))/(8.*rt3) + (conj(Em3a)*conj(r1016))/(4.*rt2) - (conj(Em1a)*r0802)/(4.*rt2) - (conj(Ep1a)*r0804)/(4.*rt2) - (conj(Em2a)*r0806)/(4.*rt6) + (conj(Ep2a)*r0808)/(4.*rt6) + (delta1 + v*Kvec1)*r0810 - (conj(Ep2a)*r1010)/(4.*rt6) + r0710*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0811*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r0809*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) + r0810*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.));
+dr0811_dt = (-(gt*r0811) - (gt + g1)*r0811)/2. - i*(-(conj(Ep2a)*conj(r1110))/(4.*rt6) + (conj(Ep3a)*conj(r1114))/(8.*rt3) + (conj(Em3a)*conj(r1116))/(4.*rt2) - (conj(Em1a)*r0803)/(4.*rt6) - (conj(Ep1a)*r0805)/4. - (conj(Em2a)*r0807)/(4.*rt6) + r0711*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0810*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r0811*(-delta1 - v*Kvec1 + WLz/6.) + r0811*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.));
+dr0812_dt = (-(gt*r0812) - (gt + g2)*r0812)/2. - i*(-(conj(Ep4a)*r0802)/(4.*rt6) - (conj(Ep3a)*r0806)/(4.*rt2) - (conj(Ep2a)*r1012)/(4.*rt6) + (conj(Ep3a)*r1412)/(8.*rt3) + (conj(Em3a)*r1612)/(4.*rt2) - r0813*((2*WLx)/3. + (2*i*WLy)/3.) + r0712*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0812*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.) - r0812*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr0813_dt = (-(gt*r0813) - (gt + g2)*r0813)/2. - i*((conj(Em4a)*r0801)/(4.*rt6) - (conj(Ep4a)*r0803)/8. - (conj(Ep3a)*r0807)/8. - (conj(Ep2a)*r1013)/(4.*rt6) + (conj(Ep3a)*r1413)/(8.*rt3) + (conj(Em3a)*r1613)/(4.*rt2) - r0812*((2*WLx)/3. - (2*i*WLy)/3.) - r0814*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r0713*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) + r0813*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.) - r0813*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 +  [...]
+dr0814_dt = (-(gt*r0814) - (gt + g2)*r0814)/2. - i*((conj(Em4a)*r0802)/8. - (conj(Ep4a)*r0804)/8. - (conj(Em3a)*r0806)/(8.*rt3) - (conj(Ep3a)*r0808)/(8.*rt3) - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r0814 - (conj(Ep2a)*r1014)/(4.*rt6) + (conj(Ep3a)*r1414)/(8.*rt3) + (conj(Em3a)*r1614)/(4.*rt2) - r0813*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0815*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r0714*(-WLx/(2.*rt2) - (i*WLy)/( [...]
+dr0815_dt = (-(gt*r0815) - (gt + g2)*r0815)/2. - i*((conj(Ep3a)*conj(r1514))/(8.*rt3) + (conj(Em4a)*r0803)/8. - (conj(Ep4a)*r0805)/(4.*rt6) - (conj(Em3a)*r0807)/8. - (conj(Ep2a)*r1015)/(4.*rt6) + (conj(Em3a)*r1615)/(4.*rt2) - r0816*((2*WLx)/3. + (2*i*WLy)/3.) - r0814*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r0715*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0815*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (2*WLz)/3.) + r0815*(-delta1 + delta2 - v*Kvec1 +  [...]
+dr0816_dt = (-(gt*r0816) - (gt + g2)*r0816)/2. - i*((conj(Ep3a)*conj(r1614))/(8.*rt3) + (conj(Em4a)*r0804)/(4.*rt6) - (conj(Em3a)*r0808)/(4.*rt2) - (conj(Ep2a)*r1016)/(4.*rt6) + (conj(Em3a)*r1616)/(4.*rt2) - r0815*((2*WLx)/3. - (2*i*WLy)/3.) + r0716*(-WLx/(2.*rt2) - (i*WLy)/(2.*rt2)) - r0816*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) + r0816*(-delta1 + delta2 - v*Kvec1 + v*Kvec2 + WLz/2.));
+dr0909_dt = -((gt + g1)*r0909) - i*(-(conj(Em1a)*conj(r0109))/4. - (conj(Ep1a)*conj(r0309))/(4.*rt6) + (conj(Ep2a)*conj(r0709))/(4.*rt6) + (Em1a*r0109)/4. + (Ep1a*r0309)/(4.*rt6) - (Ep2a*r0709)/(4.*rt6) - conj(r1009)*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) + r1009*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)));
+dr0912_dt = (-((gt + g1)*r0912) - (gt + g2)*r0912)/2. - i*(-(conj(Ep4a)*conj(r0209))/(4.*rt6) - (conj(Ep3a)*conj(r0609))/(4.*rt2) + (Em1a*r0112)/4. + (Ep1a*r0312)/(4.*rt6) - (Ep2a*r0712)/(4.*rt6) - r0913*((2*WLx)/3. + (2*i*WLy)/3.) + r1012*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) + r0912*(-delta1 - v*Kvec1 - WLz/6.) - r0912*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr0913_dt = (-((gt + g1)*r0913) - (gt + g2)*r0913)/2. - i*((conj(Em4a)*conj(r0109))/(4.*rt6) - (conj(Ep4a)*conj(r0309))/8. - (conj(Ep3a)*conj(r0709))/8. + (Em1a*r0113)/4. + (Ep1a*r0313)/(4.*rt6) - (Ep2a*r0713)/(4.*rt6) - r0912*((2*WLx)/3. - (2*i*WLy)/3.) - r0914*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r1013*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) + r0913*(-delta1 - v*Kvec1 - WLz/6.) - r0913*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (2*WLz)/3.));
+dr0914_dt = (-((gt + g1)*r0914) - (gt + g2)*r0914)/2. - i*((conj(Em4a)*conj(r0209))/8. - (conj(Ep4a)*conj(r0409))/8. - (conj(Em3a)*conj(r0609))/(8.*rt3) - (conj(Ep3a)*conj(r0809))/(8.*rt3) + (Em1a*r0114)/4. + (Ep1a*r0314)/(4.*rt6) - (Ep2a*r0714)/(4.*rt6) - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r0914 - r0913*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r0915*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r1014*(-WLx/(6.*rt2) + (i [...]
+dr0915_dt = (-((gt + g1)*r0915) - (gt + g2)*r0915)/2. - i*((conj(Em4a)*conj(r0309))/8. - (conj(Ep4a)*conj(r0509))/(4.*rt6) - (conj(Em3a)*conj(r0709))/8. + (Em1a*r0115)/4. + (Ep1a*r0315)/(4.*rt6) - (Ep2a*r0715)/(4.*rt6) - r0916*((2*WLx)/3. + (2*i*WLy)/3.) - r0914*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r1015*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r0915*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (2*WLz)/3.) + r0915*(-delta1 - v*Kvec1 - WLz/6.));
+dr0916_dt = (-((gt + g1)*r0916) - (gt + g2)*r0916)/2. - i*((conj(Em4a)*conj(r0409))/(4.*rt6) - (conj(Em3a)*conj(r0809))/(4.*rt2) + (Em1a*r0116)/4. + (Ep1a*r0316)/(4.*rt6) - (Ep2a*r0716)/(4.*rt6) - r0915*((2*WLx)/3. - (2*i*WLy)/3.) + r1016*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r0916*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) + r0916*(-delta1 - v*Kvec1 - WLz/6.));
+dr1009_dt = -((gt + g1)*r1009) - i*(-(conj(Em1a)*conj(r0110))/4. - (conj(Ep1a)*conj(r0310))/(4.*rt6) + (conj(Ep2a)*conj(r0710))/(4.*rt6) + (Em1a*r0209)/(4.*rt2) + (Ep1a*r0409)/(4.*rt2) + (Em2a*r0609)/(4.*rt6) - (Ep2a*r0809)/(4.*rt6) - (delta1 + v*Kvec1)*r1009 + r0909*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r1010*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) + r1109*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r1009*(-delta1 - v*Kvec1 - WLz/6.));
+dr1010_dt = -((gt + g1)*r1010) - i*(-(conj(Em1a)*conj(r0210))/(4.*rt2) - (conj(Ep1a)*conj(r0410))/(4.*rt2) - (conj(Em2a)*conj(r0610))/(4.*rt6) + (conj(Ep2a)*conj(r0810))/(4.*rt6) + (Em1a*r0210)/(4.*rt2) + (Ep1a*r0410)/(4.*rt2) + (Em2a*r0610)/(4.*rt6) - (Ep2a*r0810)/(4.*rt6) + conj(r1009)*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - conj(r1110)*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r1009*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) + r1110*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)));
+dr1012_dt = (-((gt + g1)*r1012) - (gt + g2)*r1012)/2. - i*(-(conj(Ep4a)*conj(r0210))/(4.*rt6) - (conj(Ep3a)*conj(r0610))/(4.*rt2) + (Em1a*r0212)/(4.*rt2) + (Ep1a*r0412)/(4.*rt2) + (Em2a*r0612)/(4.*rt6) - (Ep2a*r0812)/(4.*rt6) - (delta1 + v*Kvec1)*r1012 - r1013*((2*WLx)/3. + (2*i*WLy)/3.) + r0912*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) + r1112*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r1012*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr1013_dt = (-((gt + g1)*r1013) - (gt + g2)*r1013)/2. - i*((conj(Em4a)*conj(r0110))/(4.*rt6) - (conj(Ep4a)*conj(r0310))/8. - (conj(Ep3a)*conj(r0710))/8. + (Em1a*r0213)/(4.*rt2) + (Ep1a*r0413)/(4.*rt2) + (Em2a*r0613)/(4.*rt6) - (Ep2a*r0813)/(4.*rt6) - (delta1 + v*Kvec1)*r1013 - r1012*((2*WLx)/3. - (2*i*WLy)/3.) - r1014*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r0913*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) + r1113*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r1013*(-delta1 + del [...]
+dr1014_dt = (-((gt + g1)*r1014) - (gt + g2)*r1014)/2. - i*((conj(Em4a)*conj(r0210))/8. - (conj(Ep4a)*conj(r0410))/8. - (conj(Em3a)*conj(r0610))/(8.*rt3) - (conj(Ep3a)*conj(r0810))/(8.*rt3) + (Em1a*r0214)/(4.*rt2) + (Ep1a*r0414)/(4.*rt2) + (Em2a*r0614)/(4.*rt6) - (Ep2a*r0814)/(4.*rt6) - (delta1 + v*Kvec1)*r1014 - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r1014 - r1013*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r1015*(sqrt(0.6666666666666666)*WLx + sq [...]
+dr1015_dt = (-((gt + g1)*r1015) - (gt + g2)*r1015)/2. - i*((conj(Em4a)*conj(r0310))/8. - (conj(Ep4a)*conj(r0510))/(4.*rt6) - (conj(Em3a)*conj(r0710))/8. + (Em1a*r0215)/(4.*rt2) + (Ep1a*r0415)/(4.*rt2) + (Em2a*r0615)/(4.*rt6) - (Ep2a*r0815)/(4.*rt6) - (delta1 + v*Kvec1)*r1015 - r1016*((2*WLx)/3. + (2*i*WLy)/3.) - r1014*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r0915*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) + r1115*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r1015*(-delta1 + del [...]
+dr1016_dt = (-((gt + g1)*r1016) - (gt + g2)*r1016)/2. - i*((conj(Em4a)*conj(r0410))/(4.*rt6) - (conj(Em3a)*conj(r0810))/(4.*rt2) + (Em1a*r0216)/(4.*rt2) + (Ep1a*r0416)/(4.*rt2) + (Em2a*r0616)/(4.*rt6) - (Ep2a*r0816)/(4.*rt6) - (delta1 + v*Kvec1)*r1016 - r1015*((2*WLx)/3. - (2*i*WLy)/3.) + r0916*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) + r1116*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) - r1016*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.));
+dr1109_dt = -((gt + g1)*r1109) - i*(-(conj(Em1a)*conj(r0111))/4. - (conj(Ep1a)*conj(r0311))/(4.*rt6) + (conj(Ep2a)*conj(r0711))/(4.*rt6) + (Em1a*r0309)/(4.*rt6) + (Ep1a*r0509)/4. + (Em2a*r0709)/(4.*rt6) + r1009*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r1110*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r1109*(-delta1 - v*Kvec1 - WLz/6.) + r1109*(-delta1 - v*Kvec1 + WLz/6.));
+dr1110_dt = -((gt + g1)*r1110) - i*(-(conj(Em1a)*conj(r0211))/(4.*rt2) - (conj(Ep1a)*conj(r0411))/(4.*rt2) - (conj(Em2a)*conj(r0611))/(4.*rt6) + (conj(Ep2a)*conj(r0811))/(4.*rt6) + (Em1a*r0310)/(4.*rt6) + (Ep1a*r0510)/4. + (Em2a*r0710)/(4.*rt6) + (delta1 + v*Kvec1)*r1110 + r1010*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r1111*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r1109*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)) + r1110*(-delta1 - v*Kvec1 + WLz/6.));
+dr1111_dt = -((gt + g1)*r1111) - i*(-(conj(Em1a)*conj(r0311))/(4.*rt6) - (conj(Ep1a)*conj(r0511))/4. - (conj(Em2a)*conj(r0711))/(4.*rt6) + (Em1a*r0311)/(4.*rt6) + (Ep1a*r0511)/4. + (Em2a*r0711)/(4.*rt6) + conj(r1110)*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r1110*(-WLx/(6.*rt2) + (i*WLy)/(6.*rt2)));
+dr1112_dt = (-((gt + g1)*r1112) - (gt + g2)*r1112)/2. - i*(-(conj(Ep4a)*conj(r0211))/(4.*rt6) - (conj(Ep3a)*conj(r0611))/(4.*rt2) + (Em1a*r0312)/(4.*rt6) + (Ep1a*r0512)/4. + (Em2a*r0712)/(4.*rt6) - r1113*((2*WLx)/3. + (2*i*WLy)/3.) + r1012*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) + r1112*(-delta1 - v*Kvec1 + WLz/6.) - r1112*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr1113_dt = (-((gt + g1)*r1113) - (gt + g2)*r1113)/2. - i*((conj(Em4a)*conj(r0111))/(4.*rt6) - (conj(Ep4a)*conj(r0311))/8. - (conj(Ep3a)*conj(r0711))/8. + (Em1a*r0313)/(4.*rt6) + (Ep1a*r0513)/4. + (Em2a*r0713)/(4.*rt6) - r1112*((2*WLx)/3. - (2*i*WLy)/3.) - r1114*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r1013*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) + r1113*(-delta1 - v*Kvec1 + WLz/6.) - r1113*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (2*WLz)/3.));
+dr1114_dt = (-((gt + g1)*r1114) - (gt + g2)*r1114)/2. - i*((conj(Em4a)*conj(r0211))/8. - (conj(Ep4a)*conj(r0411))/8. - (conj(Em3a)*conj(r0611))/(8.*rt3) - (conj(Ep3a)*conj(r0811))/(8.*rt3) + (Em1a*r0314)/(4.*rt6) + (Ep1a*r0514)/4. + (Em2a*r0714)/(4.*rt6) - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r1114 - r1113*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r1115*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r1014*(-WLx/(6.*rt2) - (i [...]
+dr1115_dt = (-((gt + g1)*r1115) - (gt + g2)*r1115)/2. - i*((conj(Em4a)*conj(r0311))/8. - (conj(Ep4a)*conj(r0511))/(4.*rt6) - (conj(Em3a)*conj(r0711))/8. + (Em1a*r0315)/(4.*rt6) + (Ep1a*r0515)/4. + (Em2a*r0715)/(4.*rt6) - r1116*((2*WLx)/3. + (2*i*WLy)/3.) - r1114*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r1015*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r1115*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (2*WLz)/3.) + r1115*(-delta1 - v*Kvec1 + WLz/6.));
+dr1116_dt = (-((gt + g1)*r1116) - (gt + g2)*r1116)/2. - i*((conj(Em4a)*conj(r0411))/(4.*rt6) - (conj(Em3a)*conj(r0811))/(4.*rt2) + (Em1a*r0316)/(4.*rt6) + (Ep1a*r0516)/4. + (Em2a*r0716)/(4.*rt6) - r1115*((2*WLx)/3. - (2*i*WLy)/3.) + r1016*(-WLx/(6.*rt2) - (i*WLy)/(6.*rt2)) - r1116*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) + r1116*(-delta1 - v*Kvec1 + WLz/6.));
+dr1212_dt = -((gt + g2)*r1212) - i*(-(conj(Ep4a)*conj(r0212))/(4.*rt6) - (conj(Ep3a)*conj(r0612))/(4.*rt2) + (Ep4a*r0212)/(4.*rt6) + (Ep3a*r0612)/(4.*rt2) + r1312*((2*WLx)/3. - (2*i*WLy)/3.) - conj(r1312)*((2*WLx)/3. + (2*i*WLy)/3.));
+dr1312_dt = -((gt + g2)*r1312) - i*(-(conj(Ep4a)*conj(r0213))/(4.*rt6) - (conj(Ep3a)*conj(r0613))/(4.*rt2) - (Em4a*r0112)/(4.*rt6) + (Ep4a*r0312)/8. + (Ep3a*r0712)/8. + r1212*((2*WLx)/3. + (2*i*WLy)/3.) - r1313*((2*WLx)/3. + (2*i*WLy)/3.) + r1412*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r1312*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (2*WLz)/3.) - r1312*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr1313_dt = -((gt + g2)*r1313) - i*((conj(Em4a)*conj(r0113))/(4.*rt6) - (conj(Ep4a)*conj(r0313))/8. - (conj(Ep3a)*conj(r0713))/8. - (Em4a*r0113)/(4.*rt6) + (Ep4a*r0313)/8. + (Ep3a*r0713)/8. - r1312*((2*WLx)/3. - (2*i*WLy)/3.) + conj(r1312)*((2*WLx)/3. + (2*i*WLy)/3.) + r1413*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - conj(r1413)*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy));
+dr1412_dt = -((gt + g2)*r1412) - i*(-(conj(Ep4a)*conj(r0214))/(4.*rt6) - (conj(Ep3a)*conj(r0614))/(4.*rt2) - (Em4a*r0212)/8. + (Ep4a*r0412)/8. + (Em3a*r0612)/(8.*rt3) + (Ep3a*r0812)/(8.*rt3) + (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r1412 - r1413*((2*WLx)/3. + (2*i*WLy)/3.) + r1512*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r1312*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) - r1412*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2  [...]
+dr1413_dt = -((gt + g2)*r1413) - i*((conj(Em4a)*conj(r0114))/(4.*rt6) - (conj(Ep4a)*conj(r0314))/8. - (conj(Ep3a)*conj(r0714))/8. - (Em4a*r0213)/8. + (Ep4a*r0413)/8. + (Em3a*r0613)/(8.*rt3) + (Ep3a*r0813)/(8.*rt3) + (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r1413 - r1412*((2*WLx)/3. - (2*i*WLy)/3.) + r1513*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r1313*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) - r1414*(sqrt(0.6666666666666666 [...]
+dr1414_dt = -((gt + g2)*r1414) - i*((conj(Em4a)*conj(r0214))/8. - (conj(Ep4a)*conj(r0414))/8. - (conj(Em3a)*conj(r0614))/(8.*rt3) - (conj(Ep3a)*conj(r0814))/(8.*rt3) - (Em4a*r0214)/8. + (Ep4a*r0414)/8. + (Em3a*r0614)/(8.*rt3) + (Ep3a*r0814)/(8.*rt3) - r1413*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r1514*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + conj(r1413)*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) - conj(r1514)*(sqrt( [...]
+dr1512_dt = -((gt + g2)*r1512) - i*(-(conj(Ep4a)*conj(r0215))/(4.*rt6) - (conj(Ep3a)*conj(r0615))/(4.*rt2) - (Em4a*r0312)/8. + (Ep4a*r0512)/(4.*rt6) + (Em3a*r0712)/8. + r1612*((2*WLx)/3. - (2*i*WLy)/3.) - r1513*((2*WLx)/3. + (2*i*WLy)/3.) + r1412*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r1512*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (2*WLz)/3.) - r1512*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr1513_dt = -((gt + g2)*r1513) - i*((conj(Em4a)*conj(r0115))/(4.*rt6) - (conj(Ep4a)*conj(r0315))/8. - (conj(Ep3a)*conj(r0715))/8. - (Em4a*r0313)/8. + (Ep4a*r0513)/(4.*rt6) + (Em3a*r0713)/8. - r1512*((2*WLx)/3. - (2*i*WLy)/3.) + r1613*((2*WLx)/3. - (2*i*WLy)/3.) + r1413*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) - r1514*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r1513*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (2*WLz)/3.) - r1513 [...]
+dr1514_dt = -((gt + g2)*r1514) - i*((conj(Em4a)*conj(r0215))/8. - (conj(Ep4a)*conj(r0415))/8. - (conj(Em3a)*conj(r0615))/(8.*rt3) - (conj(Ep3a)*conj(r0815))/(8.*rt3) - (Em4a*r0314)/8. + (Ep4a*r0514)/(4.*rt6) + (Em3a*r0714)/8. - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r1514 + r1614*((2*WLx)/3. - (2*i*WLy)/3.) - r1513*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r1414*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) - r1515*(sqrt(0.6666 [...]
+dr1515_dt = -((gt + g2)*r1515) - i*((conj(Em4a)*conj(r0315))/8. - (conj(Ep4a)*conj(r0515))/(4.*rt6) - (conj(Em3a)*conj(r0715))/8. - (Em4a*r0315)/8. + (Ep4a*r0515)/(4.*rt6) + (Em3a*r0715)/8. + r1615*((2*WLx)/3. - (2*i*WLy)/3.) - conj(r1615)*((2*WLx)/3. + (2*i*WLy)/3.) - r1514*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + conj(r1514)*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy));
+dr1612_dt = -((gt + g2)*r1612) - i*(-(conj(Ep4a)*conj(r0216))/(4.*rt6) - (conj(Ep3a)*conj(r0616))/(4.*rt2) - (Em4a*r0412)/(4.*rt6) + (Em3a*r0812)/(4.*rt2) + r1512*((2*WLx)/3. + (2*i*WLy)/3.) - r1613*((2*WLx)/3. + (2*i*WLy)/3.) + r1612*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) - r1612*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (4*WLz)/3.));
+dr1613_dt = -((gt + g2)*r1613) - i*((conj(Em4a)*conj(r0116))/(4.*rt6) - (conj(Ep4a)*conj(r0316))/8. - (conj(Ep3a)*conj(r0716))/8. - (Em4a*r0413)/(4.*rt6) + (Em3a*r0813)/(4.*rt2) - r1612*((2*WLx)/3. - (2*i*WLy)/3.) + r1513*((2*WLx)/3. + (2*i*WLy)/3.) - r1614*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r1613*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) - r1613*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 + (2*WLz)/3.));
+dr1614_dt = -((gt + g2)*r1614) - i*((conj(Em4a)*conj(r0216))/8. - (conj(Ep4a)*conj(r0416))/8. - (conj(Em3a)*conj(r0616))/(8.*rt3) - (conj(Ep3a)*conj(r0816))/(8.*rt3) - (Em4a*r0414)/(4.*rt6) + (Em3a*r0814)/(4.*rt2) - (-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3)*r1614 + r1514*((2*WLx)/3. + (2*i*WLy)/3.) - r1613*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) - r1615*(sqrt(0.6666666666666666)*WLx + sqrt(0.6666666666666666)*i*WLy) + r1614*(-delta1 + delta2 - delt [...]
+dr1615_dt = -((gt + g2)*r1615) - i*((conj(Em4a)*conj(r0316))/8. - (conj(Ep4a)*conj(r0516))/(4.*rt6) - (conj(Em3a)*conj(r0716))/8. - (Em4a*r0415)/(4.*rt6) + (Em3a*r0815)/(4.*rt2) + r1515*((2*WLx)/3. + (2*i*WLy)/3.) - r1616*((2*WLx)/3. + (2*i*WLy)/3.) - r1614*(sqrt(0.6666666666666666)*WLx - sqrt(0.6666666666666666)*i*WLy) + r1615*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (4*WLz)/3.) - r1615*(-delta1 + delta2 - delta3 - v*Kvec1 + v*Kvec2 - v*Kvec3 - (2*WLz)/3.));
+dr1616_dt = -((gt + g2)*r1616) - i*((conj(Em4a)*conj(r0416))/(4.*rt6) - (conj(Em3a)*conj(r0816))/(4.*rt2) - (Em4a*r0416)/(4.*rt6) + (Em3a*r0816)/(4.*rt2) - r1615*((2*WLx)/3. - (2*i*WLy)/3.) + conj(r1615)*((2*WLx)/3. + (2*i*WLy)/3.));
+//---------------- RbEquations.txt ends  ------------------
+                                        ]]>
+        </operator>
+                                <!--
+                                                         According to xmds2 docs operator kind="ip" should be faster
+                                                         but our codes runs about 5% to 10% slower with it.
+                                                         Maybe because we very close to the stiff condition so I use "ex" kind
+                                                         <operator kind="ip" constant="yes">
+                                         -->
+                                <operator kind="ex" constant="yes" type="imaginary">
+                                        <operator_names>Lt</operator_names>
+                                        <![CDATA[
+                                        Lt = -i/c*kt;
+                                        ]]>
+                                </operator>
+        <integration_vectors>E_field</integration_vectors>
+                                <dependencies>density_matrix</dependencies>
+                                <![CDATA[
+                                //read from Mathematica generated RbPropEquations.txt
+//---------------- RbPropEquations.txt starts ------------------
+dEp1_dz = -((i*Ndens*(rt2*conj(r0309) + rt6*(conj(r0410) + rt2*conj(r0511)))*eta1)/(rt2*rt6)) - Lt[Ep1];
+dEm1_dz = -((i*Ndens*(rt2*rt6*conj(r0109) + rt6*conj(r0210) + rt2*conj(r0311))*eta1)/(rt2*rt6)) - Lt[Em1];
+dEp2_dz = (i*Ndens*(conj(r0709) + conj(r0810))*eta1)/rt6 - Lt[Ep2];
+dEm2_dz = -((i*Ndens*(conj(r0610) + conj(r0711))*eta1)/rt6) - Lt[Em2];
+dEp3_dz = -((i*Ndens*(rt2*rt3*conj(r0612) + rt3*conj(r0713) + conj(r0814))*eta2)/rt3) - Lt[Ep3];
+dEm3_dz = -((i*Ndens*(conj(r0614) + rt3*(conj(r0715) + rt2*conj(r0816)))*eta2)/rt3) - Lt[Em3];
+dEp4_dz = -((i*Ndens*(rt2*conj(r0212) + rt3*conj(r0313) + rt3*conj(r0414) + rt2*conj(r0515))*eta2)/rt3) - Lt[Ep4];
+dEm4_dz = (i*Ndens*(rt2*conj(r0113) + rt3*conj(r0214) + rt3*conj(r0315) + rt2*conj(r0416))*eta2)/rt3 - Lt[Em4];
+//---------------- RbPropEquations.txt ends  ------------------
+                                ]]>
+                        </operators>
+                </integrate>
+        </sequence>
+
+
+
+        <!-- The output to generate -->
+        <output format="binary" filename="realistic_Rb_and_fields.xsil">
+                <group>
+      <sampling basis="t(1000) " initial_sample="yes">
+                                <dependencies>E_field_avgd</dependencies>
+                                <moments>Ip1_out Im1_out Ip2_out Im2_out Ip3_out Im3_out Ip4_out Im4_out</moments>
+                                <![CDATA[
+                                Ip1_out = mod2(Ep1a);
+                                Im1_out = mod2(Em1a);
+                                Ip2_out = mod2(Ep2a);
+                                Im2_out = mod2(Em2a);
+                                Ip3_out = mod2(Ep3a);
+                                Im3_out = mod2(Em3a);
+                                Ip4_out = mod2(Ep4a);
+                                Im4_out = mod2(Em4a);
+                                ]]>
+                        </sampling>
+                </group>
+        </output>
+
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+
+Variables that can be specified on the command line:
+  Command line argument Ep1o_field = 1.884956e+07
+  Command line argument Em1o_field = 1.884956e+07
+  Command line argument Ep2o_field = 3.141593e+05
+  Command line argument Em2o_field = 3.141593e+05
+  Command line argument Ep3o_field = 3.769911e+07
+  Command line argument Em3o_field = 3.769911e+07
+  Command line argument Ep4o_field = 6.283185e+04
+  Command line argument Em4o_field = 6.283185e+04
+  Command line argument delta1 = 0.000000e+00
+  Command line argument delta2 = 0.000000e+00
+  Command line argument delta3 = 0.000000e+00
+  Command line argument Pwidth = 1.000000e-07
+  Command line argument Lcell = 5.000000e-04
+  Command line argument Ndens = 1.000000e+15
+  Command line argument WLx = 0.000000e+00
+  Command line argument WLy = 0.000000e+00
+  Command line argument WLz = 0.000000e+00
+  Command line argument Temperature = 5.000000e+00
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>10</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+z t Ip1_out Im1_out Ip2_out Im2_out Ip3_out Im3_out Ip4_out Im4_out 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>2</Dim>
+    <Dim>1000</Dim>
+    <Dim>10</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+realistic_Rb_and_fields_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/features/realistic_Rb_and_fields_expected_mg0.dat b/testsuite/features/realistic_Rb_and_fields_expected_mg0.dat
new file mode 100644
index 0000000..98a1653
Binary files /dev/null and b/testsuite/features/realistic_Rb_and_fields_expected_mg0.dat differ
diff --git a/testsuite/features/runtime_paths.xmds b/testsuite/features/runtime_paths.xmds
new file mode 100644
index 0000000..066d253
--- /dev/null
+++ b/testsuite/features/runtime_paths.xmds
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <arguments>--pathCount 20</arguments>
+    <xsil_file name="runtime_paths.xsil" expected="runtime_paths_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>runtime_paths</name>
+  <author>Graham Dennis</author>
+  <description>
+    Pointless simulation checking that the number of paths can be specified at runtime
+  </description>
+  
+  <features>
+    <benchmark />
+    <fftw plan="exhaustive" />
+    <validation kind="run-time"/>
+    <globals>
+      <![CDATA[
+      integer pathIndex = 0;
+      ]]>
+    </globals>
+    <arguments>
+      <argument name="pathCount" type="integer" default_value="10"/>
+    </arguments>
+  </features>
+  
+  <driver name="multi-path" paths="pathCount" />
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <vector name="main" type="real">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = pathIndex++;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+  </sequence>
+  
+  <output format="hdf5">
+      <sampling_group initial_sample="yes">
+        <moments>phiR</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          phiR = phi;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/features/runtime_paths_expected.h5 b/testsuite/features/runtime_paths_expected.h5
new file mode 100644
index 0000000..2e973d8
Binary files /dev/null and b/testsuite/features/runtime_paths_expected.h5 differ
diff --git a/testsuite/features/runtime_paths_expected.xsil b/testsuite/features/runtime_paths_expected.xsil
new file mode 100644
index 0000000..c94b84d
--- /dev/null
+++ b/testsuite/features/runtime_paths_expected.xsil
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <arguments>--pathCount 20</arguments>
+    <xsil_file name="runtime_paths.xsil" expected="runtime_paths_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>runtime_paths</name>
+  <author>Graham Dennis</author>
+  <description>
+    Pointless simulation checking that the number of paths can be specified at runtime
+  </description>
+  
+  <features>
+    <benchmark />
+    <fftw plan="exhaustive" />
+    <validation kind="run-time"/>
+    <globals>
+      <![CDATA[
+      integer pathIndex = 0;
+      ]]>
+    </globals>
+    <arguments>
+      <argument name="pathCount" type="integer" default_value="10"/>
+    </arguments>
+  </features>
+  
+  <driver name="multi-path" paths="pathCount" />
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <vector name="main" type="real">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = pathIndex++;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+  </sequence>
+  
+  <output format="hdf5">
+      <sampling_group initial_sample="yes">
+        <moments>phiR</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          phiR = phi;
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+
+Variables that can be specified on the command line:
+  Command line argument pathCount = 20
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">0</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+mean_phiR stderr_phiR 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+runtime_paths_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/features/space in filename.xmds b/testsuite/features/space in filename.xmds
new file mode 100644
index 0000000..fab8a66
--- /dev/null
+++ b/testsuite/features/space in filename.xmds	
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <arguments>--time_factor 2.0 --size 25.0</arguments>
+    <xsil_file name="space in filename.xsil" expected="arguments_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>space in filename</name>
+  <author>Graham Dennis</author>
+  <description>
+    This is a modified version of arguments to check that we can have simulations with spaces in the name.
+    
+    Simple one-dimensional diffusion with a pointless second dimension thrown in for fun.
+    Uses arguments and argument preprocessing. Essentially the simulation "looks" the
+    same for any given "size", as the interval/etc is scaled to fit the interesting region.
+    The user may use width_scale, time_scale and ratio to zoom out and in...
+  </description>
+  
+  <features>
+    <benchmark />
+    <fftw plan="exhaustive" />
+    <validation kind="run-time"/>
+    <globals>
+      <![CDATA[
+      real minx;
+      real maxx;
+      real miny;
+      real maxy;
+      real width;
+      real time_interval;
+      ]]>
+    </globals>
+    <arguments>
+      <argument name="size" type="real" default_value="20.0"/>
+      <argument name="ratio" type="real" default_value="0.1"/>
+      <argument name="width_factor" type="real" default_value="1.0"/>
+      <argument name="time_factor" type="real" default_value="1.0"/>
+      <![CDATA[
+      minx = -0.5*size;
+      maxx = 0.5*size;
+      miny = -0.5*size*ratio;
+      maxy = 0.5*size*ratio;
+      width = 0.5*sqrt(0.5)*size*ratio*width_factor; // half the simulation size
+      // The time intersting stuff happens scales as width^2
+      time_interval = 20.0 * width*width * time_factor;
+      ]]>
+    </arguments>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="32"  domain="(minx, maxx)" />
+      <dimension name="y" lattice="128" domain="(miny, maxy)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y/(2*width*width));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <!-- This is an interesting simulation because using IP operators means there is NO error due to the algorithm (though there may be numerical error) -->
+    <integrate algorithm="RK4" interval="time_interval" steps="24">
+      <samples>24</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="x ky">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x(0) y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/geometry/integer_dimensions.xmds b/testsuite/geometry/integer_dimensions.xmds
new file mode 100644
index 0000000..5402284
--- /dev/null
+++ b/testsuite/geometry/integer_dimensions.xmds
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="integer_dimensions.xsil" expected="integer_dimensions_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>integer_dimensions</name>
+  <author>Graham Dennis</author>
+  <description>
+    xpdeint script to test integer dimensions.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" type="integer" lattice="5" domain="(0, 4)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" type="complex">
+    <components>
+      x
+    </components>
+    <initialisation>
+      <![CDATA[
+      x(j => j) = 1.0e-3;
+      x(j => 0) = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="60.0" steps="25000">
+      <samples>100</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        long j_minus_one = (j-1) % _lattice_j;
+        if (j_minus_one < 0)
+          j_minus_one += _lattice_j;
+        long j_plus_one  = (j+1) % _lattice_j;
+        dx_dt(j => j) = x(j => j)*(x(j => j_minus_one) - x(j => j_plus_one));
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="j" initial_sample="yes">
+        <moments>xR</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          xR = x.Re();
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/geometry/integer_dimensions_expected.xsil b/testsuite/geometry/integer_dimensions_expected.xsil
new file mode 100644
index 0000000..1add52d
--- /dev/null
+++ b/testsuite/geometry/integer_dimensions_expected.xsil
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="integer_dimensions.xsil" expected="integer_dimensions_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>integer_dimensions</name>
+  <author>Graham Dennis</author>
+  <description>
+    xpdeint script to test integer dimensions.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw version="none" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <integer_valued>
+        <dimension name="j" lattice="5" domain="(0, 4)" />
+      </integer_valued>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" type="complex">
+    <components>
+      x
+    </components>
+    <initialisation>
+      <![CDATA[
+      x[j] = 1.0e-3;
+      x[0] = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="60.0" steps="25000">
+      <samples>100</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        long j_minus_one = (j-1) % _lattice_j;
+        if (j_minus_one < 0)
+          j_minus_one += _lattice_j;
+        long j_plus_one  = (j+1) % _lattice_j;
+        dx_dt[j] = x[j]*(x[j_minus_one] - x[j_plus_one]);
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <dimension name="j" />
+        <moments>xR</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          xR = x;
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t j xR 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>101</Dim>
+    <Dim>5</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+integer_dimensions_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/geometry/integer_dimensions_expected_mg0.dat b/testsuite/geometry/integer_dimensions_expected_mg0.dat
new file mode 100644
index 0000000..9d4f370
Binary files /dev/null and b/testsuite/geometry/integer_dimensions_expected_mg0.dat differ
diff --git a/testsuite/geometry/integer_dimensions_reordered.xmds b/testsuite/geometry/integer_dimensions_reordered.xmds
new file mode 100644
index 0000000..c457a99
--- /dev/null
+++ b/testsuite/geometry/integer_dimensions_reordered.xmds
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="integer_dimensions_reordered.xsil" expected="integer_dimensions_reordered_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>integer_dimensions_reordered</name>
+  <author>Graham Dennis</author>
+  <description>
+    xpdeint script to test integer dimensions.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" type="integer" lattice="5" domain="(0, 4)" />
+      <dimension name="k" type="integer" lattice="7" domain="(-3, 3)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" type="complex">
+    <components>
+      x
+    </components>
+    <initialisation>
+      <![CDATA[
+      x(k => k, j => j) = 1.0e-3;
+      x(j => 0, k => k) = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="60.0" steps="25000">
+      <samples>100</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        long j_minus_one = (j-1) % _lattice_j;
+        if (j_minus_one < 0)
+          j_minus_one += _lattice_j;
+        long j_plus_one  = (j+1) % _lattice_j;
+        dx_dt(j => j) = x(j => j, k => k)*(x(j => j_minus_one) - x(j => j_plus_one));
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="j k(1)" initial_sample="yes">
+        <moments>xR</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          xR = x.Re();
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/geometry/integer_dimensions_reordered_expected.xsil b/testsuite/geometry/integer_dimensions_reordered_expected.xsil
new file mode 100644
index 0000000..b99b8fe
--- /dev/null
+++ b/testsuite/geometry/integer_dimensions_reordered_expected.xsil
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="integer_dimensions_reordered.xsil" expected="integer_dimensions_reordered_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>integer_dimensions_reordered</name>
+  <author>Graham Dennis</author>
+  <description>
+    xpdeint script to test integer dimensions.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw version="none" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <integer_valued>
+        <dimension name="j" lattice="5" domain="(0, 4)" />
+        <dimension name="k" lattice="7" domain="(-3, 3)" />
+      </integer_valued>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" type="complex">
+    <components>
+      x
+    </components>
+    <initialisation>
+      <![CDATA[
+      x[j, k] = 1.0e-3;
+      x[0, k] = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="60.0" steps="25000">
+      <samples>100</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        long j_minus_one = (j-1) % _lattice_j;
+        if (j_minus_one < 0)
+          j_minus_one += _lattice_j;
+        long j_plus_one  = (j+1) % _lattice_j;
+        dx_dt[j, k] = x[j, k]*(x[j_minus_one, k] - x[j_plus_one, k]);
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <dimension name="j" />
+        <moments>xR</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          xR = x;
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t j xR 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>101</Dim>
+    <Dim>5</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+integer_dimensions_reordered_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/geometry/integer_dimensions_reordered_expected_mg0.dat b/testsuite/geometry/integer_dimensions_reordered_expected_mg0.dat
new file mode 100644
index 0000000..9d4f370
Binary files /dev/null and b/testsuite/geometry/integer_dimensions_reordered_expected_mg0.dat differ
diff --git a/testsuite/geometry/nonlocal_edge_uniform_access.xmds b/testsuite/geometry/nonlocal_edge_uniform_access.xmds
new file mode 100644
index 0000000..957b9bf
--- /dev/null
+++ b/testsuite/geometry/nonlocal_edge_uniform_access.xmds
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="nonlocal_edge_uniform_access.xsil" expected="nonlocal_edge_uniform_access_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>nonlocal_edge_uniform_access</name>
+  <author>Graham Dennis</author>
+  <description>
+    Script to test accessing a uniform dimension at the left end point.
+    Based off of vibstring.xmds
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      const real T_mu = T/mu;
+      
+      const real xmax = _max_x;
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x- -1.0)*(x- -1.0))*exp(i*200*x);
+        uDot = u*i*200*sqrt(T_mu);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-5" interval="2e-3" steps="1000">
+      <samples>5</samples>
+      <operators>
+        <operator kind="ex" constant="no">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T_mu*kx*kx;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="hdf5">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp amp_left</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = mod2(u);
+          amp_left = mod2(u(x => -1));
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/geometry/nonlocal_edge_uniform_access_expected.h5 b/testsuite/geometry/nonlocal_edge_uniform_access_expected.h5
new file mode 100644
index 0000000..2ff1885
Binary files /dev/null and b/testsuite/geometry/nonlocal_edge_uniform_access_expected.h5 differ
diff --git a/testsuite/geometry/nonlocal_edge_uniform_access_expected.xsil b/testsuite/geometry/nonlocal_edge_uniform_access_expected.xsil
new file mode 100644
index 0000000..e83cd20
--- /dev/null
+++ b/testsuite/geometry/nonlocal_edge_uniform_access_expected.xsil
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="nonlocal_edge_uniform_access.xsil" expected="nonlocal_edge_uniform_access_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>nonlocal_edge_uniform_access</name>
+  <author>Graham Dennis</author>
+  <description>
+    Script to test accessing a uniform dimension at the left end point.
+    Based off of vibstring.xmds
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      const real T_mu = T/mu;
+      
+      const real xmax = _max_x;
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x- -1.0)*(x- -1.0))*exp(i*200*x);
+        uDot = u*i*200*sqrt(T_mu);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-5" interval="2e-3" steps="1000">
+      <samples>5</samples>
+      <operators>
+        <operator kind="ex" constant="no">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T_mu*kx*kx;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="hdf5">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp amp_left</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = mod2(u);
+          amp_left = mod2(u(x => -1));
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t x amp amp_left 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>6</Dim>
+    <Dim>256</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+nonlocal_edge_uniform_access_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/geometry/nonlocal_index_access.xmds b/testsuite/geometry/nonlocal_index_access.xmds
new file mode 100644
index 0000000..2b73a96
--- /dev/null
+++ b/testsuite/geometry/nonlocal_index_access.xmds
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="nonlocal_index_access.xsil" expected="nonlocal_index_access_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>nonlocal_index_access</name>
+  <author>Graham Dennis</author>
+  <description>
+    Script to test accessing a dimension at a point via an index (advanced feature).
+    Based off of vibstring.xmds
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      const real T_mu = T/mu;
+      
+      const real xmax = _max_x;
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x)*(x))*exp(i*200*x);
+        uDot = u*i*200*sqrt(T_mu);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-5" interval="2e-3" steps="1000">
+      <samples>5</samples>
+      <operators>
+        <operator kind="ex" constant="no">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T_mu*kx*kx;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="hdf5">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp amp_middle</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = mod2(u);
+          amp_middle = mod2(u(x_index => _lattice_x/2));
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/geometry/nonlocal_index_access_expected.h5 b/testsuite/geometry/nonlocal_index_access_expected.h5
new file mode 100644
index 0000000..45f82a8
Binary files /dev/null and b/testsuite/geometry/nonlocal_index_access_expected.h5 differ
diff --git a/testsuite/geometry/nonlocal_index_access_expected.xsil b/testsuite/geometry/nonlocal_index_access_expected.xsil
new file mode 100644
index 0000000..274d181
--- /dev/null
+++ b/testsuite/geometry/nonlocal_index_access_expected.xsil
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="nonlocal_index_access.xsil" expected="nonlocal_index_access_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>nonlocal_index_access</name>
+  <author>Graham Dennis</author>
+  <description>
+    Script to test accessing a dimension at a point via an index (advanced feature).
+    Based off of vibstring.xmds
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      const real T_mu = T/mu;
+      
+      const real xmax = _max_x;
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x)*(x))*exp(i*200*x);
+        uDot = u*i*200*sqrt(T_mu);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-5" interval="2e-3" steps="1000">
+      <samples>5</samples>
+      <operators>
+        <operator kind="ex" constant="no">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T_mu*kx*kx;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="hdf5">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp amp_middle</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = mod2(u);
+          amp_middle = mod2(u(x_index => _lattice_x/2));
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t x amp amp_middle 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>6</Dim>
+    <Dim>256</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+nonlocal_index_access_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/geometry/nonlocal_negative_uniform_access.xmds b/testsuite/geometry/nonlocal_negative_uniform_access.xmds
new file mode 100644
index 0000000..62472b1
--- /dev/null
+++ b/testsuite/geometry/nonlocal_negative_uniform_access.xmds
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="nonlocal_negative_uniform_access.xsil" expected="nonlocal_negative_uniform_access_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>nonlocal_negative_uniform_access</name>
+  <author>Graham Dennis</author>
+  <description>
+    Script to test accessing a symmetric uniform dimension backwards.
+    Based off of vibstring.xmds
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      const real T_mu = T/mu;
+      
+      const real xmax = _max_x;
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5))*exp(i*200*x);
+        uDot = u*i*200*sqrt(T_mu);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-5" interval="2e-3" steps="1000">
+      <samples>5</samples>
+      <operators>
+        <operator kind="ex" constant="no">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T_mu*kx*kx;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="hdf5">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp amp_reversed</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = mod2(u);
+          amp_reversed = mod2(u(x => -x));
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/geometry/nonlocal_negative_uniform_access_expected.h5 b/testsuite/geometry/nonlocal_negative_uniform_access_expected.h5
new file mode 100644
index 0000000..e37eb71
Binary files /dev/null and b/testsuite/geometry/nonlocal_negative_uniform_access_expected.h5 differ
diff --git a/testsuite/geometry/nonlocal_negative_uniform_access_expected.xsil b/testsuite/geometry/nonlocal_negative_uniform_access_expected.xsil
new file mode 100644
index 0000000..056dd1c
--- /dev/null
+++ b/testsuite/geometry/nonlocal_negative_uniform_access_expected.xsil
@@ -0,0 +1,102 @@
+<?xml version="1.0" ?><simulation xmds-version="2">
+  <testing>
+    <xsil_file absolute_tolerance="1e-6" expected="nonlocal_negative_uniform_access_expected.xsil" name="nonlocal_negative_uniform_access.xsil" relative_tolerance="1e-5"/>
+  </testing>
+  
+  <name>nonlocal_negative_uniform_access</name>
+  <author>Graham Dennis</author>
+  <description>
+    Script to test accessing a symmetric uniform dimension backwards.
+    Based off of vibstring.xmds
+  </description>
+  
+  <features>
+    <benchmark/>
+    <bing/>
+    <fftw plan="patient"/>
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      const real T_mu = T/mu;
+      
+      const real xmax = _max_x;
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension domain="(-1, 1)" lattice="256" name="x"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector initial_basis="x" name="main" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5))*exp(i*200*x);
+        uDot = u*i*200*sqrt(T_mu);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="2e-3" steps="1000" tolerance="1e-5">
+      <samples>5</samples>
+      <operators>
+        <operator constant="no" kind="ex">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T_mu*kx*kx;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="hdf5">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp amp_reversed</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = mod2(u);
+          amp_reversed = mod2(u(x => -x));
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t x amp amp_reversed 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>6</Dim>
+    <Dim>256</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+nonlocal_negative_uniform_access_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/geometry/nonlocal_split_uniform_access.xmds b/testsuite/geometry/nonlocal_split_uniform_access.xmds
new file mode 100644
index 0000000..0baac64
--- /dev/null
+++ b/testsuite/geometry/nonlocal_split_uniform_access.xmds
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="nonlocal_split_uniform_access.xsil" expected="nonlocal_split_uniform_access_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>nonlocal_split_uniform_access</name>
+  <author>Graham Dennis</author>
+  <description>
+    Script to test accessing a fourier-transformed dimension backwards.
+    Based off of vibstring.xmds
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      const real T_mu = T/mu;
+      
+      const real xmax = _max_x;
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5))*exp(i*200*x);
+        uDot = u*i*200*sqrt(T_mu);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-5" interval="2e-3" steps="1000">
+      <samples>5</samples>
+      <operators>
+        <operator kind="ex" constant="no">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T_mu*kx*kx;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="kx" initial_sample="yes">
+        <moments>amp amp_reversed</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = mod2(u);
+          amp_reversed = mod2(u(kx => -kx));
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/geometry/nonlocal_split_uniform_access_expected.xsil b/testsuite/geometry/nonlocal_split_uniform_access_expected.xsil
new file mode 100644
index 0000000..95eac53
--- /dev/null
+++ b/testsuite/geometry/nonlocal_split_uniform_access_expected.xsil
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="nonlocal_split_uniform_access.xsil" expected="nonlocal_split_uniform_access_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>nonlocal_split_uniform_access</name>
+  <author>Graham Dennis</author>
+  <description>
+    Script to test accessing a fourier-transformed dimension backwards.
+    Based off of vibstring.xmds
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <globals>
+      <![CDATA[
+      const double T = 10.0;
+      const double mass = 1e-3;
+      const double length = 1.0;
+      const double mu = mass/length;
+      const double T_mu = T/mu;
+      
+      const double xmax = _max_x;
+      const double width = 0.1;
+      const double absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5))*c_exp(i*200*x);
+        uDot = u*i*200*sqrt(T_mu);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-5" interval="2e-3" steps="1000">
+      <samples>5</samples>
+      <operators>
+        <operator kind="ex" constant="no">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T_mu*kx*kx;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <dimension name="x" fourier_space="yes" lattice="256" />
+        <moments>amp amp_reversed</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = mod2(u);
+          amp_reversed = mod2(u(kx: -kx));
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t kx amp amp_reversed 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>6</Dim>
+    <Dim>256</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+nonlocal_split_uniform_access_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/geometry/nonlocal_split_uniform_access_expected_mg0.dat b/testsuite/geometry/nonlocal_split_uniform_access_expected_mg0.dat
new file mode 100644
index 0000000..03f4482
Binary files /dev/null and b/testsuite/geometry/nonlocal_split_uniform_access_expected_mg0.dat differ
diff --git a/testsuite/integrators/bug_adaptive_timestep_hang.xmds b/testsuite/integrators/bug_adaptive_timestep_hang.xmds
new file mode 100644
index 0000000..c8c3f11
--- /dev/null
+++ b/testsuite/integrators/bug_adaptive_timestep_hang.xmds
@@ -0,0 +1,252 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="bug_adaptive_timestep_hang.xsil" expected="bug_adaptive_timestep_hang_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5">
+      <moment_group number="1" absolute_tolerance="1e-4" relative_tolerance="1e-3" />
+      <moment_group number="2" absolute_tolerance="1e-4" relative_tolerance="1e-6" />
+      <moment_group number="3" absolute_tolerance="1e-4" relative_tolerance="1e-6" />
+    </xsil_file>
+  </testing>
+
+  <name>bug_adaptive_timestep_hang</name>
+
+  <author>Mattias Johnsson</author>
+  <description>
+    GPE simulation of an Rb85 BEC in a harmonic trap. In the ground state
+    (F=2, mf=2) we have U=0. We then flip a portion into the F=3 state.
+    Here the scattering length is ~400a0. No one knows that the inter-state
+    scattering length is. Wait a while, then flip it back.
+    What happens? 
+
+    We make use of cylindrical trapping frequencies, so assume omega_x=omega_y = omega_r.
+    That is, system is invariant under rotation around z. To do this we
+    use Hankel transforms instead of Fourier transforms, and describe the
+    (x,y) coords in (r, theta) = (r). That is, use a Bessel basis rather than a
+    Catesian one.
+
+    This means our 2D sim is fully accurate and there's no dimensional reductional
+    crap to deal with, i.e. we we don't have to scale the nonlinearities.
+
+    Note that the equations are done in a rotating frame to remove the Uab/2/dV
+    vacuum correction, i.e. I'm using the tilde variables in
+    a = atilde exp(i t/hbar Uab/2/dV )
+    so keep this in mind when looking at expectation value terms that don't consist
+    of equal numbers of daggered and non-daggered operators. See p1596 for details.
+  </description>
+
+  <features>
+      <benchmark />
+      <bing />
+      <fftw plan="patient" />
+      <auto_vectorise />
+      <globals>
+          <![CDATA[
+          const double hbar = 1.054e-34;
+          const double amu = 1.660539e-27;
+          const double mass = 84.912 * amu;              // Rb 85
+          //const double mass = 86.909 * amu;            // Rb 87
+
+          const double Omega = 2.0 * M_PI * 1.25e5;                      // Coupling Rabi frequency, move 1/2 population in 1us
+          //const double Omega = 3.06278e5;                      // Coupling Rabi frequency, move 1/11 population in 1us
+          //const double Omega = 3.2175e5;                      // Coupling Rabi frequency, move 1/10 population in 1us
+          
+          const double omega_r = 2.0 * M_PI * 50.0;
+          const double omega_z = 2.0 * M_PI * 30.0;
+          const double sr = sqrt(hbar/mass/omega_r);
+          const double sz = sqrt(hbar/mass/omega_z);
+
+          const double N0 = 5e4; 
+
+          const double a0 = 5.2918e-11;                   // Bohr radius
+          const double a3d_initial = 400.0 * a0;
+          const double a3d_00 = 400.0 * a0;
+          const double a3d_10 = 0.0 * a0;
+          const double a3d_11 = 400.0 * a0;
+
+          const double U3d_initial = 4.0*M_PI*hbar*hbar*a3d_initial/mass;
+          const double U3d_00 = 4.0*M_PI*hbar*hbar*a3d_00/mass;
+          const double U3d_10 = 4.0*M_PI*hbar*hbar*a3d_10/mass;
+          const double U3d_11 = 4.0*M_PI*hbar*hbar*a3d_11/mass;
+ 
+          const double BSPhase = 0.2;
+
+          const double mu3d_initial = pow(15.0 * pow(mass,1.5) * omega_r*omega_r*omega_z*N0*U3d_initial/16.0/sqrt(2.0)/M_PI, 0.4);
+
+          ]]>
+       </globals>
+     </features>
+
+<!--  <driver name="mpi-multi-path" paths="1000" /> -->
+
+  <geometry>
+      <propagation_dimension> t </propagation_dimension>
+      <transverse_dimensions>
+        <!-- For TF ground state -->
+        <dimension name="r" lattice="32"  domain="(0, 16e-6)" transform="bessel" volume_prefactor="2*M_PI" />
+        <dimension name="z" lattice="64"  domain="(-24e-6, 24e-6)" />
+
+      </transverse_dimensions>
+   </geometry>
+
+  <noise_vector name="initnoise" kind="gaussian" method="dsfmt" type="complex" seed="667813208 116090193 819982544">
+    <components>n_1 n_2</components>
+  </noise_vector>
+
+  <vector name="wavefunction" type="complex" dimensions="r z">
+    <components> psi0 psi1 </components>
+
+<!-- Initialisation by function -->
+    <initialisation>
+      <dependencies>initnoise</dependencies>
+      <![CDATA[
+        // ground state HO
+        //psi0 = sqrt(N0) * 1/sqrt(sr*sr*sz) * pow(M_PI,-0.75) * exp(-0.5*(r*r/sr/sr + z*z/sz/sz)) + n_1/sqrt(2.0);
+        // Ground state Thomas-Fermi
+        if (mu3d_initial-0.5*mass*(omega_r*omega_r*r*r + omega_z*omega_z*z*z) >=0 ) {
+          psi0 = sqrt(2)*sqrt(mu3d_initial-0.5*mass*(omega_r*omega_r*r*r + omega_z*omega_z*z*z))/sqrt(U3d_initial) + n_1/sqrt(2.0);
+        } else {
+           psi0 = n_1/sqrt(2.0);
+        }      
+        psi1 = n_2 /sqrt(2.0);
+
+        //printf("mu=%e; U3d_initial=%e;   ",mu3d_initial,U3d_initial);
+      ]]>
+    </initialisation>
+
+  </vector>
+
+  <vector name="potential" type="real" dimensions="r z">
+    <components> V </components>
+    <initialisation>
+      <![CDATA[
+        V = 0.5 * mass * (omega_r*omega_r*r*r + omega_z*omega_z*z*z);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <computed_vector name="particle_number" dimensions="" type="real">
+    <!-- The point of this computed vector is that we need access to the 
+         quantity number^2. A standard moment group will give us number by
+         integrating the density field, but it can't then square the result.
+         To get around this we calcuate the number in a CV, and then square
+         that result in the samping_group output. 
+  
+         Also note that the stochatic averaging happens *after* this is done.
+         We stochatically average (number squared).
+     -->
+    <components>
+      computed_number0 computed_number1
+    </components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        computed_number0 = mod2(psi0) - 0.5/dr/dz ;
+        computed_number1 = mod2(psi1) - 0.5/dr/dz ;
+      ]]>
+    </evaluation>
+  </computed_vector>
+
+  <sequence>
+
+    <!--  first beam splitter -->
+    <integrate algorithm="ARK45" interval="1e-6" tolerance="1e-7">
+      <samples> 10 10 10 </samples>
+      <operators>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <operator kind="ip" type="imaginary" >
+          <operator_names>Ltt</operator_names>
+          <![CDATA[
+            Ltt = -i*0.5*hbar*(kr*kr + kz*kz)/mass;
+          ]]>
+        </operator>
+        <![CDATA[
+
+          dpsi0_dt = Ltt[psi0] - i/hbar * (V) * psi0 - i*Omega*psi1;
+          dpsi1_dt = Ltt[psi1] - i/hbar * (V) * psi1 - i*Omega*psi0;
+          
+        ]]>
+      </operators>
+    </integrate>
+
+    <!-- First hold time -->
+    <integrate algorithm="ARK45" interval="4e-4" tolerance="1e-7">
+      <samples>  10 10 10 </samples>
+      <operators>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <operator kind="ip" constant="yes" type="imaginary" >
+          <operator_names>Ltt</operator_names>
+          <![CDATA[
+            Ltt = -i*0.5*hbar*(kr*kr + kz*kz)/mass;
+          ]]>
+        </operator>
+        <![CDATA[
+
+          dpsi0_dt = Ltt[psi0] - i/hbar * (V + U3d_00*(mod2(psi0)-1.0/dr/dz) + U3d_10*(mod2(psi1)-0.5/dr/dz)) * psi0;
+          dpsi1_dt = Ltt[psi1] - i/hbar * (V + U3d_11*(mod2(psi1)-1.0/dr/dz) + U3d_10*(mod2(psi0)-0.5/dr/dz)) * psi1;
+
+        ]]>
+      </operators>
+    </integrate>
+
+    <!-- And now the final beam splitter integration -->
+    <integrate algorithm="ARK45" interval="2e-6" tolerance="1e-7">
+      <samples> 10 10 50 </samples>
+      <operators>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <operator kind="ip" constant="yes" type="imaginary" >
+          <operator_names>Ltt</operator_names>
+          <![CDATA[
+            Ltt = -i*0.5*hbar*(kr*kr + kz*kz)/mass;
+          ]]>
+        </operator>
+        <![CDATA[
+
+          dpsi0_dt = Ltt[psi0] - i/hbar * (V ) * psi0 - i*exp(i*BSPhase)*Omega*psi1;
+          dpsi1_dt = Ltt[psi1] - i/hbar * (V ) * psi1 - i*exp(-i*BSPhase)*Omega*psi0;
+
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+
+  <output>
+      <sampling_group basis="r(0) z(0)" initial_sample="yes">
+        <moments>psi0real psi0imag psi1real psi1imag density0 density1 </moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          psi0real = psi0.Re();
+          psi0imag = psi0.Im();
+          psi1real = psi1.Re();
+          psi1imag = psi1.Im();
+          density0 = mod2(psi0) - 0.5/dz/dr;
+          density1 = mod2(psi1) - 0.5/dz/dr;
+        ]]>
+      </sampling_group>
+
+      <sampling_group basis="kr(0) kz(0)" initial_sample="yes">
+        <moments> density0k density1k </moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          density0k = mod2(psi0)- 0.5/dkz/dkr;
+          density1k = mod2(psi1)- 0.5/dkz/dkr;
+        ]]>
+      </sampling_group>
+
+      <sampling_group basis="r(1) z(1)" initial_sample="yes">
+        <moments> number0 number1 number0squared number1squared </moments>
+        <dependencies>wavefunction particle_number </dependencies>
+        <![CDATA[
+          number0 = computed_number0;
+          number1 = computed_number1;
+          number0squared = computed_number0 * computed_number0 - _lattice_r*_lattice_z/4.0;
+          number1squared = computed_number1 * computed_number1 - _lattice_r*_lattice_z/4.0;
+        ]]>
+      </sampling_group>
+
+
+  </output>
+</simulation>
+
diff --git a/testsuite/integrators/bug_adaptive_timestep_hang_expected.h5 b/testsuite/integrators/bug_adaptive_timestep_hang_expected.h5
new file mode 100644
index 0000000..096f0bb
Binary files /dev/null and b/testsuite/integrators/bug_adaptive_timestep_hang_expected.h5 differ
diff --git a/testsuite/integrators/bug_adaptive_timestep_hang_expected.xsil b/testsuite/integrators/bug_adaptive_timestep_hang_expected.xsil
new file mode 100644
index 0000000..bbc5a38
--- /dev/null
+++ b/testsuite/integrators/bug_adaptive_timestep_hang_expected.xsil
@@ -0,0 +1,310 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="bug_adaptive_timestep_hang.xsil" expected="bug_adaptive_timestep_hang_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5">
+      <moment_group number="1" absolute_tolerance="1e-4" relative_tolerance="1e-6" />
+      <moment_group number="2" absolute_tolerance="1e-4" relative_tolerance="1e-6" />
+      <moment_group number="3" absolute_tolerance="1e-4" relative_tolerance="1e-6" />
+    </xsil_file>
+  </testing>
+
+  <name>bug_adaptive_timestep_hang</name>
+
+  <author>Mattias Johnsson</author>
+  <description>
+    GPE simulation of an Rb85 BEC in a harmonic trap. In the ground state
+    (F=2, mf=2) we have U=0. We then flip a portion into the F=3 state.
+    Here the scattering length is ~400a0. No one knows that the inter-state
+    scattering length is. Wait a while, then flip it back.
+    What happens? 
+
+    We make use of cylindrical trapping frequencies, so assume omega_x=omega_y = omega_r.
+    That is, system is invariant under rotation around z. To do this we
+    use Hankel transforms instead of Fourier transforms, and describe the
+    (x,y) coords in (r, theta) = (r). That is, use a Bessel basis rather than a
+    Catesian one.
+
+    This means our 2D sim is fully accurate and there's no dimensional reductional
+    crap to deal with, i.e. we we don't have to scale the nonlinearities.
+
+    Note that the equations are done in a rotating frame to remove the Uab/2/dV
+    vacuum correction, i.e. I'm using the tilde variables in
+    a = atilde exp(i t/hbar Uab/2/dV )
+    so keep this in mind when looking at expectation value terms that don't consist
+    of equal numbers of daggered and non-daggered operators. See p1596 for details.
+  </description>
+
+  <features>
+      <benchmark />
+      <bing />
+      <fftw plan="patient" />
+      <auto_vectorise />
+      <globals>
+          <![CDATA[
+          const double hbar = 1.054e-34;
+          const double amu = 1.660539e-27;
+          const double mass = 84.912 * amu;              // Rb 85
+          //const double mass = 86.909 * amu;            // Rb 87
+
+          const double Omega = 2.0 * M_PI * 1.25e5;                      // Coupling Rabi frequency, move 1/2 population in 1us
+          //const double Omega = 3.06278e5;                      // Coupling Rabi frequency, move 1/11 population in 1us
+          //const double Omega = 3.2175e5;                      // Coupling Rabi frequency, move 1/10 population in 1us
+          
+          const double omega_r = 2.0 * M_PI * 50.0;
+          const double omega_z = 2.0 * M_PI * 30.0;
+          const double sr = sqrt(hbar/mass/omega_r);
+          const double sz = sqrt(hbar/mass/omega_z);
+
+          const double N0 = 5e4; 
+
+          const double a0 = 5.2918e-11;                   // Bohr radius
+          const double a3d_initial = 400.0 * a0;
+          const double a3d_00 = 400.0 * a0;
+          const double a3d_10 = 0.0 * a0;
+          const double a3d_11 = 400.0 * a0;
+
+          const double U3d_initial = 4.0*M_PI*hbar*hbar*a3d_initial/mass;
+          const double U3d_00 = 4.0*M_PI*hbar*hbar*a3d_00/mass;
+          const double U3d_10 = 4.0*M_PI*hbar*hbar*a3d_10/mass;
+          const double U3d_11 = 4.0*M_PI*hbar*hbar*a3d_11/mass;
+ 
+          const double BSPhase = 0.2;
+
+          const double mu3d_initial = pow(15.0 * pow(mass,1.5) * omega_r*omega_r*omega_z*N0*U3d_initial/16.0/sqrt(2.0)/M_PI, 0.4);
+
+          ]]>
+       </globals>
+     </features>
+
+<!--  <driver name="mpi-multi-path" paths="1000" /> -->
+
+  <geometry>
+      <propagation_dimension> t </propagation_dimension>
+      <transverse_dimensions>
+        <!-- For TF ground state -->
+        <dimension name="r" lattice="32"  domain="(0, 16e-6)" transform="bessel" volume_prefactor="2*M_PI" />
+        <dimension name="z" lattice="64"  domain="(-24e-6, 24e-6)" />
+
+      </transverse_dimensions>
+   </geometry>
+
+  <noise_vector name="initnoise" kind="gaussian" method="dsfmt" type="complex">
+    <components>n_1 n_2</components>
+  </noise_vector>
+
+  <vector name="wavefunction" type="complex" dimensions="r z">
+    <components> psi0 psi1 </components>
+
+<!-- Initialisation by function -->
+    <initialisation>
+      <dependencies>initnoise</dependencies>
+      <![CDATA[
+        // ground state HO
+        //psi0 = sqrt(N0) * 1/sqrt(sr*sr*sz) * pow(M_PI,-0.75) * exp(-0.5*(r*r/sr/sr + z*z/sz/sz)) + n_1/sqrt(2.0);
+        // Ground state Thomas-Fermi
+        if (mu3d_initial-0.5*mass*(omega_r*omega_r*r*r + omega_z*omega_z*z*z) >=0 ) {
+          psi0 = sqrt(2)*sqrt(mu3d_initial-0.5*mass*(omega_r*omega_r*r*r + omega_z*omega_z*z*z))/sqrt(U3d_initial) + n_1/sqrt(2.0);
+        } else {
+           psi0 = n_1/sqrt(2.0);
+        }      
+        psi1 = n_2 /sqrt(2.0);
+
+        //printf("mu=%e; U3d_initial=%e;   ",mu3d_initial,U3d_initial);
+      ]]>
+    </initialisation>
+
+  </vector>
+
+  <vector name="potential" type="real" dimensions="r z">
+    <components> V </components>
+    <initialisation>
+      <![CDATA[
+        V = 0.5 * mass * (omega_r*omega_r*r*r + omega_z*omega_z*z*z);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <computed_vector name="particle_number" dimensions="" type="real">
+    <!-- The point of this computed vector is that we need access to the 
+         quantity number^2. A standard moment group will give us number by
+         integrating the density field, but it can't then square the result.
+         To get around this we calcuate the number in a CV, and then square
+         that result in the samping_group output. 
+  
+         Also note that the stochatic averaging happens *after* this is done.
+         We stochatically average (number squared).
+     -->
+    <components>
+      computed_number0 computed_number1
+    </components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        computed_number0 = mod2(psi0) - 0.5/dr/dz ;
+        computed_number1 = mod2(psi1) - 0.5/dr/dz ;
+      ]]>
+    </evaluation>
+  </computed_vector>
+
+  <sequence>
+
+    <!--  first beam splitter -->
+    <integrate algorithm="ARK45" interval="1e-6" tolerance="1e-7">
+      <samples> 10 10 10 </samples>
+      <operators>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <operator kind="ip" type="imaginary" >
+          <operator_names>Ltt</operator_names>
+          <![CDATA[
+            Ltt = -i*0.5*hbar*(kr*kr + kz*kz)/mass;
+          ]]>
+        </operator>
+        <![CDATA[
+
+          dpsi0_dt = Ltt[psi0] - i/hbar * (V) * psi0 - i*Omega*psi1;
+          dpsi1_dt = Ltt[psi1] - i/hbar * (V) * psi1 - i*Omega*psi0;
+          
+        ]]>
+      </operators>
+    </integrate>
+
+    <!-- First hold time -->
+    <integrate algorithm="ARK45" interval="4e-4" tolerance="1e-7">
+      <samples>  10 10 10 </samples>
+      <operators>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <operator kind="ip" constant="yes" type="imaginary" >
+          <operator_names>Ltt</operator_names>
+          <![CDATA[
+            Ltt = -i*0.5*hbar*(kr*kr + kz*kz)/mass;
+          ]]>
+        </operator>
+        <![CDATA[
+
+          dpsi0_dt = Ltt[psi0] - i/hbar * (V + U3d_00*(mod2(psi0)-1.0/dr/dz) + U3d_10*(mod2(psi1)-0.5/dr/dz)) * psi0;
+          dpsi1_dt = Ltt[psi1] - i/hbar * (V + U3d_11*(mod2(psi1)-1.0/dr/dz) + U3d_10*(mod2(psi0)-0.5/dr/dz)) * psi1;
+
+        ]]>
+      </operators>
+    </integrate>
+
+    <!-- And now the final beam splitter integration -->
+    <integrate algorithm="ARK45" interval="2e-6" tolerance="1e-7">
+      <samples> 10 10 50 </samples>
+      <operators>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <operator kind="ip" constant="yes" type="imaginary" >
+          <operator_names>Ltt</operator_names>
+          <![CDATA[
+            Ltt = -i*0.5*hbar*(kr*kr + kz*kz)/mass;
+          ]]>
+        </operator>
+        <![CDATA[
+
+          dpsi0_dt = Ltt[psi0] - i/hbar * (V ) * psi0 - i*exp(i*BSPhase)*Omega*psi1;
+          dpsi1_dt = Ltt[psi1] - i/hbar * (V ) * psi1 - i*exp(-i*BSPhase)*Omega*psi0;
+
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+
+  <output>
+      <sampling_group basis="r(0) z(0)" initial_sample="yes">
+        <moments>psi0real psi0imag psi1real psi1imag density0 density1 </moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          psi0real = psi0.Re();
+          psi0imag = psi0.Im();
+          psi1real = psi1.Re();
+          psi1imag = psi1.Im();
+          density0 = mod2(psi0) - 0.5/dz/dr;
+          density1 = mod2(psi1) - 0.5/dz/dr;
+        ]]>
+      </sampling_group>
+
+      <sampling_group basis="kr(0) kz(0)" initial_sample="yes">
+        <moments> density0k density1k </moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          density0k = mod2(psi0)- 0.5/dkz/dkr;
+          density1k = mod2(psi1)- 0.5/dkz/dkr;
+        ]]>
+      </sampling_group>
+
+      <sampling_group basis="r(1) z(1)" initial_sample="yes">
+        <moments> number0 number1 number0squared number1squared </moments>
+        <dependencies>wavefunction particle_number </dependencies>
+        <![CDATA[
+          number0 = computed_number0;
+          number1 = computed_number1;
+          number0squared = computed_number0 * computed_number0 - _lattice_r*_lattice_z/4.0;
+          number1squared = computed_number1 * computed_number1 - _lattice_r*_lattice_z/4.0;
+        ]]>
+      </sampling_group>
+
+
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+
+No seeds were provided for noise vector 'initnoise'. The seeds generated were:
+    667813208, 116090193, 819982544
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>7</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t psi0real psi0imag psi1real psi1imag density0 density1 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>31</Dim>
+    <Dim>7</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+bug_adaptive_timestep_hang_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t density0k density1k 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>31</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/2"/>
+bug_adaptive_timestep_hang_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_3">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t number0 number1 number0squared number1squared 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>71</Dim>
+    <Dim>5</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/3"/>
+bug_adaptive_timestep_hang_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/integrators/vibstring_ark45.xmds b/testsuite/integrators/vibstring_ark45.xmds
new file mode 100644
index 0000000..d16f797
--- /dev/null
+++ b/testsuite/integrators/vibstring_ark45.xmds
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  
+  <testing>
+    <xsil_file name="vibstring_ark45.xsil" expected="vibstring_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5">
+      <moment_group number="1" absolute_tolerance="1e-7" relative_tolerance="1e-6" />
+      <moment_group number="2" absolute_tolerance="1e-3" relative_tolerance="1e-6" />
+    </xsil_file>
+  </testing>
+  
+  <name>vibstring_ark45</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="estimate" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="2e-3" steps="100" tolerance="1e-6">
+      <samples>50 50</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx(50)" initial_sample="no">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/integrators/vibstring_ark89.xmds b/testsuite/integrators/vibstring_ark89.xmds
new file mode 100644
index 0000000..056b577
--- /dev/null
+++ b/testsuite/integrators/vibstring_ark89.xmds
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  
+  <testing>
+    <xsil_file name="vibstring_ark89.xsil" expected="vibstring_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5">
+      <moment_group number="1" absolute_tolerance="1e-7" relative_tolerance="1e-6" />
+      <moment_group number="2" absolute_tolerance="1e-3" relative_tolerance="1e-6" />
+    </xsil_file>
+  </testing>
+  
+  <name>vibstring_ark89</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="estimate" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" interval="2e-3" steps="100" tolerance="1e-7">
+      <samples>50 50</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx(50)" initial_sample="no">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/integrators/vibstring_expected.xsil b/testsuite/integrators/vibstring_expected.xsil
new file mode 100644
index 0000000..6df84eb
--- /dev/null
+++ b/testsuite/integrators/vibstring_expected.xsil
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  
+  <testing>
+    <xsil_file name="vibstring_ark45.xsil" expected="vibstring_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5">
+      <moment_group number="1" absolute_tolerance="1e-7" relative_tolerance="1e-6" />
+      <moment_group number="2" absolute_tolerance="1e-3" relative_tolerance="1e-6" />
+    </xsil_file>
+  </testing>
+  
+  <name>vibstring_ark45</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="estimate" />
+    <globals>
+      <![CDATA[
+      const double T = 10.0;
+      const double mass = 1e-3;
+      const double length = 1.0;
+      const double mu = mass/length;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="2e-3" steps="100" tolerance="1e-6">
+      <samples>50 50</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <!-- Any dimension not mentioned is assumed to be in real space and its middle element will be sampled -->
+        <!-- Note that this is different default behaviour to the filter operator. To integrate, put in a dimension -->
+        <!-- with zero lattice points. -->
+        <!-- Note that dimensions can be in any order. Not that I can think of a reason why you would want to do that -->
+        <dimension name="x" lattice="100" fourier_space="no" />
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u;
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="no">
+        <dimension name="x" lattice="50" fourier_space="yes" />
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.re;
+        
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t x amp 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>51</Dim>
+    <Dim>100</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+vibstring_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t kx amp 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>50</Dim>
+    <Dim>50</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+vibstring_expected_mg1.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/integrators/vibstring_expected_mg0.dat b/testsuite/integrators/vibstring_expected_mg0.dat
new file mode 100644
index 0000000..0b3c87c
Binary files /dev/null and b/testsuite/integrators/vibstring_expected_mg0.dat differ
diff --git a/testsuite/integrators/vibstring_expected_mg1.dat b/testsuite/integrators/vibstring_expected_mg1.dat
new file mode 100644
index 0000000..bb1fb97
Binary files /dev/null and b/testsuite/integrators/vibstring_expected_mg1.dat differ
diff --git a/testsuite/integrators/vibstring_rk4.xmds b/testsuite/integrators/vibstring_rk4.xmds
new file mode 100644
index 0000000..9a72441
--- /dev/null
+++ b/testsuite/integrators/vibstring_rk4.xmds
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  
+  <testing>
+    <xsil_file name="vibstring_rk4.xsil" expected="vibstring_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5">
+      <moment_group number="1" absolute_tolerance="1e-7" relative_tolerance="1e-6" />
+      <moment_group number="2" absolute_tolerance="1e-3" relative_tolerance="1e-6" />
+    </xsil_file>
+  </testing>
+  
+  <name>vibstring_rk4</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="estimate" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="2e-3" steps="100">
+      <samples>50 50</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx(50)" initial_sample="no">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/integrators/vibstring_rk45.xmds b/testsuite/integrators/vibstring_rk45.xmds
new file mode 100644
index 0000000..de4815a
--- /dev/null
+++ b/testsuite/integrators/vibstring_rk45.xmds
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  
+  <testing>
+    <xsil_file name="vibstring_rk45.xsil" expected="vibstring_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5">
+      <moment_group number="1" absolute_tolerance="1e-7" relative_tolerance="1e-6" />
+      <moment_group number="2" absolute_tolerance="1e-3" relative_tolerance="1e-6" />
+    </xsil_file>
+  </testing>
+  
+  <name>vibstring_rk45</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="estimate" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK45" interval="2e-3" steps="100">
+      <samples>50 50</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx(50)" initial_sample="no">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/integrators/vibstring_rk89.xmds b/testsuite/integrators/vibstring_rk89.xmds
new file mode 100644
index 0000000..267b6ed
--- /dev/null
+++ b/testsuite/integrators/vibstring_rk89.xmds
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  
+  <testing>
+    <xsil_file name="vibstring_rk89.xsil" expected="vibstring_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5">
+      <moment_group number="1" absolute_tolerance="1e-7" relative_tolerance="1e-6" />
+      <moment_group number="2" absolute_tolerance="1e-3" relative_tolerance="1e-6" />
+    </xsil_file>
+  </testing>
+  
+  <name>vibstring_rk89</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="estimate" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK89" interval="2e-3" steps="100">
+      <samples>50 50</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx(50)" initial_sample="no">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/integrators/vibstring_rk9.xmds b/testsuite/integrators/vibstring_rk9.xmds
new file mode 100644
index 0000000..f1bd318
--- /dev/null
+++ b/testsuite/integrators/vibstring_rk9.xmds
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  
+  <testing>
+    <xsil_file name="vibstring_rk9.xsil" expected="vibstring_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5">
+      <moment_group number="1" absolute_tolerance="1e-7" relative_tolerance="1e-6" />
+      <moment_group number="2" absolute_tolerance="1e-3" relative_tolerance="1e-6" />
+    </xsil_file>
+  </testing>
+  
+  <name>vibstring_rk9</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="estimate" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK9" interval="2e-3" steps="100">
+      <samples>50 50</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx(50)" initial_sample="no">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/integrators/vibstring_si.xmds b/testsuite/integrators/vibstring_si.xmds
new file mode 100644
index 0000000..dc300a8
--- /dev/null
+++ b/testsuite/integrators/vibstring_si.xmds
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  
+  <testing>
+    <xsil_file name="vibstring_si.xsil" expected="vibstring_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5">
+      <moment_group number="1" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+      <moment_group number="2" absolute_tolerance="1e-3" relative_tolerance="1e-5" />
+    </xsil_file>
+  </testing>
+  
+  <name>vibstring_si</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="estimate" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="SI" interval="2e-3" steps="10000">
+      <samples>50 50</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx(50)" initial_sample="no">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/io/breakpoints.xmds b/testsuite/io/breakpoints.xmds
new file mode 100644
index 0000000..78df4ff
--- /dev/null
+++ b/testsuite/io/breakpoints.xmds
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="breakpoints_xspace.xsil" expected="breakpoints_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_kspace.xsil" expected="breakpoints_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_2d_xspace.xsil" expected="breakpoints_2d_xspace_expected.xsil"  absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_mixed_space1.xsil" expected="breakpoints_mixed_space1_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_mixed_space2.xsil" expected="breakpoints_mixed_space2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>breakpoints</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test making a breakpoints in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+      <dimension name="y" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="x" type="complex">
+    <components>u</components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5))*(sin(x) + i*cos(2*x)*cos(2*x));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="x y">
+    <components>v</components>
+    <initialisation>
+      <![CDATA[
+        v = abs(x - 0.5) < 0.3 ? 1.0 : 0.0;
+        v *= abs(y) < 0.5 ? (cos(y) + i*sin(x)*sin(y)) : complex(0.0, 0.0);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="breakpoints_xspace.xsil">
+      <dependencies basis="x">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_kspace.xsil">
+      <dependencies basis="kx">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_2d_xspace.xsil">
+      <dependencies basis="x y">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_mixed_space1.xsil">
+      <dependencies basis="x ky">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_mixed_space2.xsil">
+      <dependencies basis="kx y">twod</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/io/breakpoints_2d_xspace_expected.dat b/testsuite/io/breakpoints_2d_xspace_expected.dat
new file mode 100644
index 0000000..4a27ac2
Binary files /dev/null and b/testsuite/io/breakpoints_2d_xspace_expected.dat differ
diff --git a/testsuite/io/breakpoints_2d_xspace_expected.xsil b/testsuite/io/breakpoints_2d_xspace_expected.xsil
new file mode 100644
index 0000000..0c17f1a
--- /dev/null
+++ b/testsuite/io/breakpoints_2d_xspace_expected.xsil
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="breakpoints_xspace.xsil" expected="breakpoints_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_kspace.xsil" expected="breakpoints_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_2d_xspace.xsil" expected="breakpoints_2d_xspace_expected.xsil"  absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_mixed_space1.xsil" expected="breakpoints_mixed_space1_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_mixed_space2.xsil" expected="breakpoints_mixed_space2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>breakpoints</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test making a breakpoints in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+      <dimension name="y" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="x" type="complex">
+    <components>u</components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5))*(sin(x) + i*cos(2*x)*cos(2*x));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="x y">
+    <components>v</components>
+    <initialisation>
+      <![CDATA[
+        v = fabs(x - 0.5) < 0.3 ? 1.0 : 0.0;
+        v *= fabs(y) < 0.5 ? (cos(y) + i*sin(x)*sin(y)) : rcomplex(0.0, 0.0);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="breakpoints_xspace.xsil">
+      <dependencies fourier_space="x">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_kspace.xsil">
+      <dependencies fourier_space="kx">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_2d_xspace.xsil">
+      <dependencies fourier_space="x y">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_mixed_space1.xsil">
+      <dependencies fourier_space="x ky">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_mixed_space2.xsil">
+      <dependencies fourier_space="kx y">twod</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+    <!-- <sampling_group initial_sample="no">
+        <dimension name="x" lattice="100" fourier_space="no" />
+        <moments>amp</moments>
+        <dependencies>oned</dependencies>
+        <![CDATA[
+          amp = u;
+        ]]>
+      </sampling_group>   -->
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x y vR vI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>100</Dim>
+    <Dim>256</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+breakpoints_2d_xspace_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/io/breakpoints_hdf5.xmds b/testsuite/io/breakpoints_hdf5.xmds
new file mode 100644
index 0000000..2228160
--- /dev/null
+++ b/testsuite/io/breakpoints_hdf5.xmds
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="breakpoints_hdf5_xspace.xsil" expected="breakpoints_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_kspace.xsil" expected="breakpoints_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_2d_xspace.xsil" expected="breakpoints_2d_xspace_expected.xsil"  absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space1.xsil" expected="breakpoints_mixed_space1_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space2.xsil" expected="breakpoints_mixed_space2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_xspace.xsil" expected="breakpoints_hdf5_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_kspace.xsil" expected="breakpoints_hdf5_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_2d_xspace.xsil" expected="breakpoints_hdf5_2d_xspace_expected.xsil"  absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space1.xsil" expected="breakpoints_hdf5_mixed_space1_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space2.xsil" expected="breakpoints_hdf5_mixed_space2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>breakpoints_hdf5</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test making a breakpoints in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+      <dimension name="y" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="x" type="complex">
+    <components>u</components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5))*(sin(x) + i*cos(2*x)*cos(2*x));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="x y">
+    <components>v</components>
+    <initialisation>
+      <![CDATA[
+        v = abs(x - 0.5) < 0.3 ? 1.0 : 0.0;
+        v *= abs(y) < 0.5 ? (cos(y) + i*sin(x)*sin(y)) : complex(0.0, 0.0);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="breakpoints_hdf5_xspace.xsil">
+      <dependencies basis="x">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_kspace.xsil">
+      <dependencies basis="kx">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_2d_xspace.xsil">
+      <dependencies basis="x y">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_mixed_space1.xsil">
+      <dependencies basis="x ky">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_mixed_space2.xsil">
+      <dependencies basis="kx y">twod</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="hdf5" />
+</simulation>
\ No newline at end of file
diff --git a/testsuite/io/breakpoints_hdf5_2d_xspace_expected.h5 b/testsuite/io/breakpoints_hdf5_2d_xspace_expected.h5
new file mode 100644
index 0000000..4dcf517
Binary files /dev/null and b/testsuite/io/breakpoints_hdf5_2d_xspace_expected.h5 differ
diff --git a/testsuite/io/breakpoints_hdf5_2d_xspace_expected.xsil b/testsuite/io/breakpoints_hdf5_2d_xspace_expected.xsil
new file mode 100644
index 0000000..3e9e57e
--- /dev/null
+++ b/testsuite/io/breakpoints_hdf5_2d_xspace_expected.xsil
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="breakpoints_hdf5_xspace.xsil" expected="breakpoints_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_kspace.xsil" expected="breakpoints_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_2d_xspace.xsil" expected="breakpoints_2d_xspace_expected.xsil"  absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space1.xsil" expected="breakpoints_mixed_space1_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space2.xsil" expected="breakpoints_mixed_space2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_xspace.xsil" expected="breakpoints_hdf5_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_kspace.xsil" expected="breakpoints_hdf5_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_2d_xspace.xsil" expected="breakpoints_hdf5_2d_xspace_expected.xsil"  absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space1.xsil" expected="breakpoints_hdf5_mixed_space1_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space2.xsil" expected="breakpoints_hdf5_mixed_space2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>breakpoints_hdf5</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test making a breakpoints in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+      <dimension name="y" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="x" type="complex">
+    <components>u</components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5))*(sin(x) + i*cos(2*x)*cos(2*x));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="x y">
+    <components>v</components>
+    <initialisation>
+      <![CDATA[
+        v = fabs(x - 0.5) < 0.3 ? 1.0 : 0.0;
+        v *= fabs(y) < 0.5 ? (cos(y) + i*sin(x)*sin(y)) : rcomplex(0.0, 0.0);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="breakpoints_hdf5_xspace.xsil">
+      <dependencies fourier_space="x">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_kspace.xsil">
+      <dependencies fourier_space="kx">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_2d_xspace.xsil">
+      <dependencies fourier_space="x y">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_mixed_space1.xsil">
+      <dependencies fourier_space="x ky">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_mixed_space2.xsil">
+      <dependencies fourier_space="kx y">twod</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="hdf5" />
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x y vR vI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>100</Dim>
+    <Dim>256</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+breakpoints_hdf5_2d_xspace_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/io/breakpoints_hdf5_kspace_expected.h5 b/testsuite/io/breakpoints_hdf5_kspace_expected.h5
new file mode 100644
index 0000000..8442a03
Binary files /dev/null and b/testsuite/io/breakpoints_hdf5_kspace_expected.h5 differ
diff --git a/testsuite/io/breakpoints_hdf5_kspace_expected.xsil b/testsuite/io/breakpoints_hdf5_kspace_expected.xsil
new file mode 100644
index 0000000..043e660
--- /dev/null
+++ b/testsuite/io/breakpoints_hdf5_kspace_expected.xsil
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="breakpoints_hdf5_xspace.xsil" expected="breakpoints_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_kspace.xsil" expected="breakpoints_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_2d_xspace.xsil" expected="breakpoints_2d_xspace_expected.xsil"  absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space1.xsil" expected="breakpoints_mixed_space1_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space2.xsil" expected="breakpoints_mixed_space2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_xspace.xsil" expected="breakpoints_hdf5_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_kspace.xsil" expected="breakpoints_hdf5_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_2d_xspace.xsil" expected="breakpoints_hdf5_2d_xspace_expected.xsil"  absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space1.xsil" expected="breakpoints_hdf5_mixed_space1_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space2.xsil" expected="breakpoints_hdf5_mixed_space2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>breakpoints_hdf5</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test making a breakpoints in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+      <dimension name="y" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="x" type="complex">
+    <components>u</components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5))*(sin(x) + i*cos(2*x)*cos(2*x));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="x y">
+    <components>v</components>
+    <initialisation>
+      <![CDATA[
+        v = fabs(x - 0.5) < 0.3 ? 1.0 : 0.0;
+        v *= fabs(y) < 0.5 ? (cos(y) + i*sin(x)*sin(y)) : rcomplex(0.0, 0.0);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="breakpoints_hdf5_xspace.xsil">
+      <dependencies fourier_space="x">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_kspace.xsil">
+      <dependencies fourier_space="kx">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_2d_xspace.xsil">
+      <dependencies fourier_space="x y">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_mixed_space1.xsil">
+      <dependencies fourier_space="x ky">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_mixed_space2.xsil">
+      <dependencies fourier_space="kx y">twod</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="hdf5" />
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+kx uR uI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>100</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+breakpoints_hdf5_kspace_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/io/breakpoints_hdf5_mixed_space1_expected.h5 b/testsuite/io/breakpoints_hdf5_mixed_space1_expected.h5
new file mode 100644
index 0000000..4833d34
Binary files /dev/null and b/testsuite/io/breakpoints_hdf5_mixed_space1_expected.h5 differ
diff --git a/testsuite/io/breakpoints_hdf5_mixed_space1_expected.xsil b/testsuite/io/breakpoints_hdf5_mixed_space1_expected.xsil
new file mode 100644
index 0000000..880019d
--- /dev/null
+++ b/testsuite/io/breakpoints_hdf5_mixed_space1_expected.xsil
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="breakpoints_hdf5_xspace.xsil" expected="breakpoints_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_kspace.xsil" expected="breakpoints_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_2d_xspace.xsil" expected="breakpoints_2d_xspace_expected.xsil"  absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space1.xsil" expected="breakpoints_mixed_space1_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space2.xsil" expected="breakpoints_mixed_space2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_xspace.xsil" expected="breakpoints_hdf5_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_kspace.xsil" expected="breakpoints_hdf5_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_2d_xspace.xsil" expected="breakpoints_hdf5_2d_xspace_expected.xsil"  absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space1.xsil" expected="breakpoints_hdf5_mixed_space1_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space2.xsil" expected="breakpoints_hdf5_mixed_space2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>breakpoints_hdf5</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test making a breakpoints in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+      <dimension name="y" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="x" type="complex">
+    <components>u</components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5))*(sin(x) + i*cos(2*x)*cos(2*x));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="x y">
+    <components>v</components>
+    <initialisation>
+      <![CDATA[
+        v = fabs(x - 0.5) < 0.3 ? 1.0 : 0.0;
+        v *= fabs(y) < 0.5 ? (cos(y) + i*sin(x)*sin(y)) : rcomplex(0.0, 0.0);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="breakpoints_hdf5_xspace.xsil">
+      <dependencies fourier_space="x">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_kspace.xsil">
+      <dependencies fourier_space="kx">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_2d_xspace.xsil">
+      <dependencies fourier_space="x y">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_mixed_space1.xsil">
+      <dependencies fourier_space="x ky">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_mixed_space2.xsil">
+      <dependencies fourier_space="kx y">twod</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="hdf5" />
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x ky vR vI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>100</Dim>
+    <Dim>256</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+breakpoints_hdf5_mixed_space1_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/io/breakpoints_hdf5_mixed_space2_expected.h5 b/testsuite/io/breakpoints_hdf5_mixed_space2_expected.h5
new file mode 100644
index 0000000..b8267e8
Binary files /dev/null and b/testsuite/io/breakpoints_hdf5_mixed_space2_expected.h5 differ
diff --git a/testsuite/io/breakpoints_hdf5_mixed_space2_expected.xsil b/testsuite/io/breakpoints_hdf5_mixed_space2_expected.xsil
new file mode 100644
index 0000000..11ad7e2
--- /dev/null
+++ b/testsuite/io/breakpoints_hdf5_mixed_space2_expected.xsil
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="breakpoints_hdf5_xspace.xsil" expected="breakpoints_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_kspace.xsil" expected="breakpoints_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_2d_xspace.xsil" expected="breakpoints_2d_xspace_expected.xsil"  absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space1.xsil" expected="breakpoints_mixed_space1_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space2.xsil" expected="breakpoints_mixed_space2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_xspace.xsil" expected="breakpoints_hdf5_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_kspace.xsil" expected="breakpoints_hdf5_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_2d_xspace.xsil" expected="breakpoints_hdf5_2d_xspace_expected.xsil"  absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space1.xsil" expected="breakpoints_hdf5_mixed_space1_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space2.xsil" expected="breakpoints_hdf5_mixed_space2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>breakpoints_hdf5</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test making a breakpoints in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+      <dimension name="y" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="x" type="complex">
+    <components>u</components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5))*(sin(x) + i*cos(2*x)*cos(2*x));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="x y">
+    <components>v</components>
+    <initialisation>
+      <![CDATA[
+        v = fabs(x - 0.5) < 0.3 ? 1.0 : 0.0;
+        v *= fabs(y) < 0.5 ? (cos(y) + i*sin(x)*sin(y)) : rcomplex(0.0, 0.0);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="breakpoints_hdf5_xspace.xsil">
+      <dependencies fourier_space="x">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_kspace.xsil">
+      <dependencies fourier_space="kx">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_2d_xspace.xsil">
+      <dependencies fourier_space="x y">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_mixed_space1.xsil">
+      <dependencies fourier_space="x ky">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_mixed_space2.xsil">
+      <dependencies fourier_space="kx y">twod</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="hdf5" />
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+kx y vR vI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>100</Dim>
+    <Dim>256</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+breakpoints_hdf5_mixed_space2_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/io/breakpoints_hdf5_xspace_expected.h5 b/testsuite/io/breakpoints_hdf5_xspace_expected.h5
new file mode 100644
index 0000000..8168f5e
Binary files /dev/null and b/testsuite/io/breakpoints_hdf5_xspace_expected.h5 differ
diff --git a/testsuite/io/breakpoints_hdf5_xspace_expected.xsil b/testsuite/io/breakpoints_hdf5_xspace_expected.xsil
new file mode 100644
index 0000000..8cc082c
--- /dev/null
+++ b/testsuite/io/breakpoints_hdf5_xspace_expected.xsil
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="breakpoints_hdf5_xspace.xsil" expected="breakpoints_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_kspace.xsil" expected="breakpoints_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_2d_xspace.xsil" expected="breakpoints_2d_xspace_expected.xsil"  absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space1.xsil" expected="breakpoints_mixed_space1_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space2.xsil" expected="breakpoints_mixed_space2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_xspace.xsil" expected="breakpoints_hdf5_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_kspace.xsil" expected="breakpoints_hdf5_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_2d_xspace.xsil" expected="breakpoints_hdf5_2d_xspace_expected.xsil"  absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space1.xsil" expected="breakpoints_hdf5_mixed_space1_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space2.xsil" expected="breakpoints_hdf5_mixed_space2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>breakpoints_hdf5</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test making a breakpoints in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+      <dimension name="y" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="x" type="complex">
+    <components>u</components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5))*(sin(x) + i*cos(2*x)*cos(2*x));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="x y">
+    <components>v</components>
+    <initialisation>
+      <![CDATA[
+        v = fabs(x - 0.5) < 0.3 ? 1.0 : 0.0;
+        v *= fabs(y) < 0.5 ? (cos(y) + i*sin(x)*sin(y)) : rcomplex(0.0, 0.0);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="breakpoints_hdf5_xspace.xsil">
+      <dependencies fourier_space="x">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_kspace.xsil">
+      <dependencies fourier_space="kx">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_2d_xspace.xsil">
+      <dependencies fourier_space="x y">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_mixed_space1.xsil">
+      <dependencies fourier_space="x ky">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_mixed_space2.xsil">
+      <dependencies fourier_space="kx y">twod</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="hdf5" />
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x uR uI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>100</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+breakpoints_hdf5_xspace_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/io/breakpoints_kspace_expected.dat b/testsuite/io/breakpoints_kspace_expected.dat
new file mode 100644
index 0000000..a114c50
Binary files /dev/null and b/testsuite/io/breakpoints_kspace_expected.dat differ
diff --git a/testsuite/io/breakpoints_kspace_expected.xsil b/testsuite/io/breakpoints_kspace_expected.xsil
new file mode 100644
index 0000000..4ebe067
--- /dev/null
+++ b/testsuite/io/breakpoints_kspace_expected.xsil
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="breakpoints_xspace.xsil" expected="breakpoints_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_kspace.xsil" expected="breakpoints_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_2d_xspace.xsil" expected="breakpoints_2d_xspace_expected.xsil"  absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_mixed_space1.xsil" expected="breakpoints_mixed_space1_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_mixed_space2.xsil" expected="breakpoints_mixed_space2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>breakpoints</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test making a breakpoints in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+      <dimension name="y" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="x" type="complex">
+    <components>u</components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5))*(sin(x) + i*cos(2*x)*cos(2*x));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="x y">
+    <components>v</components>
+    <initialisation>
+      <![CDATA[
+        v = fabs(x - 0.5) < 0.3 ? 1.0 : 0.0;
+        v *= fabs(y) < 0.5 ? (cos(y) + i*sin(x)*sin(y)) : rcomplex(0.0, 0.0);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="breakpoints_xspace.xsil">
+      <dependencies fourier_space="x">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_kspace.xsil">
+      <dependencies fourier_space="kx">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_2d_xspace.xsil">
+      <dependencies fourier_space="x y">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_mixed_space1.xsil">
+      <dependencies fourier_space="x ky">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_mixed_space2.xsil">
+      <dependencies fourier_space="kx y">twod</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+    <!-- <sampling_group initial_sample="no">
+        <dimension name="x" lattice="100" fourier_space="no" />
+        <moments>amp</moments>
+        <dependencies>oned</dependencies>
+        <![CDATA[
+          amp = u;
+        ]]>
+      </sampling_group>   -->
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+kx uR uI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>100</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+breakpoints_kspace_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/io/breakpoints_mixed_space1_expected.dat b/testsuite/io/breakpoints_mixed_space1_expected.dat
new file mode 100644
index 0000000..4b51760
Binary files /dev/null and b/testsuite/io/breakpoints_mixed_space1_expected.dat differ
diff --git a/testsuite/io/breakpoints_mixed_space1_expected.xsil b/testsuite/io/breakpoints_mixed_space1_expected.xsil
new file mode 100644
index 0000000..1c99df1
--- /dev/null
+++ b/testsuite/io/breakpoints_mixed_space1_expected.xsil
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="breakpoints_xspace.xsil" expected="breakpoints_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_kspace.xsil" expected="breakpoints_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_2d_xspace.xsil" expected="breakpoints_2d_xspace_expected.xsil"  absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_mixed_space1.xsil" expected="breakpoints_mixed_space1_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_mixed_space2.xsil" expected="breakpoints_mixed_space2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>breakpoints</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test making a breakpoints in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+      <dimension name="y" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="x" type="complex">
+    <components>u</components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5))*(sin(x) + i*cos(2*x)*cos(2*x));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="x y">
+    <components>v</components>
+    <initialisation>
+      <![CDATA[
+        v = fabs(x - 0.5) < 0.3 ? 1.0 : 0.0;
+        v *= fabs(y) < 0.5 ? (cos(y) + i*sin(x)*sin(y)) : rcomplex(0.0, 0.0);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="breakpoints_xspace.xsil">
+      <dependencies fourier_space="x">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_kspace.xsil">
+      <dependencies fourier_space="kx">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_2d_xspace.xsil">
+      <dependencies fourier_space="x y">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_mixed_space1.xsil">
+      <dependencies fourier_space="x ky">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_mixed_space2.xsil">
+      <dependencies fourier_space="kx y">twod</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+    <!-- <sampling_group initial_sample="no">
+        <dimension name="x" lattice="100" fourier_space="no" />
+        <moments>amp</moments>
+        <dependencies>oned</dependencies>
+        <![CDATA[
+          amp = u;
+        ]]>
+      </sampling_group>  -->
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x ky vR vI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>100</Dim>
+    <Dim>256</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+breakpoints_mixed_space1_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/io/breakpoints_mixed_space2_expected.dat b/testsuite/io/breakpoints_mixed_space2_expected.dat
new file mode 100644
index 0000000..bc309c9
Binary files /dev/null and b/testsuite/io/breakpoints_mixed_space2_expected.dat differ
diff --git a/testsuite/io/breakpoints_mixed_space2_expected.xsil b/testsuite/io/breakpoints_mixed_space2_expected.xsil
new file mode 100644
index 0000000..7fe4e38
--- /dev/null
+++ b/testsuite/io/breakpoints_mixed_space2_expected.xsil
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="breakpoints_xspace.xsil" expected="breakpoints_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_kspace.xsil" expected="breakpoints_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_2d_xspace.xsil" expected="breakpoints_2d_xspace_expected.xsil"  absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_mixed_space1.xsil" expected="breakpoints_mixed_space1_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_mixed_space2.xsil" expected="breakpoints_mixed_space2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>breakpoints</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test making a breakpoints in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+      <dimension name="y" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="x" type="complex">
+    <components>u</components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5))*(sin(x) + i*cos(2*x)*cos(2*x));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="x y">
+    <components>v</components>
+    <initialisation>
+      <![CDATA[
+        v = fabs(x - 0.5) < 0.3 ? 1.0 : 0.0;
+        v *= fabs(y) < 0.5 ? (cos(y) + i*sin(x)*sin(y)) : rcomplex(0.0, 0.0);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="breakpoints_xspace.xsil">
+      <dependencies fourier_space="x">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_kspace.xsil">
+      <dependencies fourier_space="kx">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_2d_xspace.xsil">
+      <dependencies fourier_space="x y">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_mixed_space1.xsil">
+      <dependencies fourier_space="x ky">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_mixed_space2.xsil">
+      <dependencies fourier_space="kx y">twod</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+    <!--  <sampling_group initial_sample="no">
+        <dimension name="x" lattice="100" fourier_space="no" />
+        <moments>amp</moments>
+        <dependencies>oned</dependencies>
+        <![CDATA[
+          amp = u;
+        ]]>
+      </sampling_group>   -->
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+kx y vR vI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>100</Dim>
+    <Dim>256</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+breakpoints_mixed_space2_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/io/breakpoints_xspace_expected.dat b/testsuite/io/breakpoints_xspace_expected.dat
new file mode 100644
index 0000000..9b59bf4
Binary files /dev/null and b/testsuite/io/breakpoints_xspace_expected.dat differ
diff --git a/testsuite/io/breakpoints_xspace_expected.xsil b/testsuite/io/breakpoints_xspace_expected.xsil
new file mode 100644
index 0000000..4a4c574
--- /dev/null
+++ b/testsuite/io/breakpoints_xspace_expected.xsil
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="breakpoints_xspace.xsil" expected="breakpoints_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_kspace.xsil" expected="breakpoints_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_2d_xspace.xsil" expected="breakpoints_2d_xspace_expected.xsil"  absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_mixed_space1.xsil" expected="breakpoints_mixed_space1_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_mixed_space2.xsil" expected="breakpoints_mixed_space2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>breakpoints</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test making a breakpoints in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+      <dimension name="y" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="x" type="complex">
+    <components>u</components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5))*(sin(x) + i*cos(2*x)*cos(2*x));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="x y">
+    <components>v</components>
+    <initialisation>
+      <![CDATA[
+        v = fabs(x - 0.5) < 0.3 ? 1.0 : 0.0;
+        v *= fabs(y) < 0.5 ? (cos(y) + i*sin(x)*sin(y)) : rcomplex(0.0, 0.0);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="breakpoints_xspace.xsil">
+      <dependencies fourier_space="x">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_kspace.xsil">
+      <dependencies fourier_space="kx">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_2d_xspace.xsil">
+      <dependencies fourier_space="x y">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_mixed_space1.xsil">
+      <dependencies fourier_space="x ky">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_mixed_space2.xsil">
+      <dependencies fourier_space="kx y">twod</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+    <!--  <sampling_group initial_sample="no">
+        <dimension name="x" lattice="100" fourier_space="no" />
+        <moments>amp</moments>
+        <dependencies>oned</dependencies>
+        <![CDATA[
+          amp = u;
+        ]]>
+      </sampling_group>   -->
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x uR uI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>100</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+breakpoints_xspace_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/io/mpi_xsilloading.xmds b/testsuite/io/mpi_xsilloading.xmds
new file mode 100644
index 0000000..87fe561
--- /dev/null
+++ b/testsuite/io/mpi_xsilloading.xmds
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 3 ./mpi_xsilloading</command_line>
+    <input_xsil_file name="breakpoints_kspace_expected.xsil" />
+    <input_xsil_file name="breakpoints_mixed_space2_expected.xsil" />
+    <xsil_file name="mpi_xsilloading.xsil" expected="xsilloading_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>mpi_xsilloading</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test loading xsil files in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <driver name="distributed-mpi" />
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+      <dimension name="y" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="kx" type="complex">
+    <components>u</components>
+    <initialisation kind="xsil">
+      <filename>breakpoints_kspace_expected.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="kx y">
+    <components>v</components>
+    <initialisation kind="xsil">
+      <filename>breakpoints_mixed_space2_expected.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <filter>
+      <![CDATA[
+        ;
+      ]]>
+    </filter>
+  </sequence>
+  
+  <output format="binary">
+    <sampling_group basis="x(50) y(0)" initial_sample="yes">
+      <moments>amp</moments>
+      <dependencies>oned twod</dependencies>
+      <![CDATA[
+        amp = cos(u.Re())*sin(u.Im()) - v.Re()*v.Re() + v.Im(); // Some crazy function to combine the quantities
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/io/mpi_xsilloading_hdf5.xmds b/testsuite/io/mpi_xsilloading_hdf5.xmds
new file mode 100644
index 0000000..bcaa57e
--- /dev/null
+++ b/testsuite/io/mpi_xsilloading_hdf5.xmds
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 3 ./mpi_xsilloading_hdf5</command_line>
+    <input_xsil_file name="breakpoints_hdf5_kspace_expected.xsil" />
+    <input_xsil_file name="breakpoints_hdf5_mixed_space2_expected.xsil" />
+    <xsil_file name="mpi_xsilloading_hdf5.xsil" expected="xsilloading_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>mpi_xsilloading_hdf5</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test loading xsil files in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <driver name="distributed-mpi" />
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+      <dimension name="y" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="kx" type="complex">
+    <components>u</components>
+    <initialisation kind="hdf5">
+      <filename>breakpoints_hdf5_kspace_expected.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="kx y">
+    <components>v</components>
+    <initialisation kind="hdf5">
+      <filename>breakpoints_hdf5_mixed_space2_expected.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <filter>
+      <![CDATA[
+        ;
+      ]]>
+    </filter>
+  </sequence>
+  
+  <output format="hdf5">
+    <sampling_group basis="x(50) y(0)" initial_sample="yes">
+      <moments>amp</moments>
+      <dependencies>oned twod</dependencies>
+      <![CDATA[
+        amp = cos(u.Re())*sin(u.Im()) - v.Re()*v.Re() + v.Im(); // Some crazy function to combine the quantities
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/io/mpi_xsilloading_hdf5_loose.xmds b/testsuite/io/mpi_xsilloading_hdf5_loose.xmds
new file mode 100644
index 0000000..6046b38
--- /dev/null
+++ b/testsuite/io/mpi_xsilloading_hdf5_loose.xmds
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 3 ./mpi_xsilloading_hdf5_loose</command_line>
+    <input_xsil_file name="breakpoints_hdf5_kspace_expected.xsil" />
+    <input_xsil_file name="breakpoints_hdf5_mixed_space2_expected.xsil" />
+    <xsil_file name="mpi_xsilloading_hdf5_loose.xsil" expected="xsilloading_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>mpi_xsilloading_hdf5_loose</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test loading xsil files in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <driver name="distributed-mpi" />
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="250"  domain="(0, 1)" />
+      <dimension name="y" lattice="512"  domain="(-1, 3)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="kx" type="complex">
+    <components>u</components>
+    <initialisation kind="hdf5" geometry_matching_mode="loose">
+      <filename>breakpoints_hdf5_kspace_expected.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="kx y">
+    <components>v</components>
+    <initialisation kind="hdf5" geometry_matching_mode="loose">
+      <filename>breakpoints_hdf5_mixed_space2_expected.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <filter>
+      <![CDATA[
+        ;
+      ]]>
+    </filter>
+  </sequence>
+  
+  <output format="hdf5">
+    <sampling_group basis="x(50) y(0)" initial_sample="yes">
+      <moments>amp</moments>
+      <dependencies>oned twod</dependencies>
+      <![CDATA[
+        amp = cos(u.Re())*sin(u.Im())/2.0 - v.Re()*v.Re() + v.Im(); // Some crazy function to combine the quantities
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/io/mpi_xsilloading_hdf5_loose2.xmds b/testsuite/io/mpi_xsilloading_hdf5_loose2.xmds
new file mode 100644
index 0000000..6f232e3
--- /dev/null
+++ b/testsuite/io/mpi_xsilloading_hdf5_loose2.xmds
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 3 ./mpi_xsilloading_hdf5_loose2</command_line>
+    <input_xsil_file name="breakpoints_hdf5_kspace_expected.xsil" />
+    <input_xsil_file name="breakpoints_hdf5_mixed_space2_expected.xsil" />
+    <xsil_file name="mpi_xsilloading_hdf5_loose2.xsil" expected="xsilloading_expected2.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>mpi_xsilloading_hdf5_loose2</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test loading xsil files in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <driver name="distributed-mpi" />
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="250"  domain="(0, 1)" />
+      <dimension name="y" lattice="512"  domain="(-1, 3)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="kx" type="complex">
+    <components>u</components>
+    <initialisation kind="hdf5" geometry_matching_mode="loose">
+      <filename>breakpoints_hdf5_kspace_expected.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="kx y">
+    <components>v</components>
+    <initialisation kind="hdf5" geometry_matching_mode="loose">
+      <filename>breakpoints_hdf5_mixed_space2_expected.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <filter>
+      <![CDATA[
+        ;
+      ]]>
+    </filter>
+  </sequence>
+  
+  <output format="hdf5">
+    <sampling_group basis="x(50) y(0)" initial_sample="yes">
+      <moments>amp</moments>
+      <dependencies>oned twod</dependencies>
+      <![CDATA[
+              amp = cos(u.Re())*sin(u.Im())/2.0 - v.Re()*v.Re()*x*y + sin(y)*v.Im(); // Some crazy function to combine the quantities
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/io/mpi_xsilloading_loose.xmds b/testsuite/io/mpi_xsilloading_loose.xmds
new file mode 100644
index 0000000..62ba8ea
--- /dev/null
+++ b/testsuite/io/mpi_xsilloading_loose.xmds
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 3 ./mpi_xsilloading_loose</command_line>
+    <input_xsil_file name="breakpoints_kspace_expected.xsil" />
+    <input_xsil_file name="breakpoints_mixed_space2_expected.xsil" />
+    <xsil_file name="mpi_xsilloading_loose.xsil" expected="xsilloading_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>mpi_xsilloading_loose</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test loading xsil files in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <driver name="distributed-mpi" />
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="250"  domain="(0, 1)" />
+      <dimension name="y" lattice="512"  domain="(-1, 3)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="kx" type="complex">
+    <components>u</components>
+    <initialisation kind="xsil" geometry_matching_mode="loose">
+      <filename>breakpoints_kspace_expected.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="kx y">
+    <components>v</components>
+    <initialisation kind="xsil" geometry_matching_mode="loose">
+      <filename>breakpoints_mixed_space2_expected.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <filter>
+      <![CDATA[
+        ;
+      ]]>
+    </filter>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="x(50) y(0)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>oned twod</dependencies>
+        <![CDATA[
+          amp = cos(u.Re())*sin(u.Im())/2.0 - v.Re()*v.Re() + v.Im(); // Some crazy function to combine the quantities
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/io/mpi_xsilloading_loose2.xmds b/testsuite/io/mpi_xsilloading_loose2.xmds
new file mode 100644
index 0000000..46f3caa
--- /dev/null
+++ b/testsuite/io/mpi_xsilloading_loose2.xmds
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 3 ./mpi_xsilloading_loose2</command_line>
+    <input_xsil_file name="breakpoints_kspace_expected.xsil" />
+    <input_xsil_file name="breakpoints_mixed_space2_expected.xsil" />
+    <xsil_file name="mpi_xsilloading_loose2.xsil" expected="xsilloading_expected2.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>mpi_xsilloading_loose2</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test loading xsil files in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <driver name="distributed-mpi" />
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="250"  domain="(0, 1)" />
+      <dimension name="y" lattice="512"  domain="(-2, 2)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="kx" type="complex">
+    <components>u</components>
+    <initialisation kind="xsil" geometry_matching_mode="loose">
+      <filename>breakpoints_kspace_expected.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="kx y">
+    <components>v</components>
+    <initialisation kind="xsil" geometry_matching_mode="loose">
+      <filename>breakpoints_mixed_space2_expected.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <filter>
+      <![CDATA[
+        ;
+      ]]>
+    </filter>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="x(50) y(0)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>oned twod</dependencies>
+        <![CDATA[
+	            amp = cos(u.Re())*sin(u.Im())/2.0 - v.Re()*v.Re()*x*y + sin(y)*v.Im(); // Some crazy function to combine the quantities
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/io/nlse_sampling.xmds b/testsuite/io/nlse_sampling.xmds
new file mode 100644
index 0000000..ada02ad
--- /dev/null
+++ b/testsuite/io/nlse_sampling.xmds
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="nlse_sampling.xsil" expected="nlse_sampling_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+  </testing>
+
+  <name>nlse_sampling</name>
+
+  <author>Joe Hope</author>
+  <description>
+    The nonlinear Schrodinger equation in one dimension, 
+    which is a simple partial differential equation.  
+    We introduce several new features in this script.
+  </description>
+
+  <features>
+      <benchmark />
+      <bing />
+      <fftw plan="patient" />
+      <auto_vectorise />
+      <globals>
+          <![CDATA[
+          const double energy = 4;
+          const double vel = 0.3;
+          const double hwhm = 1.0;
+          ]]>
+       </globals>
+     </features>
+
+  <geometry>
+      <propagation_dimension> xi </propagation_dimension>
+      <transverse_dimensions>
+        <dimension name="tau" lattice="128"  domain="(-6, 6)" />
+      </transverse_dimensions>
+   </geometry>
+
+  <vector name="wavefunction" type="complex" dimensions="tau">
+    <components> phi </components>
+    <initialisation>
+      <![CDATA[
+      const double w0 = hwhm*sqrt(2/log(2));
+      const double amp = sqrt(energy/w0/sqrt(M_PI/2));
+      phi = amp*exp(-tau*tau/w0/w0)*exp(i*vel*tau);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <vector name="dampingVector" type="real">
+    <components> Gamma </components>
+    <initialisation>
+      <![CDATA[
+      Gamma=1.0*(1-exp(-pow(tau*tau/4.0/4.0,10)));
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <integrate algorithm="ARK45" interval="20.0" tolerance="1e-7">
+      <samples>10 100 10</samples>
+      <operators>
+        <integration_vectors>wavefunction</integration_vectors>
+        <operator kind="ex" constant="yes">
+          <operator_names>Ltt</operator_names>
+          <![CDATA[
+            Ltt = -i*ktau*ktau*0.5;
+          ]]>
+        </operator>
+        <![CDATA[
+        dphi_dxi = Ltt[phi] - phi*Gamma + i*mod2(phi)*phi;
+        ]]>
+        <dependencies>dampingVector</dependencies>
+      </operators>
+    </integrate>
+  </sequence>
+
+  <output>
+      <sampling_group basis="tau" initial_sample="yes">
+        <moments>density</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          density = mod2(phi);
+        ]]>
+      </sampling_group>
+
+      <sampling_group basis="tau(0)" initial_sample="yes">
+        <moments>normalisation</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          normalisation = mod2(phi);
+        ]]>
+      </sampling_group>
+
+      <sampling_group basis="ktau(1)" initial_sample="yes">
+        <moments>densityK</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          densityK = mod2(phi);
+        ]]>
+      </sampling_group>
+
+  </output>
+</simulation>
+
diff --git a/testsuite/io/nlse_sampling_expected.h5 b/testsuite/io/nlse_sampling_expected.h5
new file mode 100644
index 0000000..717bbbd
Binary files /dev/null and b/testsuite/io/nlse_sampling_expected.h5 differ
diff --git a/testsuite/io/nlse_sampling_expected.xsil b/testsuite/io/nlse_sampling_expected.xsil
new file mode 100644
index 0000000..6a8c894
--- /dev/null
+++ b/testsuite/io/nlse_sampling_expected.xsil
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="nlse_sampling.xsil" expected="nlse_sampling_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+  </testing>
+
+  <name>nlse_sampling</name>
+
+  <author>Joe Hope</author>
+  <description>
+    The nonlinear Schrodinger equation in one dimension, 
+    which is a simple partial differential equation.  
+    We introduce several new features in this script.
+  </description>
+
+  <features>
+      <benchmark />
+      <bing />
+      <fftw plan="patient" />
+      <openmp />
+      <auto_vectorise />
+      <globals>
+          <![CDATA[
+          const double energy = 4;
+          const double vel = 0.3;
+          const double hwhm = 1.0;
+          ]]>
+       </globals>
+     </features>
+
+  <geometry>
+      <propagation_dimension> xi </propagation_dimension>
+      <transverse_dimensions>
+        <dimension name="tau" lattice="128"  domain="(-6, 6)" />
+      </transverse_dimensions>
+   </geometry>
+
+  <vector name="wavefunction" type="complex" dimensions="tau">
+    <components> phi </components>
+    <initialisation>
+      <![CDATA[
+      const double w0 = hwhm*sqrt(2/log(2));
+      const double amp = sqrt(energy/w0/sqrt(M_PI/2));
+      phi = amp*exp(-tau*tau/w0/w0)*exp(i*vel*tau);
+      ]]>
+    </initialisation>
+  </vector>
+
+  <vector name="dampingVector" type="real">
+    <components> Gamma </components>
+    <initialisation>
+      <![CDATA[
+      Gamma=1.0*(1-exp(-pow(tau*tau/4.0/4.0,10)));
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <integrate algorithm="ARK45" interval="20.0" tolerance="1e-7">
+      <samples>10 100 10</samples>
+      <operators>
+        <integration_vectors>wavefunction</integration_vectors>
+        <operator kind="ex" constant="yes">
+          <operator_names>Ltt</operator_names>
+          <![CDATA[
+            Ltt = -i*ktau*ktau*0.5;
+          ]]>
+        </operator>
+        <![CDATA[
+        dphi_dxi = Ltt[phi] - phi*Gamma + i*mod2(phi)*phi;
+        ]]>
+        <dependencies>dampingVector</dependencies>
+      </operators>
+    </integrate>
+  </sequence>
+
+  <output>
+      <sampling_group basis="tau" initial_sample="yes">
+        <moments>density</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          density = mod2(phi);
+        ]]>
+      </sampling_group>
+
+      <sampling_group basis="tau(0)" initial_sample="yes">
+        <moments>normalisation</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          normalisation = mod2(phi);
+        ]]>
+      </sampling_group>
+
+      <sampling_group basis="ktau(1)" initial_sample="yes">
+        <moments>densityK</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          densityK = mod2(phi);
+        ]]>
+      </sampling_group>
+
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+xi tau density 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>11</Dim>
+    <Dim>128</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+nlse_sampling_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+xi normalisation 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>101</Dim>
+    <Dim>2</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/2"/>
+nlse_sampling_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_3">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+xi densityK 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>11</Dim>
+    <Dim>2</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/3"/>
+nlse_sampling_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/io/xsilloading.xmds b/testsuite/io/xsilloading.xmds
new file mode 100644
index 0000000..be6a3a0
--- /dev/null
+++ b/testsuite/io/xsilloading.xmds
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <input_xsil_file name="breakpoints_kspace_expected.xsil" />
+    <input_xsil_file name="breakpoints_mixed_space2_expected.xsil" />
+    <xsil_file name="xsilloading.xsil" expected="xsilloading_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>xsilloading</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test loading xsil files in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+      <dimension name="y" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="kx" type="complex">
+    <components>u</components>
+    <initialisation kind="xsil">
+      <filename>breakpoints_kspace_expected.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="kx y">
+    <components>v</components>
+    <initialisation kind="xsil">
+      <filename>breakpoints_mixed_space2_expected.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <filter>
+      <![CDATA[
+        ;
+      ]]>
+    </filter>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="x(50) y(0)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>oned twod</dependencies>
+        <![CDATA[
+          amp = cos(u.Re())*sin(u.Im()) - v.Re()*v.Re() + v.Im(); // Some crazy function to combine the quantities
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/io/xsilloading_expected.xsil b/testsuite/io/xsilloading_expected.xsil
new file mode 100644
index 0000000..cf893cf
--- /dev/null
+++ b/testsuite/io/xsilloading_expected.xsil
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 3 ./mpi_xsilloading</command_line>
+    <input_xsil_file name="breakpoints_kspace_expected.xsil" />
+    <input_xsil_file name="breakpoints_mixed_space2_expected.xsil" />
+    <xsil_file name="mpi_xsilloading.xsil" expected="xsilloading_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>mpi_xsilloading</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test loading xsil files in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <driver name="distributed-mpi" />
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+      <dimension name="y" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="kx" type="complex">
+    <components>u</components>
+    <initialisation kind="xsil">
+      <filename>breakpoints_kspace_expected.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="kx y">
+    <components>v</components>
+    <initialisation kind="xsil">
+      <filename>breakpoints_mixed_space2_expected.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <filter>
+      <![CDATA[
+        ;
+      ]]>
+    </filter>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <dimension name="x" lattice="50" fourier_space="no" />
+        <dimension name="y" lattice="0" fourier_space="no" />
+        <moments>amp</moments>
+        <dependencies>oned twod</dependencies>
+        <![CDATA[
+          amp = cos(u.re)*sin(u.im) - v.re*v.re + v.im; // Some crazy function to combine the quantities
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x amp 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>50</Dim>
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+xsilloading_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/io/xsilloading_expected2.xsil b/testsuite/io/xsilloading_expected2.xsil
new file mode 100644
index 0000000..67ca624
--- /dev/null
+++ b/testsuite/io/xsilloading_expected2.xsil
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <input_xsil_file name="breakpoints_kspace_expected.xsil" />
+    <input_xsil_file name="breakpoints_mixed_space2_expected.xsil" />
+    <xsil_file name="xsilloading_loose2.xsil" expected="xsilloading_expected2.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>xsilloading_loose2</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test loading xsil files in various spaces with loose geometry matching mode
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="250"  domain="(0, 1)" />
+      <dimension name="y" lattice="512"  domain="(-2, 2)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="kx" type="complex">
+    <components>u</components>
+    <initialisation kind="xsil" geometry_matching_mode="loose">
+      <filename>breakpoints_kspace_expected.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="kx y">
+    <components>v</components>
+    <initialisation kind="xsil" geometry_matching_mode="loose">
+      <filename>breakpoints_mixed_space2_expected.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <filter>
+      <![CDATA[
+        ;
+      ]]>
+    </filter>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="x(50) y(0)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>oned twod</dependencies>
+        <![CDATA[
+          amp = cos(u.Re())*sin(u.Im())/2.0 - v.Re()*v.Re()*x*y + sin(y)*v.Im(); // Some crazy function to combine the quantities
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x amp 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>50</Dim>
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+xsilloading_expected2_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/io/xsilloading_expected2_mg0.dat b/testsuite/io/xsilloading_expected2_mg0.dat
new file mode 100644
index 0000000..0384d19
Binary files /dev/null and b/testsuite/io/xsilloading_expected2_mg0.dat differ
diff --git a/testsuite/io/xsilloading_expected_mg0.dat b/testsuite/io/xsilloading_expected_mg0.dat
new file mode 100644
index 0000000..cf81557
Binary files /dev/null and b/testsuite/io/xsilloading_expected_mg0.dat differ
diff --git a/testsuite/io/xsilloading_hdf5.xmds b/testsuite/io/xsilloading_hdf5.xmds
new file mode 100644
index 0000000..0283f7f
--- /dev/null
+++ b/testsuite/io/xsilloading_hdf5.xmds
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <input_xsil_file name="breakpoints_hdf5_kspace_expected.xsil" />
+    <input_xsil_file name="breakpoints_hdf5_mixed_space2_expected.xsil" />
+    <xsil_file name="xsilloading_hdf5.xsil" expected="xsilloading_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>xsilloading_hdf5</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test loading xsil files in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" />
+      <dimension name="y" lattice="256"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="kx" type="complex">
+    <components>u</components>
+    <initialisation kind="hdf5">
+      <filename>breakpoints_hdf5_kspace_expected.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="kx y">
+    <components>v</components>
+    <initialisation kind="hdf5">
+      <filename>breakpoints_hdf5_mixed_space2_expected.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <filter>
+      <![CDATA[
+        ;
+      ]]>
+    </filter>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="x(50) y(0)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>oned twod</dependencies>
+        <![CDATA[
+          amp = cos(u.Re())*sin(u.Im()) - v.Re()*v.Re() + v.Im(); // Some crazy function to combine the quantities
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/io/xsilloading_hdf5_loose.xmds b/testsuite/io/xsilloading_hdf5_loose.xmds
new file mode 100644
index 0000000..647f680
--- /dev/null
+++ b/testsuite/io/xsilloading_hdf5_loose.xmds
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <input_xsil_file name="breakpoints_hdf5_kspace_expected.xsil" />
+    <input_xsil_file name="breakpoints_hdf5_mixed_space2_expected.xsil" />
+    <xsil_file name="xsilloading_hdf5_loose.xsil" expected="xsilloading_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>xsilloading_hdf5_loose</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test loading xsil files in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="250"  domain="(0, 1)" />
+      <dimension name="y" lattice="512"  domain="(-1, 3)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="kx" type="complex">
+    <components>u</components>
+    <initialisation kind="hdf5" geometry_matching_mode="loose">
+      <filename>breakpoints_hdf5_kspace_expected.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="kx y">
+    <components>v</components>
+    <initialisation kind="hdf5" geometry_matching_mode="loose">
+      <filename>breakpoints_hdf5_mixed_space2_expected.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <filter>
+      <![CDATA[
+        ;
+      ]]>
+    </filter>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="x(50) y(0)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>oned twod</dependencies>
+        <![CDATA[
+          amp = cos(u.Re())*sin(u.Im())/2.0 - v.Re()*v.Re() + v.Im(); // Some crazy function to combine the quantities
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/io/xsilloading_hdf5_loose2.xmds b/testsuite/io/xsilloading_hdf5_loose2.xmds
new file mode 100644
index 0000000..e6aedee
--- /dev/null
+++ b/testsuite/io/xsilloading_hdf5_loose2.xmds
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <input_xsil_file name="breakpoints_hdf5_kspace_expected.xsil" />
+    <input_xsil_file name="breakpoints_hdf5_mixed_space2_expected.xsil" />
+    <xsil_file name="xsilloading_hdf5_loose2.xsil" expected="xsilloading_expected2.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>xsilloading_hdf5_loose2</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test loading xsil files in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="250"  domain="(0, 1)" />
+      <dimension name="y" lattice="512"  domain="(-2, 2)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="kx" type="complex">
+    <components>u</components>
+    <initialisation kind="hdf5" geometry_matching_mode="loose">
+      <filename>breakpoints_hdf5_kspace_expected.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="kx y">
+    <components>v</components>
+    <initialisation kind="hdf5" geometry_matching_mode="loose">
+      <filename>breakpoints_hdf5_mixed_space2_expected.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <filter>
+      <![CDATA[
+        ;
+      ]]>
+    </filter>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="x(50) y(0)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>oned twod</dependencies>
+        <![CDATA[
+	            amp = cos(u.Re())*sin(u.Im())/2.0 - v.Re()*v.Re()*x*y + sin(y)*v.Im(); // Some crazy function to combine the quantities
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/io/xsilloading_loose.xmds b/testsuite/io/xsilloading_loose.xmds
new file mode 100644
index 0000000..3781287
--- /dev/null
+++ b/testsuite/io/xsilloading_loose.xmds
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <input_xsil_file name="breakpoints_kspace_expected.xsil" />
+    <input_xsil_file name="breakpoints_mixed_space2_expected.xsil" />
+    <xsil_file name="xsilloading_loose.xsil" expected="xsilloading_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>xsilloading_loose</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test loading xsil files in various spaces with loose geometry matching mode
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="250"  domain="(0, 1)" />
+      <dimension name="y" lattice="512"  domain="(-1, 3)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="kx" type="complex">
+    <components>u</components>
+    <initialisation kind="xsil" geometry_matching_mode="loose">
+      <filename>breakpoints_kspace_expected.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="kx y">
+    <components>v</components>
+    <initialisation kind="xsil" geometry_matching_mode="loose">
+      <filename>breakpoints_mixed_space2_expected.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <filter>
+      <![CDATA[
+        ;
+      ]]>
+    </filter>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="x(50) y(0)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>oned twod</dependencies>
+        <![CDATA[
+          amp = cos(u.Re())*sin(u.Im())/2.0 - v.Re()*v.Re() + v.Im(); // Some crazy function to combine the quantities
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/io/xsilloading_loose2.xmds b/testsuite/io/xsilloading_loose2.xmds
new file mode 100644
index 0000000..b4fb17e
--- /dev/null
+++ b/testsuite/io/xsilloading_loose2.xmds
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <input_xsil_file name="breakpoints_kspace_expected.xsil" />
+    <input_xsil_file name="breakpoints_mixed_space2_expected.xsil" />
+    <xsil_file name="xsilloading_loose2.xsil" expected="xsilloading_expected2.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>xsilloading_loose2</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test loading xsil files in various spaces with loose geometry matching mode
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="250"  domain="(0, 1)" />
+      <dimension name="y" lattice="512"  domain="(-2, 2)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="kx" type="complex">
+    <components>u</components>
+    <initialisation kind="xsil" geometry_matching_mode="loose">
+      <filename>breakpoints_kspace_expected.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="kx y">
+    <components>v</components>
+    <initialisation kind="xsil" geometry_matching_mode="loose">
+      <filename>breakpoints_mixed_space2_expected.xsil</filename>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <filter>
+      <![CDATA[
+        ;
+      ]]>
+    </filter>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="x(50) y(0)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>oned twod</dependencies>
+        <![CDATA[
+          amp = cos(u.Re())*sin(u.Im())/2.0 - v.Re()*v.Re()*x*y + sin(y)*v.Im(); // Some crazy function to combine the quantities
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/mpi/diffusion_mpi.xmds b/testsuite/mpi/diffusion_mpi.xmds
new file mode 100644
index 0000000..aa2617e
--- /dev/null
+++ b/testsuite/mpi/diffusion_mpi.xmds
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 2 ./diffusion_mpi</command_line>
+    <xsil_file name="diffusion_mpi.xsil" expected="diffusion_mpi_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>diffusion_mpi</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion with a pointless second dimension thrown in for fun
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="measure" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+      <dimension name="x" lattice="256"  domain="(-10.0, 10.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="10.0" steps="2400" tolerance="1e-5">
+      <samples>24 4</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="x ky">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="y x(0)" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="y x" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/mpi/diffusion_mpi_chunked.xmds b/testsuite/mpi/diffusion_mpi_chunked.xmds
new file mode 100644
index 0000000..0731162
--- /dev/null
+++ b/testsuite/mpi/diffusion_mpi_chunked.xmds
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 2 ./diffusion_mpi_chunked</command_line>
+    <xsil_file name="diffusion_mpi_chunked.xsil" expected="diffusion_mpi_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>diffusion_mpi_chunked</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion with a pointless second dimension thrown in for fun
+  </description>
+  
+  <features>
+    <benchmark />
+    <chunked_output size="10KB" />
+    <fftw plan="measure" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+      <dimension name="x" lattice="256"  domain="(-10.0, 10.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="10.0" steps="2400" tolerance="1e-5">
+      <samples>24 4</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="x ky">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="y x(0)" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="y x" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/mpi/diffusion_mpi_expected.xsil b/testsuite/mpi/diffusion_mpi_expected.xsil
new file mode 100644
index 0000000..3594e9b
--- /dev/null
+++ b/testsuite/mpi/diffusion_mpi_expected.xsil
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 2 ./diffusion_mpi</command_line>
+    <xsil_file name="diffusion_mpi.xsil" expected="diffusion_mpi_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>diffusion_mpi</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion with a pointless second dimension thrown in for fun
+  </description>
+  
+  <features>
+    <benchmark />
+    <!-- <error_check /> -->
+    <bing />
+    <fftw plan="measure" />
+    <openmp />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+      <dimension name="x" lattice="256"  domain="(-10.0, 10.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="10.0" steps="2400" tolerance="1e-5">
+      <samples>24 4</samples>
+      <operators>
+        <operator kind="ip" constant="yes" fourier_space="x ky">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <!-- Any dimension not mentioned is assumed to be in real space and its middle element will be sampled -->
+        <!-- Note that dimensions can be in any order. Not that I can think of a reason why you would want to do that -->
+        <dimension name="y" fourier_space="y" />
+        <dimension name="x" lattice="0" fourier_space="x" />
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes">
+        <!-- Any dimension not mentioned is assumed to be in real space and its middle element will be sampled -->
+        <!-- Note that dimensions can be in any order. Not that I can think of a reason why you would want to do that -->
+        <dimension name="y" fourier_space="y" />
+        <dimension name="x" fourier_space="x" />
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t y dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>25</Dim>
+    <Dim>128</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+diffusion_mpi_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t y x dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>5</Dim>
+    <Dim>128</Dim>
+    <Dim>256</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+diffusion_mpi_expected_mg1.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/mpi/diffusion_mpi_expected_mg0.dat b/testsuite/mpi/diffusion_mpi_expected_mg0.dat
new file mode 100644
index 0000000..8d58f37
Binary files /dev/null and b/testsuite/mpi/diffusion_mpi_expected_mg0.dat differ
diff --git a/testsuite/mpi/diffusion_mpi_expected_mg1.dat b/testsuite/mpi/diffusion_mpi_expected_mg1.dat
new file mode 100644
index 0000000..775d188
Binary files /dev/null and b/testsuite/mpi/diffusion_mpi_expected_mg1.dat differ
diff --git a/testsuite/mpi/eigenvalues.xmds b/testsuite/mpi/eigenvalues.xmds
new file mode 100644
index 0000000..07cd0e5
--- /dev/null
+++ b/testsuite/mpi/eigenvalues.xmds
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 2 ./eigenvalues</command_line>
+    <xsil_file name="eigenvalues_break.xsil" expected="../fast/eigenvalues_break_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+    <xsil_file name="eigenvalues.xsil" expected="../fast/eigenvalues_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>eigenvalues</name>
+  <author>Graham Dennis</author>
+  <description>
+    1D TW model of the uniform Peaks system.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <fftw plan="exhaustive" />
+    <globals>
+      <![CDATA[
+      /* physical constants  */
+       const double omegaz = 2*M_PI*55.0;
+       const double omegarho = 2*M_PI*1020.0;
+       const double hbar = 1.05457148e-34;
+       const double M = 4.0026032*1.66053886e-27;
+       const double scatteringLength = 7.51e-9;
+       const double Uint3 = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+       const double Nparticles = 2.0e6;
+       const double mu = pow(15*Nparticles*Uint3*omegarho*omegarho*omegaz/(8.0*M_PI)*pow(M/2,3.0/2.0),2.0/5.0);
+       const double Uint = Uint3*5.0*omegarho*omegarho*M/(4.0*M_PI*mu);
+       const double Uint_hbar = Uint/hbar;
+       const complex miUint_hbar = -i*Uint_hbar;
+       const double otherScatteringLength = 5.56e-9;
+       const double kappa = otherScatteringLength/scatteringLength;
+       double Delta;
+       const double hbar_M = hbar/M;
+       const double Omega = 2.0*M_PI*3e3;
+       
+       double mu0 = hbar*1.7786e3*2.0*M_PI;
+       double nu = 6.649299328e3;//4.4046e4; // Hertz
+       
+      ]]>
+    </globals>
+    <validation kind="run-time" />
+  </features>
+  
+  <driver name="distributed-mpi" />
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="kz" lattice="32"  domain="(0, 3e6)" transform="none"/>
+      <!-- <dimension name="kz" lattice="1024"  domain="(1.3220e6, 1.3221e6)" /> -->
+      <dimension name="p" domain="(1, 4)" type="integer" aliases="q" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="wavefunction" dimensions="" type="complex">
+    <components>
+      phi1 phi0
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi1 = sqrt(mu/Uint);
+        phi0 = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="matrixterms" dimensions="kz p q" initial_basis="kz" type="complex">
+    <components>matrix</components>
+    <initialisation>
+      <![CDATA[
+        if (p == q) {
+          matrix = 1.0;
+        } else {
+          matrix = 0.0;
+        }
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="hamiltonian_matrix" dimensions="kz p q" type="complex">
+    <components>h_matrix</components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        const double kineticEnergy = 0.5*hbar*hbar*kz*kz/M;
+        if (p == 1 && q == 1) h_matrix = Uint*mod2(phi1)+kineticEnergy-mu0;
+        if (p == 1 && q == 2) h_matrix = Uint*phi1*phi1;
+        if (p == 1 && q == 3) h_matrix = Uint*phi1*conj(phi0)+hbar*Omega;
+        if (p == 1 && q == 4) h_matrix = Uint*phi1*phi0;
+        
+        if (p == 2 && q == 1) h_matrix = -Uint*conj(phi1*phi1);
+        if (p == 2 && q == 2) h_matrix = -Uint*mod2(phi1)-kineticEnergy+mu0;
+        if (p == 2 && q == 3) h_matrix = -Uint*conj(phi1 * phi0);
+        if (p == 2 && q == 4) h_matrix = -Uint*conj(phi1)*phi0 - hbar*Omega;
+        
+        if (p == 3 && q == 1) h_matrix = Uint*conj(phi1)*phi0 + hbar*Omega;
+        if (p == 3 && q == 2) h_matrix = Uint*phi0*phi1;
+        if (p == 3 && q == 3) h_matrix = Uint*(2.0*kappa-1.0)*mod2(phi0)-mu0+kineticEnergy;
+        if (p == 3 && q == 4) h_matrix = Uint*kappa*phi0*phi0;
+        
+        if (p == 4 && q == 1) h_matrix = -Uint*conj(phi0*phi1);
+        if (p == 4 && q == 2) h_matrix = -Uint*phi1*conj(phi0)-hbar*Omega;
+        if (p == 4 && q == 3) h_matrix = -Uint*kappa*conj(phi0*phi0);
+        if (p == 4 && q == 4) h_matrix = -Uint*(2.0*kappa-1.0)*mod2(phi0)-kineticEnergy+mu0;
+        
+        h_matrix *= -i/hbar;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" interval="1.0/nu" tolerance="1e-8">
+      <samples>20 20</samples>
+      <operators dimensions="">
+        <integration_vectors>wavefunction</integration_vectors>
+        <![CDATA[
+          dphi1_dt = - i/hbar*( - mu0)*phi1 -i*Omega*phi0;
+          dphi0_dt = - i/hbar*( - Uint*(1.0-kappa)*mod2(phi0) - mu0)*phi0 -i*Omega*phi1;
+        ]]>
+      </operators>
+      <operators dimensions="kz p q">
+        <integration_vectors>matrixterms</integration_vectors>
+        <dependencies>wavefunction hamiltonian_matrix</dependencies>
+        <![CDATA[
+          dmatrix_dt = 0.0;
+          for (long pp = 1; pp <= 4; pp++) {
+            dmatrix_dt += h_matrix(q=> pp)*matrix(p=> pp);
+          }
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="eigenvalues_break.xsil" format="hdf5">
+      <dependencies>matrixterms</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="hdf5">
+      <sampling_group initial_sample="yes">
+        <moments>phi1R phi1I phi0R phi0I</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(phi1); _SAMPLE_COMPLEX(phi0);
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes" basis="kz p q">
+        <moments>matrixR matrixI</moments>
+        <dependencies>matrixterms</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(matrix);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/mpi/fibre_integer_dimensions_mpi.xmds b/testsuite/mpi/fibre_integer_dimensions_mpi.xmds
new file mode 100644
index 0000000..7c65966
--- /dev/null
+++ b/testsuite/mpi/fibre_integer_dimensions_mpi.xmds
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 3 ./fibre_integer_dimensions_mpi</command_line>
+    <xsil_file name="fibre_integer_dimensions_mpi.xsil" expected="fibre_integer_dimensions_mpi_expected.xsil" absolute_tolerance="5e-3" relative_tolerance="1e-2" />
+    <xsil_file name="fibre_integer_dimensions_mpi_xspace.xsil" expected="fibre_integer_dimensions_mpi_xspace_expected.xsil" absolute_tolerance="5e-3" relative_tolerance="1e-2" />
+    <xsil_file name="fibre_integer_dimensions_mpi_kspace.xsil" expected="fibre_integer_dimensions_mpi_kspace_expected.xsil" absolute_tolerance="5e-3" relative_tolerance="1e-2" />
+  </testing>
+  <name>fibre_integer_dimensions_mpi</name>
+  <author>Unknown author</author>
+  <description>
+    Example fibre noise simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" lattice="4"   domain="(1, 4)" type="integer"/>
+      <dimension name="x" lattice="64"  domain="(-5, 5)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <features>
+    <auto_vectorise />
+    <error_check />
+    <globals>
+      <![CDATA[
+      const real ggamma = 1.0;
+      const real beta = sqrt(4.0*M_PI*ggamma/10.0);
+      ]]>
+    </globals>
+  </features>
+  
+  <vector name="main" initial_basis="j x" type="complex">
+    <components>phi</components>
+    <initialisation>
+      <![CDATA[
+        phi = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <noise_vector name="noise" kind="wiener" method="solirte" type="complex" seed="293485">
+    <components>n_1</components>
+  </noise_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="2.5" steps="200000">
+      <samples>50</samples>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*kx*kx;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>noise</dependencies>
+        <![CDATA[
+          dphi_dt = L[phi] - ggamma*phi + beta*n_1;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="fibre_integer_dimensions_mpi_xspace_hdf5.xsil" format='hdf5'>
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="fibre_integer_dimensions_mpi_xspace.xsil" format='binary'>
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="fibre_integer_dimensions_mpi_kspace_hdf5.xsil" format='hdf5'>
+      <dependencies basis="j kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="fibre_integer_dimensions_mpi_kspace.xsil" format='binary'>
+      <dependencies basis="j kx">main</dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="j(0) kx" initial_sample="yes">
+        <moments>pow_dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          pow_dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/mpi/fibre_integer_dimensions_mpi_expected.xsil b/testsuite/mpi/fibre_integer_dimensions_mpi_expected.xsil
new file mode 100644
index 0000000..b0f0b5e
--- /dev/null
+++ b/testsuite/mpi/fibre_integer_dimensions_mpi_expected.xsil
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 3 ./fibre_integer_dimensions_mpi</command_line>
+    <xsil_file name="fibre_integer_dimensions_mpi.xsil" expected="fibre_integer_dimensions_mpi_expected.xsil" absolute_tolerance="5e-3" relative_tolerance="1e-2" />
+    <xsil_file name="fibre_integer_dimensions_mpi_xspace.xsil" expected="fibre_integer_dimensions_mpi_xspace_expected.xsil" absolute_tolerance="5e-3" relative_tolerance="1e-2" />
+    <xsil_file name="fibre_integer_dimensions_mpi_kspace.xsil" expected="fibre_integer_dimensions_mpi_kspace_expected.xsil" absolute_tolerance="5e-3" relative_tolerance="1e-2" />
+  </testing>
+  <name>fibre_integer_dimensions_mpi</name>
+  <author>Unknown author</author>
+  <description>
+    Example fibre noise simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" lattice="4"   domain="(1, 4)" type="integer"/>
+      <dimension name="x" lattice="64"  domain="(-5, 5)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <features>
+    <auto_vectorise />
+    <error_check />
+    <globals>
+      <![CDATA[
+      const real ggamma = 1.0;
+      const real beta = sqrt(4.0*M_PI*ggamma/10.0);
+      ]]>
+    </globals>
+  </features>
+  
+  <vector name="main" initial_basis="j x" type="complex">
+    <components>phi</components>
+    <initialisation>
+      <![CDATA[
+        phi = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <noise_vector name="noise" kind="wiener" method="solirte" type="complex" seed="293485">
+    <components>n_1</components>
+  </noise_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="2.5" steps="200000">
+      <samples>50</samples>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*kx*kx;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>noise</dependencies>
+        <![CDATA[
+          dphi_dt = L[phi] - ggamma*phi + beta*n_1;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="fibre_integer_dimensions_mpi_xspace_hdf5.xsil" format='hdf5'>
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="fibre_integer_dimensions_mpi_xspace.xsil" format='binary'>
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="fibre_integer_dimensions_mpi_kspace_hdf5.xsil" format='hdf5'>
+      <dependencies basis="j kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="fibre_integer_dimensions_mpi_kspace.xsil" format='binary'>
+      <dependencies basis="j kx">main</dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="j(0) kx" initial_sample="yes">
+        <moments>pow_dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          pow_dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t kx pow_dens error_pow_dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>51</Dim>
+    <Dim>64</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+fibre_integer_dimensions_mpi_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/mpi/fibre_integer_dimensions_mpi_expected_mg0.dat b/testsuite/mpi/fibre_integer_dimensions_mpi_expected_mg0.dat
new file mode 100644
index 0000000..353e98a
Binary files /dev/null and b/testsuite/mpi/fibre_integer_dimensions_mpi_expected_mg0.dat differ
diff --git a/testsuite/mpi/fibre_integer_dimensions_mpi_kspace_expected.dat b/testsuite/mpi/fibre_integer_dimensions_mpi_kspace_expected.dat
new file mode 100644
index 0000000..d7b49d6
Binary files /dev/null and b/testsuite/mpi/fibre_integer_dimensions_mpi_kspace_expected.dat differ
diff --git a/testsuite/mpi/fibre_integer_dimensions_mpi_kspace_expected.xsil b/testsuite/mpi/fibre_integer_dimensions_mpi_kspace_expected.xsil
new file mode 100644
index 0000000..5207304
--- /dev/null
+++ b/testsuite/mpi/fibre_integer_dimensions_mpi_kspace_expected.xsil
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 3 ./fibre_integer_dimensions_mpi</command_line>
+    <xsil_file name="fibre_integer_dimensions_mpi.xsil" expected="fibre_integer_dimensions_mpi_expected.xsil" absolute_tolerance="5e-3" relative_tolerance="1e-2" />
+    <xsil_file name="fibre_integer_dimensions_mpi_xspace.xsil" expected="fibre_integer_dimensions_mpi_xspace_expected.xsil" absolute_tolerance="5e-3" relative_tolerance="1e-2" />
+    <xsil_file name="fibre_integer_dimensions_mpi_kspace.xsil" expected="fibre_integer_dimensions_mpi_kspace_expected.xsil" absolute_tolerance="5e-3" relative_tolerance="1e-2" />
+  </testing>
+  <name>fibre_integer_dimensions_mpi</name>
+  <author>Unknown author</author>
+  <description>
+    Example fibre noise simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" lattice="4"   domain="(1, 4)" type="integer"/>
+      <dimension name="x" lattice="64"  domain="(-5, 5)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <features>
+    <auto_vectorise />
+    <error_check />
+    <globals>
+      <![CDATA[
+      const real ggamma = 1.0;
+      const real beta = sqrt(4.0*M_PI*ggamma/10.0);
+      ]]>
+    </globals>
+  </features>
+  
+  <vector name="main" initial_basis="j x" type="complex">
+    <components>phi</components>
+    <initialisation>
+      <![CDATA[
+        phi = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <noise_vector name="noise" kind="wiener" method="solirte" type="complex" seed="293485">
+    <components>n_1</components>
+  </noise_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="2.5" steps="200000">
+      <samples>50</samples>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*kx*kx;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>noise</dependencies>
+        <![CDATA[
+          dphi_dt = L[phi] - ggamma*phi + beta*n_1;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="fibre_integer_dimensions_mpi_xspace_hdf5.xsil" format='hdf5'>
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="fibre_integer_dimensions_mpi_xspace.xsil" format='binary'>
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="fibre_integer_dimensions_mpi_kspace_hdf5.xsil" format='hdf5'>
+      <dependencies basis="j kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="fibre_integer_dimensions_mpi_kspace.xsil" format='binary'>
+      <dependencies basis="j kx">main</dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="j(0) kx" initial_sample="yes">
+        <moments>pow_dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          pow_dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+j kx phiR phiI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>4</Dim>
+    <Dim>64</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+fibre_integer_dimensions_mpi_kspace_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/mpi/fibre_integer_dimensions_mpi_xspace_expected.dat b/testsuite/mpi/fibre_integer_dimensions_mpi_xspace_expected.dat
new file mode 100644
index 0000000..ccfab73
Binary files /dev/null and b/testsuite/mpi/fibre_integer_dimensions_mpi_xspace_expected.dat differ
diff --git a/testsuite/mpi/fibre_integer_dimensions_mpi_xspace_expected.xsil b/testsuite/mpi/fibre_integer_dimensions_mpi_xspace_expected.xsil
new file mode 100644
index 0000000..126b887
--- /dev/null
+++ b/testsuite/mpi/fibre_integer_dimensions_mpi_xspace_expected.xsil
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 3 ./fibre_integer_dimensions_mpi</command_line>
+    <xsil_file name="fibre_integer_dimensions_mpi.xsil" expected="fibre_integer_dimensions_mpi_expected.xsil" absolute_tolerance="5e-3" relative_tolerance="1e-2" />
+    <xsil_file name="fibre_integer_dimensions_mpi_xspace.xsil" expected="fibre_integer_dimensions_mpi_xspace_expected.xsil" absolute_tolerance="5e-3" relative_tolerance="1e-2" />
+    <xsil_file name="fibre_integer_dimensions_mpi_kspace.xsil" expected="fibre_integer_dimensions_mpi_kspace_expected.xsil" absolute_tolerance="5e-3" relative_tolerance="1e-2" />
+  </testing>
+  <name>fibre_integer_dimensions_mpi</name>
+  <author>Unknown author</author>
+  <description>
+    Example fibre noise simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" lattice="4"   domain="(1, 4)" type="integer"/>
+      <dimension name="x" lattice="64"  domain="(-5, 5)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <features>
+    <auto_vectorise />
+    <error_check />
+    <globals>
+      <![CDATA[
+      const real ggamma = 1.0;
+      const real beta = sqrt(4.0*M_PI*ggamma/10.0);
+      ]]>
+    </globals>
+  </features>
+  
+  <vector name="main" initial_basis="j x" type="complex">
+    <components>phi</components>
+    <initialisation>
+      <![CDATA[
+        phi = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <noise_vector name="noise" kind="wiener" method="solirte" type="complex" seed="293485">
+    <components>n_1</components>
+  </noise_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="2.5" steps="200000">
+      <samples>50</samples>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*kx*kx;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>noise</dependencies>
+        <![CDATA[
+          dphi_dt = L[phi] - ggamma*phi + beta*n_1;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="fibre_integer_dimensions_mpi_xspace_hdf5.xsil" format='hdf5'>
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="fibre_integer_dimensions_mpi_xspace.xsil" format='binary'>
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="fibre_integer_dimensions_mpi_kspace_hdf5.xsil" format='hdf5'>
+      <dependencies basis="j kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="fibre_integer_dimensions_mpi_kspace.xsil" format='binary'>
+      <dependencies basis="j kx">main</dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="j(0) kx" initial_sample="yes">
+        <moments>pow_dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          pow_dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+j x phiR phiI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>4</Dim>
+    <Dim>64</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+fibre_integer_dimensions_mpi_xspace_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/mpi/hermitegauss_transform_2d_mpi.xmds b/testsuite/mpi/hermitegauss_transform_2d_mpi.xmds
new file mode 100644
index 0000000..7ad1708
--- /dev/null
+++ b/testsuite/mpi/hermitegauss_transform_2d_mpi.xmds
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 3 ./hermitegauss_transform_2d_mpi</command_line>
+    <xsil_file name="hermitegauss_transform_2d_mpi.xsil" expected="hermitegauss_transform_2d_mpi_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+  </testing>
+
+  <name>hermitegauss_transform_2d_mpi</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the Schroedinger equation in 2D using the hermite-Gauss basis.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <validation kind="run-time" />
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="10" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+      <dimension name="y" lattice="10" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+        // initial state is the groundstate in the x axis, but shifted by offset
+      psi = pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.5*(M*omega/hbar)*(x - offset)*(x - offset));
+        // and an expanded gaussian in the y axis
+      psi *= pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.25*(M*omega/hbar)*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>N integral_y2</components>
+    <evaluation>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        N = mod2(psi);
+        integral_y2 = mod2(psi)*y*y;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-6" interval="1e-3" steps="400">
+      <samples>10 1 100</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="nx ny">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*(nx + ny + 1.0)*omega;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dpsi_dt = L[psi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="nx ny" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(0)" initial_sample="yes">
+        <moments>mean_x mean_sigmay</moments>
+        <dependencies>main normalisation</dependencies>
+        <![CDATA[
+          mean_x = mod2(psi)*x/N;
+          mean_sigmay = sqrt(integral_y2/N);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/mpi/hermitegauss_transform_2d_mpi_expected.xsil b/testsuite/mpi/hermitegauss_transform_2d_mpi_expected.xsil
new file mode 100644
index 0000000..f849e0b
--- /dev/null
+++ b/testsuite/mpi/hermitegauss_transform_2d_mpi_expected.xsil
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 3 ./hermitegauss_transform_2d_mpi</command_line>
+    <xsil_file name="hermitegauss_transform_2d_mpi.xsil" expected="hermitegauss_transform_2d_mpi_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+  </testing>
+
+  <name>hermitegauss_transform_2d_mpi</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the Schroedinger equation in 2D using the hermite-Gauss basis.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <validation kind="run-time" />
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="10" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+      <dimension name="y" lattice="10" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+        // initial state is the groundstate in the x axis, but shifted by offset
+      psi = pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.5*(M*omega/hbar)*(x - offset)*(x - offset));
+        // and an expanded gaussian in the y axis
+      psi *= pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.25*(M*omega/hbar)*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>N integral_y2</components>
+    <evaluation>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        N = mod2(psi);
+        integral_y2 = mod2(psi)*y*y;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-6" interval="1e-3" steps="400">
+      <samples>10 1 100</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="nx ny">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*(nx + ny + 1.0)*omega;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dpsi_dt = L[psi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="nx ny" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(0)" initial_sample="yes">
+        <moments>mean_x mean_sigmay</moments>
+        <dependencies>main normalisation</dependencies>
+        <![CDATA[
+          mean_x = mod2(psi)*x/N;
+          mean_sigmay = sqrt(integral_y2/N);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t x y dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>11</Dim>
+    <Dim>10</Dim>
+    <Dim>10</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+hermitegauss_transform_2d_mpi_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+nx ny dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>10</Dim>
+    <Dim>10</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+hermitegauss_transform_2d_mpi_expected_mg1.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_3">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t mean_x mean_sigmay 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>101</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+hermitegauss_transform_2d_mpi_expected_mg2.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/mpi/hermitegauss_transform_2d_mpi_expected_mg0.dat b/testsuite/mpi/hermitegauss_transform_2d_mpi_expected_mg0.dat
new file mode 100644
index 0000000..8c050d8
Binary files /dev/null and b/testsuite/mpi/hermitegauss_transform_2d_mpi_expected_mg0.dat differ
diff --git a/testsuite/mpi/hermitegauss_transform_2d_mpi_expected_mg1.dat b/testsuite/mpi/hermitegauss_transform_2d_mpi_expected_mg1.dat
new file mode 100644
index 0000000..4b76f04
Binary files /dev/null and b/testsuite/mpi/hermitegauss_transform_2d_mpi_expected_mg1.dat differ
diff --git a/testsuite/mpi/hermitegauss_transform_2d_mpi_expected_mg2.dat b/testsuite/mpi/hermitegauss_transform_2d_mpi_expected_mg2.dat
new file mode 100644
index 0000000..fc86dce
Binary files /dev/null and b/testsuite/mpi/hermitegauss_transform_2d_mpi_expected_mg2.dat differ
diff --git a/testsuite/mpi/hermitegauss_transform_2d_mpi_small.xmds b/testsuite/mpi/hermitegauss_transform_2d_mpi_small.xmds
new file mode 100644
index 0000000..aad403b
--- /dev/null
+++ b/testsuite/mpi/hermitegauss_transform_2d_mpi_small.xmds
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 8 ./hermitegauss_transform_2d_mpi_small</command_line>
+    <xsil_file name="hermitegauss_transform_2d_mpi_small.xsil" expected="hermitegauss_transform_2d_mpi_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+  </testing>
+
+  <name>hermitegauss_transform_2d_mpi_small</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the Schroedinger equation in 2D using the hermite-Gauss basis.
+	
+	Checking that when the number of processes is of the same order as the number of grid points that things don't go awry
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <validation kind="run-time" />
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="10" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+      <dimension name="y" lattice="10" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+        // initial state is the groundstate in the x axis, but shifted by offset
+      psi = pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.5*(M*omega/hbar)*(x - offset)*(x - offset));
+        // and an expanded gaussian in the y axis
+      psi *= pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.25*(M*omega/hbar)*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>N integral_y2</components>
+    <evaluation>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        N = mod2(psi);
+        integral_y2 = mod2(psi)*y*y;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-6" interval="1e-3" steps="400">
+      <samples>10 1 100</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="nx ny">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*(nx + ny + 1.0)*omega;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dpsi_dt = L[psi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="nx ny" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(0)" initial_sample="yes">
+        <moments>mean_x mean_sigmay</moments>
+        <dependencies>main normalisation</dependencies>
+        <![CDATA[
+          mean_x = mod2(psi)*x/N;
+          mean_sigmay = sqrt(integral_y2/N);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/mpi/kubo_integer_dimensions_mpi.xmds b/testsuite/mpi/kubo_integer_dimensions_mpi.xmds
new file mode 100644
index 0000000..490509e
--- /dev/null
+++ b/testsuite/mpi/kubo_integer_dimensions_mpi.xmds
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 2 ./kubo_integer_dimensions_mpi</command_line>
+    <xsil_file name="kubo_integer_dimensions_mpi.xsil" expected="kubo_integer_dimensions_mpi_expected.xsil" absolute_tolerance="5e-2" relative_tolerance="1e-1" />
+    <xsil_file name="kubo_integer_dimensions_mpi_break.xsil" expected="kubo_integer_dimensions_mpi_break_expected.xsil" absolute_tolerance="5e-2" relative_tolerance="1e-1" />
+  </testing>
+  
+  <name>kubo_integer_dimensions_mpi</name>
+  <author>Graham Dennis</author>
+  <description>
+    Example Kubo oscillator simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" type="integer" lattice="1024" domain="(1, 1024)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" type="complex">
+    <components>
+      z
+    </components>
+    <initialisation>
+      <![CDATA[
+        z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <noise_vector name="noise" kind="wiener" type="real" seed="157 9348 234">
+    <components>n_1</components>
+  </noise_vector>
+  
+  <sequence>
+    <integrate algorithm="RK9" interval="10" steps="1000" tolerance="1e-8">
+      <samples>500 10</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>noise</dependencies>
+        <![CDATA[
+          dz_dt(j => j) = i*z*n_1;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="kubo_integer_dimensions_mpi_break.xsil">
+      <dependencies>main</dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="j(0)" initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          zR = z.Re()/_lattice_j;
+          zI = z.Im()/_lattice_j;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="j" initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+            _SAMPLE_COMPLEX(z);
+          zR = z.Re();
+          zI = z.Im();
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/mpi/kubo_integer_dimensions_mpi_break_expected.dat b/testsuite/mpi/kubo_integer_dimensions_mpi_break_expected.dat
new file mode 100644
index 0000000..a21a25b
Binary files /dev/null and b/testsuite/mpi/kubo_integer_dimensions_mpi_break_expected.dat differ
diff --git a/testsuite/mpi/kubo_integer_dimensions_mpi_break_expected.xsil b/testsuite/mpi/kubo_integer_dimensions_mpi_break_expected.xsil
new file mode 100644
index 0000000..b1a5114
--- /dev/null
+++ b/testsuite/mpi/kubo_integer_dimensions_mpi_break_expected.xsil
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 2 ./kubo_integer_dimensions_mpi</command_line>
+    <xsil_file name="kubo_integer_dimensions_mpi.xsil" expected="kubo_integer_dimensions_mpi_expected.xsil" absolute_tolerance="5e-2" relative_tolerance="1e-1" />
+    <xsil_file name="kubo_integer_dimensions_mpi_break.xsil" expected="kubo_integer_dimensions_mpi_break_expected.xsil" absolute_tolerance="5e-2" relative_tolerance="1e-1" />
+  </testing>
+  
+  <name>kubo_integer_dimensions_mpi</name>
+  <author>Graham Dennis</author>
+  <description>
+    Example Kubo oscillator simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" type="integer" lattice="1024" domain="(1, 1024)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <features>
+    <benchmark />
+    <bing />
+    <stochastic>
+      <noise kind="gaussian" prefix="n" num="1" seed="157 9348 234"/>
+      <!-- If there is no seed attribute then seeds will be chosen randomly at run-time -->
+    </stochastic>
+  </features>
+  
+  <vector name="main" type="complex">
+    <components>
+      z
+    </components>
+    <initialisation noises="">
+      <![CDATA[
+        z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK9" interval="10" steps="1000" tolerance="1e-8">
+      <samples>500 10</samples>
+      <operators noises="n">
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dz_dt(j => j) = i*z*n_1;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="kubo_integer_dimensions_mpi_break.xsil">
+      <dependencies>main</dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="j(0)" initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          zR = z.Re()/_lattice_j;
+          zI = z.Im()/_lattice_j;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="j" initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+            _SAMPLE_COMPLEX(z);
+          zR = z.Re();
+          zI = z.Im();
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+j zR zI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>1024</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+kubo_integer_dimensions_mpi_break_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/mpi/kubo_integer_dimensions_mpi_expected.xsil b/testsuite/mpi/kubo_integer_dimensions_mpi_expected.xsil
new file mode 100644
index 0000000..9516d32
--- /dev/null
+++ b/testsuite/mpi/kubo_integer_dimensions_mpi_expected.xsil
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 2 ./kubo_integer_dimensions_mpi</command_line>
+    <xsil_file name="kubo_integer_dimensions_mpi.xsil" expected="kubo_integer_dimensions_mpi_expected.xsil" absolute_tolerance="5e-2" relative_tolerance="1e-1" />
+    <xsil_file name="kubo_integer_dimensions_mpi_break.xsil" expected="kubo_integer_dimensions_mpi_break_expected.xsil" absolute_tolerance="5e-2" relative_tolerance="1e-1" />
+  </testing>
+  
+  <name>kubo_integer_dimensions_mpi</name>
+  <author>Graham Dennis</author>
+  <description>
+    Example Kubo oscillator simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" type="integer" lattice="1024" domain="(1, 1024)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <features>
+    <benchmark />
+    <bing />
+    <stochastic>
+      <noise kind="gaussian" prefix="n" num="1" seed="157 9348 234"/>
+      <!-- If there is no seed attribute then seeds will be chosen randomly at run-time -->
+    </stochastic>
+  </features>
+  
+  <vector name="main" type="complex">
+    <components>
+      z
+    </components>
+    <initialisation noises="">
+      <![CDATA[
+        z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK9" interval="10" steps="1000" tolerance="1e-8">
+      <samples>500 10</samples>
+      <operators noises="n">
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dz_dt(j => j) = i*z*n_1;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="kubo_integer_dimensions_mpi_break.xsil">
+      <dependencies>main</dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="j(0)" initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          zR = z.Re()/_lattice_j;
+          zI = z.Im()/_lattice_j;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="j" initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+            _SAMPLE_COMPLEX(z);
+          zR = z.Re();
+          zI = z.Im();
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t zR zI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>501</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+kubo_integer_dimensions_mpi_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t j zR zI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>11</Dim>
+    <Dim>1024</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+kubo_integer_dimensions_mpi_expected_mg1.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/mpi/kubo_integer_dimensions_mpi_expected_mg0.dat b/testsuite/mpi/kubo_integer_dimensions_mpi_expected_mg0.dat
new file mode 100644
index 0000000..2244856
Binary files /dev/null and b/testsuite/mpi/kubo_integer_dimensions_mpi_expected_mg0.dat differ
diff --git a/testsuite/mpi/kubo_integer_dimensions_mpi_expected_mg1.dat b/testsuite/mpi/kubo_integer_dimensions_mpi_expected_mg1.dat
new file mode 100644
index 0000000..ed97370
Binary files /dev/null and b/testsuite/mpi/kubo_integer_dimensions_mpi_expected_mg1.dat differ
diff --git a/testsuite/mpi/kubo_mpi_paths.xmds b/testsuite/mpi/kubo_mpi_paths.xmds
new file mode 100644
index 0000000..f0c0fad
--- /dev/null
+++ b/testsuite/mpi/kubo_mpi_paths.xmds
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 2 ./kubo_mpi_paths</command_line>
+    <xsil_file name="kubo_mpi_paths.xsil" expected="kubo_mpi_paths_expected.xsil" absolute_tolerance="4e-2" relative_tolerance="4e-2" />
+  </testing>
+  
+  <name>kubo_mpi_paths</name>
+  <author>Graham Dennis / Michael Hush</author>
+  <description>
+    Example Kubo oscillator simulation 
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <driver name="mpi-multi-path" paths="10000" />
+  
+  <vector name="main">
+    <components type="complex">
+      z
+    </components>
+    <initialisation>
+      <![CDATA[
+        z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <noise_vector name="noise" kind="wiener" type="real">
+    <components>n_1</components>
+  </noise_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" interval="3" steps="1000" tolerance="1e-6">
+      <samples>50 </samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>noise</dependencies>
+        <![CDATA[
+          dz_dt = i*z*n_1;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+            _SAMPLE_COMPLEX(z);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/mpi/kubo_mpi_paths_expected.xsil b/testsuite/mpi/kubo_mpi_paths_expected.xsil
new file mode 100644
index 0000000..6f77413
--- /dev/null
+++ b/testsuite/mpi/kubo_mpi_paths_expected.xsil
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 2 ./kubo_mpi_paths</command_line>
+    <xsil_file name="kubo_mpi_paths.xsil" expected="kubo_mpi_paths_expected.xsil" absolute_tolerance="4e-2" relative_tolerance="4e-2" />
+  </testing>
+  
+  <name>kubo_mpi_paths</name>
+  <author>Graham Dennis / Michael Hush</author>
+  <description>
+    Example Kubo oscillator simulation 
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <driver name="mpi-multi-path" paths="10000" />
+  
+  <features>
+    <benchmark />
+    <bing />
+    <stochastic>
+      <noise kind="gaussian" prefix="n" num="1" />
+      <!-- If there is no seed attribute then seeds will be chosen randomly at run-time -->
+    </stochastic>
+  </features>
+  
+  <vector name="main">
+    <components type="complex">
+      z
+    </components>
+    <initialisation noises="">
+      <![CDATA[
+        z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" interval="3" steps="1000" tolerance="1e-6">
+      <samples>50 </samples>
+      <operators noises="n">
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dz_dt = i*z*n_1;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+            _SAMPLE_COMPLEX(z);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+
+No seeds were provided for noise 'n'. The seeds generated were:
+    57173, 61326, 60708
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t mean_zR mean_zI stderr_zR stderr_zI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>51</Dim>
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+kubo_mpi_paths_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/mpi/kubo_mpi_paths_expected_mg0.dat b/testsuite/mpi/kubo_mpi_paths_expected_mg0.dat
new file mode 100644
index 0000000..23b42be
Binary files /dev/null and b/testsuite/mpi/kubo_mpi_paths_expected_mg0.dat differ
diff --git a/testsuite/mpi/lorenz_mpi.xmds b/testsuite/mpi/lorenz_mpi.xmds
new file mode 100644
index 0000000..1e47a37
--- /dev/null
+++ b/testsuite/mpi/lorenz_mpi.xmds
@@ -0,0 +1,91 @@
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 8 ./lorenz_mpi</command_line>
+    <xsil_file name="lorenz_mpi.xsil" expected="lorenz_mpi_expected.xsil" absolute_tolerance="4e-2" relative_tolerance="4e-2" />
+  </testing>
+  
+  <name>lorenz_mpi</name>
+  
+  <!-- While not strictly necessary, the following two tags are handy. -->
+  <author>Graham Dennis</author>
+  <description>
+    The Lorenz Attractor, an example of chaos.
+    
+    This example is designed to check that when the number of processors is of the same order
+    as the number of lattice points that things don't go awry
+  </description>
+  
+  <!-- 
+  This element defines some constants.  It can be used for other 
+  features as well, but we will go into that in more detail later.
+  -->
+  <features>
+    <globals>
+        <![CDATA[
+        real b = 8.0/3.0;
+        real r = 28.0;
+        ]]>
+     </globals>
+     <arguments>
+         <![CDATA[
+             printf("Hello from rank %i\n", _rank);
+         ]]>
+     </arguments>
+   </features>
+   
+  <!-- 
+  This part defines all of the dimensions used in the problem,
+  in this case, only the dimension of 'time' is needed.
+  -->
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+        <dimension name="sigma" domain="(5.0,15.0)" lattice="10" transform="none"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <!-- A 'vector' describes the variables that we will be evolving. -->
+  <vector name="position" type="real">
+    <components>
+      x y z
+    </components>
+    <initialisation>
+      <![CDATA[
+      x = y = z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <!--
+    Here we define what differential equations need to be solved
+    and what algorithm we want to use.
+    -->
+    <integrate algorithm="ARK89" interval="20.0" tolerance="1e-7">
+      <samples>5</samples>
+      <operators>
+        <integration_vectors>position</integration_vectors>
+        <![CDATA[
+        dx_dt = sigma*(y-x);
+        dy_dt = r*x - y - x*z;
+        dz_dt = x*y - b*z;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <!-- This part defines what data will be saved in the output file -->
+  <output format="binary">
+      <sampling_group basis="sigma" initial_sample="yes">
+        <moments>xR yR zR</moments>
+        <dependencies>position</dependencies>
+        <![CDATA[
+          xR = x;
+          yR = y;
+          zR = z;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/mpi/lorenz_mpi_expected.xsil b/testsuite/mpi/lorenz_mpi_expected.xsil
new file mode 100644
index 0000000..61857d4
--- /dev/null
+++ b/testsuite/mpi/lorenz_mpi_expected.xsil
@@ -0,0 +1,116 @@
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 8 ./lorenz_mpi</command_line>
+    <xsil_file name="lorenz_mpi.xsil" expected="lorenz_mpi_expected.xsil" absolute_tolerance="4e-2" relative_tolerance="4e-2" />
+  </testing>
+  
+  <name>lorenz_mpi</name>
+  
+  <!-- While not strictly necessary, the following two tags are handy. -->
+  <author>Graham Dennis</author>
+  <description>
+    The Lorenz Attractor, an example of chaos.
+    
+    This example is designed to check that when the number of processors is of the same order
+    as the number of lattice points that things don't go awry
+  </description>
+  
+  <!-- 
+  This element defines some constants.  It can be used for other 
+  features as well, but we will go into that in more detail later.
+  -->
+  <features>
+    <globals>
+        <![CDATA[
+        real b = 8.0/3.0;
+        real r = 28.0;
+        ]]>
+     </globals>
+     <arguments>
+         <![CDATA[
+             printf("Hello from rank %i\n", _rank);
+         ]]>
+     </arguments>
+   </features>
+   
+  <!-- 
+  This part defines all of the dimensions used in the problem,
+  in this case, only the dimension of 'time' is needed.
+  -->
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+        <dimension name="sigma" domain="(5.0,15.0)" lattice="10" transform="none"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <!-- A 'vector' describes the variables that we will be evolving. -->
+  <vector name="position" type="real">
+    <components>
+      x y z
+    </components>
+    <initialisation>
+      <![CDATA[
+      x = y = z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <!--
+    Here we define what differential equations need to be solved
+    and what algorithm we want to use.
+    -->
+    <integrate algorithm="ARK89" interval="20.0" tolerance="1e-7">
+      <samples>5</samples>
+      <operators>
+        <integration_vectors>position</integration_vectors>
+        <![CDATA[
+        dx_dt = sigma*(y-x);
+        dy_dt = r*x - y - x*z;
+        dz_dt = x*y - b*z;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <!-- This part defines what data will be saved in the output file -->
+  <output format="binary">
+      <sampling_group basis="sigma" initial_sample="yes">
+        <moments>xR yR zR</moments>
+        <dependencies>position</dependencies>
+        <![CDATA[
+          xR = x;
+          yR = y;
+          zR = z;
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+
+Variables that can be specified on the command line:
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t sigma xR yR zR 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>6</Dim>
+    <Dim>10</Dim>
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+lorenz_mpi_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/mpi/lorenz_mpi_expected_mg0.dat b/testsuite/mpi/lorenz_mpi_expected_mg0.dat
new file mode 100644
index 0000000..3ef9c8e
Binary files /dev/null and b/testsuite/mpi/lorenz_mpi_expected_mg0.dat differ
diff --git a/testsuite/mpi/mpi_dft.xmds b/testsuite/mpi/mpi_dft.xmds
new file mode 100644
index 0000000..c8b30e5
--- /dev/null
+++ b/testsuite/mpi/mpi_dft.xmds
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 3 ./mpi_dft</command_line>
+    <xsil_file name="mpi_dft_xspace1.xsil" expected="mpi_dft_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_kspace.xsil" expected="mpi_dft_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_kspace2.xsil" expected="mpi_dft_kspace2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_xspace2.xsil" expected="mpi_dft_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  
+  <name>mpi_dft</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test of the fourier transforms using MPI.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="32"  domain="(-1, 1)" />
+      <dimension name="y" lattice="32"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      u
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="mpi_dft_xspace1.xsil">
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_kspace.xsil">
+      <dependencies basis="ky kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_kspace2.xsil">
+      <dependencies basis="ky x">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_xspace2.xsil">
+      <dependencies basis="y x">main</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/mpi/mpi_dft_hdf5.xmds b/testsuite/mpi/mpi_dft_hdf5.xmds
new file mode 100644
index 0000000..b873eb5
--- /dev/null
+++ b/testsuite/mpi/mpi_dft_hdf5.xmds
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 3 ./mpi_dft_hdf5</command_line>
+    <xsil_file name="mpi_dft_hdf5_xspace1.xsil" expected="mpi_dft_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_hdf5_kspace.xsil" expected="mpi_dft_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_hdf5_kspace2.xsil" expected="mpi_dft_kspace2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_hdf5_xspace2.xsil" expected="mpi_dft_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  
+  <name>mpi_dft_hdf5</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test of the fourier transforms using MPI.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="32"  domain="(-1, 1)" />
+      <dimension name="y" lattice="32"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      u
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="mpi_dft_hdf5_xspace1.xsil" format="hdf5">
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_hdf5_kspace.xsil" format="hdf5">
+      <dependencies basis="ky kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_hdf5_kspace2.xsil" format="hdf5">
+      <dependencies basis="ky x">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_hdf5_xspace2.xsil" format="hdf5">
+      <dependencies basis="y x">main</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/mpi/mpi_dft_kspace2_expected.dat b/testsuite/mpi/mpi_dft_kspace2_expected.dat
new file mode 100644
index 0000000..152ec35
Binary files /dev/null and b/testsuite/mpi/mpi_dft_kspace2_expected.dat differ
diff --git a/testsuite/mpi/mpi_dft_kspace2_expected.xsil b/testsuite/mpi/mpi_dft_kspace2_expected.xsil
new file mode 100644
index 0000000..e99b682
--- /dev/null
+++ b/testsuite/mpi/mpi_dft_kspace2_expected.xsil
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 3 ./mpi_dft</command_line>
+    <xsil_file name="mpi_dft_xspace1.xsil" expected="mpi_dft_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_kspace.xsil" expected="mpi_dft_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_kspace2.xsil" expected="mpi_dft_kspace2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_xspace2.xsil" expected="mpi_dft_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  
+  <name>mpi_dft</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test of the fourier transforms using MPI.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <openmp />
+    <globals>
+      <![CDATA[
+      const double T = 10.0;
+      const double mass = 1e-3;
+      const double length = 1.0;
+      const double mu = mass/length;
+      
+      const double xmax = _xy_max_x;
+      const double width = 0.1;
+      const double absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="32"  domain="(-1, 1)" />
+      <dimension name="y" lattice="32"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      u
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="mpi_dft_xspace1.xsil">
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_kspace.xsil">
+      <dependencies fourier_space="ky kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_kspace2.xsil">
+      <dependencies fourier_space="ky x">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_xspace2.xsil">
+      <dependencies fourier_space="y x">main</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x ky uR uI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>32</Dim>
+    <Dim>32</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+mpi_dft_kspace2_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/mpi/mpi_dft_kspace_expected.dat b/testsuite/mpi/mpi_dft_kspace_expected.dat
new file mode 100644
index 0000000..c2b2d1f
Binary files /dev/null and b/testsuite/mpi/mpi_dft_kspace_expected.dat differ
diff --git a/testsuite/mpi/mpi_dft_kspace_expected.xsil b/testsuite/mpi/mpi_dft_kspace_expected.xsil
new file mode 100644
index 0000000..cf1e3be
--- /dev/null
+++ b/testsuite/mpi/mpi_dft_kspace_expected.xsil
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 3 ./mpi_dft</command_line>
+    <xsil_file name="mpi_dft_xspace1.xsil" expected="mpi_dft_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_kspace.xsil" expected="mpi_dft_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_xspace2.xsil" expected="mpi_dft_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  
+  <name>mpi_dft</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test of the fourier transforms using MPI.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <openmp />
+    <globals>
+      <![CDATA[
+      const double T = 10.0;
+      const double mass = 1e-3;
+      const double length = 1.0;
+      const double mu = mass/length;
+      
+      const double xmax = _xy_max_x;
+      const double width = 0.1;
+      const double absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="32"  domain="(-1, 1)" />
+      <dimension name="y" lattice="32"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      u
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="mpi_dft_xspace1.xsil">
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_kspace.xsil">
+      <dependencies fourier_space="ky kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_xspace2.xsil">
+      <dependencies fourier_space="y x">main</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+kx ky uR uI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>32</Dim>
+    <Dim>32</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+mpi_dft_kspace_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/mpi/mpi_dft_small.xmds b/testsuite/mpi/mpi_dft_small.xmds
new file mode 100644
index 0000000..cd68282
--- /dev/null
+++ b/testsuite/mpi/mpi_dft_small.xmds
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 8 ./mpi_dft_small</command_line>
+    <xsil_file name="mpi_dft_small_xspace1.xsil" expected="mpi_dft_small_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_small_kspace.xsil"  expected="mpi_dft_small_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_small_kspace2.xsil" expected="mpi_dft_small_kspace2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_small_xspace2.xsil" expected="mpi_dft_small_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  
+  <name>mpi_dft_small</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test of the fourier transforms using MPI.
+    
+    Checking that when the number of processors is of the same order as the number of grid points that things don't go awry
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="10"  domain="(-1, 1)" />
+      <dimension name="y" lattice="10"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      u
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="mpi_dft_small_xspace1.xsil">
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_small_kspace.xsil">
+      <dependencies basis="ky kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_small_kspace2.xsil">
+      <dependencies basis="ky x">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_small_xspace2.xsil">
+      <dependencies basis="y x">main</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/mpi/mpi_dft_small_kspace2_expected.dat b/testsuite/mpi/mpi_dft_small_kspace2_expected.dat
new file mode 100644
index 0000000..386486b
Binary files /dev/null and b/testsuite/mpi/mpi_dft_small_kspace2_expected.dat differ
diff --git a/testsuite/mpi/mpi_dft_small_kspace2_expected.xsil b/testsuite/mpi/mpi_dft_small_kspace2_expected.xsil
new file mode 100644
index 0000000..b7b9182
--- /dev/null
+++ b/testsuite/mpi/mpi_dft_small_kspace2_expected.xsil
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 8 ./mpi_dft_small</command_line>
+    <xsil_file name="mpi_dft_small_xspace1.xsil" expected="mpi_dft_small_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_small_kspace.xsil"  expected="mpi_dft_small_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_small_kspace2.xsil" expected="mpi_dft_small_kspace2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_small_xspace2.xsil" expected="mpi_dft_small_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  
+  <name>mpi_dft_small</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test of the fourier transforms using MPI.
+    
+    Checking that when the number of processors is of the same order as the number of grid points that things don't go awry
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <openmp />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="10"  domain="(-1, 1)" />
+      <dimension name="y" lattice="10"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      u
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="mpi_dft_small_xspace1.xsil">
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_small_kspace.xsil">
+      <dependencies basis="ky kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_small_kspace2.xsil">
+      <dependencies basis="ky x">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_small_xspace2.xsil">
+      <dependencies basis="y x">main</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x ky uR uI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>10</Dim>
+    <Dim>10</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+mpi_dft_small_kspace2_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/mpi/mpi_dft_small_kspace_expected.dat b/testsuite/mpi/mpi_dft_small_kspace_expected.dat
new file mode 100644
index 0000000..c388076
Binary files /dev/null and b/testsuite/mpi/mpi_dft_small_kspace_expected.dat differ
diff --git a/testsuite/mpi/mpi_dft_small_kspace_expected.xsil b/testsuite/mpi/mpi_dft_small_kspace_expected.xsil
new file mode 100644
index 0000000..7990520
--- /dev/null
+++ b/testsuite/mpi/mpi_dft_small_kspace_expected.xsil
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 8 ./mpi_dft_small</command_line>
+    <xsil_file name="mpi_dft_small_xspace1.xsil" expected="mpi_dft_small_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_small_kspace.xsil"  expected="mpi_dft_small_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_small_kspace2.xsil" expected="mpi_dft_small_kspace2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_small_xspace2.xsil" expected="mpi_dft_small_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  
+  <name>mpi_dft_small</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test of the fourier transforms using MPI.
+    
+    Checking that when the number of processors is of the same order as the number of grid points that things don't go awry
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <openmp />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="10"  domain="(-1, 1)" />
+      <dimension name="y" lattice="10"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      u
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="mpi_dft_small_xspace1.xsil">
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_small_kspace.xsil">
+      <dependencies basis="ky kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_small_kspace2.xsil">
+      <dependencies basis="ky x">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_small_xspace2.xsil">
+      <dependencies basis="y x">main</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+kx ky uR uI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>10</Dim>
+    <Dim>10</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+mpi_dft_small_kspace_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/mpi/mpi_dft_small_xspace_expected.dat b/testsuite/mpi/mpi_dft_small_xspace_expected.dat
new file mode 100644
index 0000000..1ed4cc8
Binary files /dev/null and b/testsuite/mpi/mpi_dft_small_xspace_expected.dat differ
diff --git a/testsuite/mpi/mpi_dft_small_xspace_expected.xsil b/testsuite/mpi/mpi_dft_small_xspace_expected.xsil
new file mode 100644
index 0000000..80cd54c
--- /dev/null
+++ b/testsuite/mpi/mpi_dft_small_xspace_expected.xsil
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 8 ./mpi_dft_small</command_line>
+    <xsil_file name="mpi_dft_small_xspace1.xsil" expected="mpi_dft_small_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_small_kspace.xsil"  expected="mpi_dft_small_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_small_kspace2.xsil" expected="mpi_dft_small_kspace2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_small_xspace2.xsil" expected="mpi_dft_small_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  
+  <name>mpi_dft_small</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test of the fourier transforms using MPI.
+    
+    Checking that when the number of processors is of the same order as the number of grid points that things don't go awry
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <openmp />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="10"  domain="(-1, 1)" />
+      <dimension name="y" lattice="10"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      u
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="mpi_dft_small_xspace1.xsil">
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_small_kspace.xsil">
+      <dependencies basis="ky kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_small_kspace2.xsil">
+      <dependencies basis="ky x">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_small_xspace2.xsil">
+      <dependencies basis="y x">main</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x y uR uI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>10</Dim>
+    <Dim>10</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+mpi_dft_small_xspace_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/mpi/mpi_dft_xspace_expected.dat b/testsuite/mpi/mpi_dft_xspace_expected.dat
new file mode 100644
index 0000000..b0433bb
Binary files /dev/null and b/testsuite/mpi/mpi_dft_xspace_expected.dat differ
diff --git a/testsuite/mpi/mpi_dft_xspace_expected.xsil b/testsuite/mpi/mpi_dft_xspace_expected.xsil
new file mode 100644
index 0000000..475a83b
--- /dev/null
+++ b/testsuite/mpi/mpi_dft_xspace_expected.xsil
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 3 ./mpi_dft</command_line>
+    <xsil_file name="mpi_dft_xspace1.xsil" expected="mpi_dft_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_kspace.xsil" expected="mpi_dft_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="mpi_dft_xspace2.xsil" expected="mpi_dft_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  
+  <name>mpi_dft</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test of the fourier transforms using MPI.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <openmp />
+    <globals>
+      <![CDATA[
+      const double T = 10.0;
+      const double mass = 1e-3;
+      const double length = 1.0;
+      const double mu = mass/length;
+      
+      const double xmax = _xy_max_x;
+      const double width = 0.1;
+      const double absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="32"  domain="(-1, 1)" />
+      <dimension name="y" lattice="32"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      u
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="mpi_dft_xspace1.xsil">
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_kspace.xsil">
+      <dependencies fourier_space="ky kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="mpi_dft_xspace2.xsil">
+      <dependencies fourier_space="y x">main</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x y uR uI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>32</Dim>
+    <Dim>32</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+mpi_dft_xspace_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/mpi/mpi_highdimcrossprop.xmds b/testsuite/mpi/mpi_highdimcrossprop.xmds
new file mode 100644
index 0000000..06ef645
--- /dev/null
+++ b/testsuite/mpi/mpi_highdimcrossprop.xmds
@@ -0,0 +1,226 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 2 ./mpi_highdimcrossprop</command_line>
+    <xsil_file name="mpi_highdimcrossprop.xsil" expected="../operators/highdimcrossprop_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-4" />
+  </testing>
+  <name>mpi_highdimcrossprop</name>
+  
+  <features>
+    <benchmark />
+   
+    <bing />
+      <globals>
+<![CDATA[
+const real pi=3.14159265358979;
+const real g =2*pi*11.4005; // Sqrt(density)/Hz
+const real sample_length = 0.2; //m
+const real time_input =2.5e-6; // sec (5)
+const real sigma=1e-6; // sec (2)
+const real inp_hgt=1e3; //photonnum
+const real gama=2*pi*5.6e6; //Hz
+const real eta =2*pi*10e6/sample_length; //Hz/m (was 2*pi*10e6)
+const real omc=2*pi*20e6; //Hz (was 2*pi*20e6)
+
+const real gama0=0; //2*pi*2e3; //Hz
+const real gamac=0; //2*pi*1e3; //Hz
+const real c=3e8; // m/s
+const real timeswitchz=10e-6; // sec (10)
+
+const real N=1e18; // density 
+const real gNonc = g*N/c; 
+const real delta=2*pi*3e9; //Hz
+
+const real width = 0.001; //m
+const real k0 = 6.28 / (795e-9);
+
+const real alpha=0.00; //m^2/s
+
+]]> 
+  </globals>
+    
+  </features>
+  <driver name="distributed-mpi" />
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+	   <dimension name="x" lattice="16" domain="(-0.004,0.004)"  /> 
+	   <dimension name="y" lattice="16" domain="(-0.003,0.003)"  /> 
+	   <dimension name="z" lattice="512"  domain="(0,0.2)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="z x y" type="complex">
+    <components>
+    alpha12
+    </components>
+    <initialisation>
+      <![CDATA[
+      alpha12 =  0.0;
+    
+      ]]>
+    </initialisation>
+  </vector>
+
+    <vector name="crossinitial" initial_basis="x y" type="complex">
+    <components>
+    beamprofile
+    </components>
+    <initialisation>
+      <![CDATA[
+      beamprofile=inp_hgt * (2*sqrt(2)*x/width) * exp(-x*x/(width*width)) * exp(-y*y/(width*width))* exp(-i*k0*(x*x+y*y)/0.5);
+      ]]>
+    </initialisation>
+  </vector>
+
+<vector name="cross1" initial_basis="x y z" type="complex">
+    <components>
+     E
+    </components>
+  </vector>
+  
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="20e-8" steps="20" tolerance="1.0e-6">
+          <samples>2 1 2 2 1 1 1 1 1 1</samples>
+      
+       <operators>
+        <operator kind="cross_propagation" algorithm="RK4"  propagation_dimension="z">
+            <operator kind="ip" constant="yes">
+              <operator_names>Btt</operator_names>
+              <![CDATA[
+                Btt = 0; //i*(kx*kx + ky*ky)/(2*k0);
+              ]]>
+            </operator>
+
+          <integration_vectors>cross1</integration_vectors>
+          <!-- You can have a dependencies tag in here -->
+          <dependencies>main</dependencies>
+          <boundary_condition kind="left">
+            <!-- You can also have a dependencies tag in here -->
+            <!-- like the one shown below, but none are needed -->
+            <!-- in this example -->
+			<dependencies>crossinitial</dependencies> 
+      <![CDATA[
+	  
+	  //E=inp_hgt*exp(-(t-time_input)*(t-time_input)/(sigma*sigma)) * exp(-x*x/(width*width))*exp(-y*y/(width*width));
+	  E = exp(-(t-time_input)*(t-time_input)/(sigma*sigma)) * beamprofile;
+			
+			]]>
+          </boundary_condition>
+          <![CDATA[
+      complex aalpha13 = (alpha12*omc+g*E)/delta;
+	  
+	  dE_dz =  i*gNonc*(aalpha13) + Btt[E]; 
+	   
+          ]]>
+        </operator>
+           <operator kind="ip" constant="yes">
+              <operator_names>Ltt</operator_names>
+              <![CDATA[
+                Ltt = -alpha*(kz*kz+kx*kx+ky*ky);
+              ]]>
+            </operator>
+        
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+
+complex sw  = -1.0; //( t<timeswitchz ? -1.0:1.0);
+
+complex aalpha13 = (alpha12*omc+g*E)/(delta-i*(gamac/2+gama+gama0/2));
+dalpha12_dt  = ((-gama0 - gamac-i*(sw*eta*(z-sample_length/2) +(omc*omc)/delta))*alpha12+i*aalpha13*(omc)) + Ltt[alpha12];
+
+
+        ]]>
+      </operators>
+      
+    </integrate>
+  </sequence>
+  
+  <output format="hdf5" filename="mpi_highdimcrossprop.xsil">
+    <group>
+      <sampling basis="z(128) x(16) y(16)" initial_sample="yes">
+        <moments>bprobereal bprobeimag</moments>
+        <dependencies>cross1</dependencies>
+        <![CDATA[
+bprobereal = E.Re();
+bprobeimag = E.Im();
+        ]]>
+      </sampling>
+     </group> 
+     <sampling_group basis="kx(16) ky(16) kz(128)" initial_sample="yes">
+        <moments>bproberealK bprobeimagK bintensityK</moments>
+        <dependencies>cross1</dependencies>
+        <![CDATA[
+          bproberealK = E.Re();
+          bprobeimagK = E.Im();
+          bintensityK = mod2(E);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(16) y(16) z(256)" initial_sample="yes">
+        <moments>balpreal12 balpimag12</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+balpreal12 = (alpha12).Re();
+balpimag12 = (alpha12).Im();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx(2) ky(2) kz(256)" initial_sample="yes">
+        <moments>balpreal12K balpimag12K</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          balpreal12K = (alpha12).Re();
+          balpimag12K = (alpha12).Im();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(0) z(512)" initial_sample="yes">
+        <moments>bprobereal bprobeimag</moments>
+        <dependencies>cross1</dependencies>
+        <![CDATA[
+bprobereal = E.Re();
+bprobeimag = E.Im();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(16) z(0)" initial_sample="yes">
+        <moments>bprobereal bprobeimag</moments>
+        <dependencies>cross1</dependencies>
+        <![CDATA[
+bprobereal = E.Re();
+bprobeimag = E.Im();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(16) y(0) z(0)" initial_sample="yes">
+        <moments>bprobereal bprobeimag</moments>
+        <dependencies>cross1</dependencies>
+        <![CDATA[
+bprobereal = E.Re();
+bprobeimag = E.Im();
+        ]]>
+      </sampling_group>
+       <sampling_group basis="x(0) y(0) z(512)" initial_sample="no">
+        <moments>balpreal12 balpimag12</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          balpreal12 = Re(alpha12);
+          balpimag12 = Im(alpha12);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(16) y(0) z(0)" initial_sample="no">
+        <moments>balpreal12 balpimag12</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          balpreal12 = Re(alpha12);
+          balpimag12 = Im(alpha12);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(16) z(0)" initial_sample="no">
+        <moments>balpreal12 balpimag12</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          balpreal12 = Re(alpha12);
+          balpimag12 = Im(alpha12);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/mpi/nonlocal_access_test_expected.h5 b/testsuite/mpi/nonlocal_access_test_expected.h5
new file mode 100644
index 0000000..e329959
Binary files /dev/null and b/testsuite/mpi/nonlocal_access_test_expected.h5 differ
diff --git a/testsuite/mpi/nonlocal_access_test_expected.xsil b/testsuite/mpi/nonlocal_access_test_expected.xsil
new file mode 100644
index 0000000..1a66c0e
--- /dev/null
+++ b/testsuite/mpi/nonlocal_access_test_expected.xsil
@@ -0,0 +1,135 @@
+<?xml version="1.0" ?><simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 4 ./vibstring_mpi_aliases</command_line>
+    <xsil_file absolute_tolerance="1e-7" expected="vibstring_mpi_aliases_expected.xsil" name="vibstring_mpi_aliases.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-7" expected="nonlocal_access_test_expected.xsil" name="nonlocal_access_test.xsil" relative_tolerance="1e-5"/>
+  </testing>
+  
+  <name>vibstring_mpi_aliases</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string
+  </description>
+  
+  <features>
+    <benchmark/>
+    <error_check/>
+    <bing/>
+    <fftw plan="estimate"/>
+
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+    <diagnostics/>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension aliases="y" domain="(0, 1)" lattice="100" name="x"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi"/>
+  
+  <vector initial_basis="x" name="main" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector dimensions="x y" name="nonlocal_access_test" type="complex">
+    <components>g</components>
+    <evaluation>
+      <dependencies>main</dependencies>
+      <![CDATA[
+      g = u(x => x) * conj(u(x => y));
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="2e-3" steps="100">
+      <samples>50 50</samples>
+      <computed_vector dimensions="" name="moment_creator" type="real">
+        <components>moment</components>
+        <evaluation>
+          <dependencies basis="kx"> main </dependencies>
+          <![CDATA[
+            moment = mod2(u);
+          ]]>
+        </evaluation>
+      </computed_vector>
+      <operators>
+        <operator constant="yes" kind="ex">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>moment_creator</dependencies>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+          moment;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="nonlocal_access_test.xsil">
+      <dependencies>nonlocal_access_test</dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output>
+    <sampling_group basis="x" initial_sample="yes">
+      <moments>amp</moments>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        amp = u.Re();
+      ]]>
+    </sampling_group>
+    <sampling_group basis="kx(50)" initial_sample="no">
+      <moments>amp</moments>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        amp = u.Re();
+        
+      ]]>
+    </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x y gR gI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>100</Dim>
+    <Dim>100</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+nonlocal_access_test_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/mpi/partial_integration_computed_vector.xmds b/testsuite/mpi/partial_integration_computed_vector.xmds
new file mode 100644
index 0000000..c854817
--- /dev/null
+++ b/testsuite/mpi/partial_integration_computed_vector.xmds
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 2 ./partial_integration_computed_vector</command_line>
+    <xsil_file name="partial_integration_computed_vector.xsil" expected="../fast/bessel_cosine_groundstate_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="partial_integration_computed_vector_breakpoint.xsil" expected="../fast/bessel_cosine_groundstate_breakpoint_expected.xsil" absolute_tolerance="1e0" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>partial_integration_computed_vector</name>
+  <author>Graham Dennis</author>
+  <description>
+    Calculate the 3D ground state of a Rubidium BEC in a harmonic magnetic trap assuming
+    cylindrical symmetry about the z axis and reflection symmetry about z=0.
+    This permits us to use the cylindrical bessel functions to expand the solution transverse
+    to z and a cosine series to expand the solution along z.
+    
+    This testcase tests using both Fourier transforms and Matrix transforms in a single simulation.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <globals>
+      <![CDATA[
+        const real omegaz = 2*M_PI*20;
+        const real omegarho = 2*M_PI*200;
+        const real hbar = 1.05457148e-34;
+        const real M = 1.409539200000000e-25;
+        const real g = 9.8;
+        const real scatteringLength = 5.57e-9;
+        const real Uint = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+        const real Nparticles = 5.0e5;
+
+        /* offset constants */
+        const real EnergyOffset = pow(15.0*Nparticles*Uint*omegaz*omegarho*omegarho/(8*M_PI), 2.0/5.0)
+                                    * pow(M/2.0, 3.0/5.0);
+
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="z" lattice="32"  domain="(0.0, 1.0e-4)" transform="dct" volume_prefactor="2.0" />
+      <dimension name="r" lattice="32"  domain="(0.0, 1.0e-5)" transform="bessel" volume_prefactor="2.0*M_PI"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="potential" type="complex">
+    <components>
+      V1
+    </components>
+    <initialisation>
+      <![CDATA[
+        real Vtrap = 0.5*M*(omegarho*omegarho*r*r + omegaz*omegaz*z*z);
+      
+        V1  = -i/hbar*(Vtrap - EnergyOffset);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+      
+        if ((abs(r) < 0.9e-5) && abs(z) < 0.9e-4) {
+          phi = 1.0; //sqrt(Nparticles/2.0e-5);
+          // This will be automatically normalised later
+        } else {
+          phi = 0.0;
+        }
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="partial_r" dimensions="r" type="real">
+      <components>Nr</components>
+      <evaluation>
+          <dependencies>wavefunction</dependencies>
+          <![CDATA[
+                  Nr = mod2(phi);
+          ]]>
+      </evaluation>
+  </computed_vector>
+
+  <computed_vector name="partial_z" dimensions="z" type="real">
+      <components>Nz</components>
+      <evaluation>
+          <dependencies>wavefunction</dependencies>
+          <![CDATA[
+                  Nz = mod2(phi);
+          ]]>
+      </evaluation>
+  </computed_vector>
+  
+  <computed_vector name="norm_r" dimensions="" type="real">
+      <components>NcalcR</components>
+      <evaluation>
+          <dependencies>partial_r</dependencies>
+          <![CDATA[
+                      NcalcR = Nr;
+          ]]>
+      </evaluation>
+  </computed_vector>
+  
+  <computed_vector name="norm_z" dimensions="" type="real">
+      <components>NcalcZ</components>
+      <evaluation>
+          <dependencies>partial_z</dependencies>
+          <![CDATA[
+                      NcalcZ = Nz;
+        ]]>
+      </evaluation>
+  </computed_vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>
+      Ncalc
+    </components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="1e-4" steps="1000">
+      <samples>100</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation norm_r norm_z</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+                  real mean_number = (Ncalc + NcalcR + NcalcZ)/3.0;
+            phi *= sqrt(Nparticles/mean_number);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*hbar/M*(kr*kr + kz*kz);
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] - (i*V1 + Uint/hbar*mod2(phi))*phi;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="partial_integration_computed_vector_breakpoint.xsil" format="hdf5">
+      <dependencies>wavefunction</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="r z" initial_sample="no">
+        <moments>norm_dens</moments>
+        <dependencies>wavefunction normalisation norm_r norm_z</dependencies>
+        <![CDATA[
+                    real mean_number = (Ncalc + NcalcR + NcalcZ)/3.0;
+          norm_dens = mod2(phi)/mean_number;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/mpi/vibstring_dst_mpi.xmds b/testsuite/mpi/vibstring_dst_mpi.xmds
new file mode 100644
index 0000000..e1b45b1
--- /dev/null
+++ b/testsuite/mpi/vibstring_dst_mpi.xmds
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 4 ./vibstring_dst_mpi</command_line>
+    <xsil_file name="vibstring_dst_mpi.xsil" expected="vibstring_dst_mpi_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>vibstring_dst_mpi</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string with Dirichlet boundary conditions on a square using DST's.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="256"  domain="(-1, 1)" transform="dst"/>
+      <dimension name="y" lattice="256"  domain="(-1, 1)" transform="dst"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="real">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-5" interval="2e-3" steps="1000">
+      <samples>5 5</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*(kx*kx + ky*ky)/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x(32) y(32)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx(32) ky(32)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = mod2(u);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/mpi/vibstring_dst_mpi_chunked.xmds b/testsuite/mpi/vibstring_dst_mpi_chunked.xmds
new file mode 100644
index 0000000..ed821e0
--- /dev/null
+++ b/testsuite/mpi/vibstring_dst_mpi_chunked.xmds
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 4 ./vibstring_dst_mpi_chunked</command_line>
+    <xsil_file name="vibstring_dst_mpi_chunked.xsil" expected="vibstring_dst_mpi_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>vibstring_dst_mpi_chunked</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string with Dirichlet boundary conditions on a square using DST's.
+  </description>
+  
+  <features>
+    <chunked_output size="2KB" />
+    <fftw plan="patient" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="256"  domain="(-1, 1)" transform="dst"/>
+      <dimension name="y" lattice="256"  domain="(-1, 1)" transform="dst"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="real">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-5" interval="2e-3" steps="1000">
+      <samples>5 5</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*(kx*kx + ky*ky)/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x(32) y(32)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx(32) ky(32)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = mod2(u);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/mpi/vibstring_dst_mpi_expected.xsil b/testsuite/mpi/vibstring_dst_mpi_expected.xsil
new file mode 100644
index 0000000..0a8d2c6
--- /dev/null
+++ b/testsuite/mpi/vibstring_dst_mpi_expected.xsil
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 4 ./vibstring_dst_mpi</command_line>
+    <xsil_file name="vibstring_dst_mpi.xsil" expected="vibstring_dst_mpi_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>vibstring_dst_mpi</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string with Dirichlet boundary conditions on a square using DST's.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <openmp />
+    <globals>
+      <![CDATA[
+      const double T = 10.0;
+      const double mass = 1e-3;
+      const double length = 1.0;
+      const double mu = mass/length;
+      
+      const double xmax = _xy_max_x;
+      const double width = 0.1;
+      const double absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="256"  domain="(-1, 1)" transform="dst"/>
+      <dimension name="y" lattice="256"  domain="(-1, 1)" transform="dst"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="double">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-5" interval="2e-3" steps="1000">
+      <samples>5 5</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*(kx*kx + ky*ky)/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <!-- Any dimension not mentioned is assumed to be in real space and its middle element will be sampled -->
+        <!-- Note that this is different default behaviour to the filter operator. To integrate, put in a dimension -->
+        <!-- with zero lattice points. -->
+        <!-- Note that dimensions can be in any order. Not that I can think of a reason why you would want to do that -->
+        <dimension name="x" fourier_space="no" lattice="32"/>
+        <dimension name="y" fourier_space="no" lattice="32"/>
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u;
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes">
+        <dimension name="x" fourier_space="yes" lattice="32" />
+        <dimension name="y" fourier_space="yes" lattice="32" />
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = mod2(u);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t x y amp 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>6</Dim>
+    <Dim>32</Dim>
+    <Dim>32</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+vibstring_dst_mpi_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t kx ky amp 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>6</Dim>
+    <Dim>32</Dim>
+    <Dim>32</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+vibstring_dst_mpi_expected_mg1.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/mpi/vibstring_dst_mpi_expected_mg0.dat b/testsuite/mpi/vibstring_dst_mpi_expected_mg0.dat
new file mode 100644
index 0000000..d21c439
Binary files /dev/null and b/testsuite/mpi/vibstring_dst_mpi_expected_mg0.dat differ
diff --git a/testsuite/mpi/vibstring_dst_mpi_expected_mg1.dat b/testsuite/mpi/vibstring_dst_mpi_expected_mg1.dat
new file mode 100644
index 0000000..0accdbf
Binary files /dev/null and b/testsuite/mpi/vibstring_dst_mpi_expected_mg1.dat differ
diff --git a/testsuite/mpi/vibstring_mpi_aliases.xmds b/testsuite/mpi/vibstring_mpi_aliases.xmds
new file mode 100644
index 0000000..e905cad
--- /dev/null
+++ b/testsuite/mpi/vibstring_mpi_aliases.xmds
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 4 ./vibstring_mpi_aliases</command_line>
+    <xsil_file name="vibstring_mpi_aliases.xsil" expected="vibstring_mpi_aliases_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="nonlocal_access_test.xsil" expected="nonlocal_access_test_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>vibstring_mpi_aliases</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw plan="estimate" />
+
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+    <diagnostics />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" aliases="y" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="nonlocal_access_test" dimensions="x y" type="complex">
+    <components>g</components>
+    <evaluation>
+      <dependencies>main</dependencies>
+      <![CDATA[
+      g = u(x => x) * conj(u(x => y));
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="2e-3" steps="100">
+      <samples>50 50</samples>
+      <computed_vector name="moment_creator" dimensions="" type="real">
+        <components>moment</components>
+        <evaluation>
+          <dependencies basis="kx"> main </dependencies>
+          <![CDATA[
+            moment = mod2(u);
+          ]]>
+        </evaluation>
+      </computed_vector>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>moment_creator</dependencies>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+          moment;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="nonlocal_access_test.xsil">
+      <dependencies>nonlocal_access_test</dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output>
+    <sampling_group basis="x" initial_sample="yes">
+      <moments>amp</moments>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        amp = u.Re();
+      ]]>
+    </sampling_group>
+    <sampling_group basis="kx(50)" initial_sample="no">
+      <moments>amp</moments>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        amp = u.Re();
+        
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/mpi/vibstring_mpi_aliases_expected.h5 b/testsuite/mpi/vibstring_mpi_aliases_expected.h5
new file mode 100644
index 0000000..dd063a1
Binary files /dev/null and b/testsuite/mpi/vibstring_mpi_aliases_expected.h5 differ
diff --git a/testsuite/mpi/vibstring_mpi_aliases_expected.xsil b/testsuite/mpi/vibstring_mpi_aliases_expected.xsil
new file mode 100644
index 0000000..92f2466
--- /dev/null
+++ b/testsuite/mpi/vibstring_mpi_aliases_expected.xsil
@@ -0,0 +1,153 @@
+<?xml version="1.0" ?><simulation xmds-version="2">
+  <testing>
+    <command_line>mpirun -n 4 ./vibstring_mpi_aliases</command_line>
+    <xsil_file absolute_tolerance="1e-7" expected="vibstring_mpi_aliases_expected.xsil" name="vibstring_mpi_aliases.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-7" expected="nonlocal_access_test_expected.xsil" name="nonlocal_access_test.xsil" relative_tolerance="1e-5"/>
+  </testing>
+  
+  <name>vibstring_mpi_aliases</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string
+  </description>
+  
+  <features>
+    <benchmark/>
+    <error_check/>
+    <bing/>
+    <fftw plan="estimate"/>
+
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+    <diagnostics/>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension aliases="y" domain="(0, 1)" lattice="100" name="x"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi"/>
+  
+  <vector initial_basis="x" name="main" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector dimensions="x y" name="nonlocal_access_test" type="complex">
+    <components>g</components>
+    <evaluation>
+      <dependencies>main</dependencies>
+      <![CDATA[
+      g = u(x => x) * conj(u(x => y));
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="2e-3" steps="100">
+      <samples>50 50</samples>
+      <computed_vector dimensions="" name="moment_creator" type="real">
+        <components>moment</components>
+        <evaluation>
+          <dependencies basis="kx"> main </dependencies>
+          <![CDATA[
+            moment = mod2(u);
+          ]]>
+        </evaluation>
+      </computed_vector>
+      <operators>
+        <operator constant="yes" kind="ex">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>moment_creator</dependencies>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+          moment;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="nonlocal_access_test.xsil">
+      <dependencies>nonlocal_access_test</dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output>
+    <sampling_group basis="x" initial_sample="yes">
+      <moments>amp</moments>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        amp = u.Re();
+      ]]>
+    </sampling_group>
+    <sampling_group basis="kx(50)" initial_sample="no">
+      <moments>amp</moments>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        amp = u.Re();
+        
+      ]]>
+    </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t x amp error_amp 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>51</Dim>
+    <Dim>100</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+vibstring_mpi_aliases_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t kx amp error_amp 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>50</Dim>
+    <Dim>50</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/2"/>
+vibstring_mpi_aliases_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/openmp/bessel_cosine_groundstate.xmds b/testsuite/openmp/bessel_cosine_groundstate.xmds
new file mode 100644
index 0000000..a3ae3f0
--- /dev/null
+++ b/testsuite/openmp/bessel_cosine_groundstate.xmds
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="bessel_cosine_groundstate.xsil" expected="../fast/bessel_cosine_groundstate_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="bessel_cosine_groundstate_breakpoint.xsil" expected="../fast/bessel_cosine_groundstate_breakpoint_expected.xsil" absolute_tolerance="1e0" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>bessel_cosine_groundstate</name>
+  <author>Graham Dennis</author>
+  <description>
+    Calculate the 3D ground state of a Rubidium BEC in a harmonic magnetic trap assuming
+    cylindrical symmetry about the z axis and reflection symmetry about z=0.
+    This permits us to use the cylindrical bessel functions to expand the solution transverse
+    to z and a cosine series to expand the solution along z.
+    
+    This testcase tests using both Fourier transforms and Matrix transforms in a single simulation.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <openmp />
+    <fftw threads="4" />
+    <globals>
+      <![CDATA[
+        const real omegaz = 2*M_PI*20;
+        const real omegarho = 2*M_PI*200;
+        const real hbar = 1.05457148e-34;
+        const real M = 1.409539200000000e-25;
+        const real g = 9.8;
+        const real scatteringLength = 5.57e-9;
+        const real Uint = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+        const real Nparticles = 5.0e5;
+
+        /* offset constants */
+        const real EnergyOffset = pow(15.0*Nparticles*Uint*omegaz*omegarho*omegarho/(8*M_PI), 2.0/5.0)
+                                    * pow(M/2.0, 3.0/5.0);
+
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="z" lattice="32"  domain="(0.0, 1.0e-4)" transform="dct" volume_prefactor="2.0" />
+      <dimension name="r" lattice="32"  domain="(0.0, 1.0e-5)" transform="bessel" volume_prefactor="2.0*M_PI"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" type="complex">
+    <components>
+      V1
+    </components>
+    <initialisation>
+      <![CDATA[
+        real Vtrap = 0.5*M*(omegarho*omegarho*r*r + omegaz*omegaz*z*z);
+      
+        V1  = -i/hbar*(Vtrap - EnergyOffset);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+      
+        if ((abs(r) < 0.9e-5) && abs(z) < 0.9e-4) {
+          phi = 1.0; //sqrt(Nparticles/2.0e-5);
+          // This will be automatically normalised later
+        } else {
+          phi = 0.0;
+        }
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>
+      Ncalc
+    </components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="1e-4" steps="1000">
+      <samples>100</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi *= sqrt(Nparticles/Ncalc);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*hbar/M*(kr*kr + kz*kz);
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] - (i*V1 + Uint/hbar*mod2(phi))*phi;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="bessel_cosine_groundstate_breakpoint.xsil" format="hdf5">
+      <dependencies>wavefunction</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="r z" initial_sample="no">
+        <moments>norm_dens</moments>
+        <dependencies>wavefunction normalisation</dependencies>
+        <![CDATA[
+          norm_dens = mod2(phi)/Ncalc;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/openmp/diffusion_openmp.xmds b/testsuite/openmp/diffusion_openmp.xmds
new file mode 100644
index 0000000..72f13b9
--- /dev/null
+++ b/testsuite/openmp/diffusion_openmp.xmds
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="diffusion_openmp.xsil" expected="../mpi/diffusion_mpi_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>diffusion_openmp</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion with a pointless second dimension thrown in for fun
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="measure" threads="4" />
+    <openmp />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+      <dimension name="x" lattice="256"  domain="(-10.0, 10.0)" />
+    </transverse_dimensions>
+  </geometry>
+    
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="10.0" steps="2400" tolerance="1e-5">
+      <samples>24 4</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="x ky">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="y x(0)" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="y x" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/openmp/diffusion_openmp_chunked.xmds b/testsuite/openmp/diffusion_openmp_chunked.xmds
new file mode 100644
index 0000000..12d0496
--- /dev/null
+++ b/testsuite/openmp/diffusion_openmp_chunked.xmds
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="diffusion_openmp_chunked.xsil" expected="../mpi/diffusion_mpi_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>diffusion_openmp_chunked</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion with a pointless second dimension thrown in for fun
+  </description>
+  
+  <features>
+    <benchmark />
+    <chunked_output size="10KB" />
+    <fftw plan="measure" threads="4"/>
+    <openmp />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+      <dimension name="x" lattice="256"  domain="(-10.0, 10.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="10.0" steps="2400" tolerance="1e-5">
+      <samples>24 4</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="x ky">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="y x(0)" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="y x" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/openmp/eigenvalues.xmds b/testsuite/openmp/eigenvalues.xmds
new file mode 100644
index 0000000..f7de5a0
--- /dev/null
+++ b/testsuite/openmp/eigenvalues.xmds
@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="eigenvalues_break.xsil" expected="../fast/eigenvalues_break_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+    <xsil_file name="eigenvalues.xsil" expected="../fast/eigenvalues_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>eigenvalues</name>
+  <author>Graham Dennis</author>
+  <description>
+    1D TW model of the uniform Peaks system.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <fftw plan="exhaustive" threads="4" />
+    <globals>
+      <![CDATA[
+      /* physical constants  */
+       const double omegaz = 2*M_PI*55.0;
+       const double omegarho = 2*M_PI*1020.0;
+       const double hbar = 1.05457148e-34;
+       const double M = 4.0026032*1.66053886e-27;
+       const double scatteringLength = 7.51e-9;
+       const double Uint3 = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+       const double Nparticles = 2.0e6;
+       const double mu = pow(15*Nparticles*Uint3*omegarho*omegarho*omegaz/(8.0*M_PI)*pow(M/2,3.0/2.0),2.0/5.0);
+       const double Uint = Uint3*5.0*omegarho*omegarho*M/(4.0*M_PI*mu);
+       const double Uint_hbar = Uint/hbar;
+       const complex miUint_hbar = -i*Uint_hbar;
+       const double otherScatteringLength = 5.56e-9;
+       const double kappa = otherScatteringLength/scatteringLength;
+       double Delta;
+       const double hbar_M = hbar/M;
+       const double Omega = 2.0*M_PI*3e3;
+       
+       double mu0 = hbar*1.7786e3*2.0*M_PI;
+       double nu = 6.649299328e3;//4.4046e4; // Hertz
+       
+      ]]>
+    </globals>
+    <openmp />
+    <validation kind="run-time" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="kz" lattice="32"  domain="(0, 3e6)" />
+      <!-- <dimension name="kz" lattice="1024"  domain="(1.3220e6, 1.3221e6)" /> -->
+      <dimension name="p" domain="(1, 4)" type="integer" aliases="q" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="wavefunction" dimensions="" type="complex">
+    <components>
+      phi1 phi0
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi1 = sqrt(mu/Uint);
+        phi0 = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="matrixterms" dimensions="kz p q" initial_basis="kz" type="complex">
+    <components>matrix</components>
+    <initialisation>
+      <![CDATA[
+        if (p == q) {
+          matrix = 1.0;
+        } else {
+          matrix = 0.0;
+        }
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="hamiltonian_matrix" dimensions="kz p q" type="complex">
+    <components>h_matrix</components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        const double kineticEnergy = 0.5*hbar*hbar*kz*kz/M;
+        if (p == 1 && q == 1) h_matrix = Uint*mod2(phi1)+kineticEnergy-mu0;
+        if (p == 1 && q == 2) h_matrix = Uint*phi1*phi1;
+        if (p == 1 && q == 3) h_matrix = Uint*phi1*conj(phi0)+hbar*Omega;
+        if (p == 1 && q == 4) h_matrix = Uint*phi1*phi0;
+        
+        if (p == 2 && q == 1) h_matrix = -Uint*conj(phi1*phi1);
+        if (p == 2 && q == 2) h_matrix = -Uint*mod2(phi1)-kineticEnergy+mu0;
+        if (p == 2 && q == 3) h_matrix = -Uint*conj(phi1 * phi0);
+        if (p == 2 && q == 4) h_matrix = -Uint*conj(phi1)*phi0 - hbar*Omega;
+        
+        if (p == 3 && q == 1) h_matrix = Uint*conj(phi1)*phi0 + hbar*Omega;
+        if (p == 3 && q == 2) h_matrix = Uint*phi0*phi1;
+        if (p == 3 && q == 3) h_matrix = Uint*(2.0*kappa-1.0)*mod2(phi0)-mu0+kineticEnergy;
+        if (p == 3 && q == 4) h_matrix = Uint*kappa*phi0*phi0;
+        
+        if (p == 4 && q == 1) h_matrix = -Uint*conj(phi0*phi1);
+        if (p == 4 && q == 2) h_matrix = -Uint*phi1*conj(phi0)-hbar*Omega;
+        if (p == 4 && q == 3) h_matrix = -Uint*kappa*conj(phi0*phi0);
+        if (p == 4 && q == 4) h_matrix = -Uint*(2.0*kappa-1.0)*mod2(phi0)-kineticEnergy+mu0;
+        
+        h_matrix *= -i/hbar;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" interval="1.0/nu" tolerance="1e-8">
+      <samples>20 20</samples>
+      <operators dimensions="">
+        <integration_vectors>wavefunction</integration_vectors>
+        <![CDATA[
+          dphi1_dt = - i/hbar*( - mu0)*phi1 -i*Omega*phi0;
+          dphi0_dt = - i/hbar*( - Uint*(1.0-kappa)*mod2(phi0) - mu0)*phi0 -i*Omega*phi1;
+        ]]>
+      </operators>
+      <operators dimensions="kz p q">
+        <integration_vectors>matrixterms</integration_vectors>
+        <dependencies>wavefunction hamiltonian_matrix</dependencies>
+        <![CDATA[
+          dmatrix_dt = 0.0;
+          for (long pp = 1; pp <= 4; pp++) {
+            dmatrix_dt += h_matrix(q=> pp)*matrix(p=> pp);
+          }
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="eigenvalues_break.xsil" format="hdf5">
+      <dependencies>matrixterms</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="hdf5">
+      <sampling_group initial_sample="yes">
+        <moments>phi1R phi1I phi0R phi0I</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(phi1); _SAMPLE_COMPLEX(phi0);
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes" basis="kz p q">
+        <moments>matrixR matrixI</moments>
+        <dependencies>matrixterms</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(matrix);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/openmp/hermitegauss_transform_2d_openmp.xmds b/testsuite/openmp/hermitegauss_transform_2d_openmp.xmds
new file mode 100644
index 0000000..e9f41f4
--- /dev/null
+++ b/testsuite/openmp/hermitegauss_transform_2d_openmp.xmds
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="hermitegauss_transform_2d_openmp.xsil" expected="../mpi/hermitegauss_transform_2d_mpi_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+  </testing>
+
+  <name>hermitegauss_transform_2d_openmp</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the Schroedinger equation in 2D using the hermite-Gauss basis.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <validation kind="run-time" />
+    <openmp />
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="10" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+      <dimension name="y" lattice="10" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+        // initial state is the groundstate in the x axis, but shifted by offset
+      psi = pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.5*(M*omega/hbar)*(x - offset)*(x - offset));
+        // and an expanded gaussian in the y axis
+      psi *= pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.25*(M*omega/hbar)*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>N integral_y2</components>
+    <evaluation>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        N = mod2(psi);
+        integral_y2 = mod2(psi)*y*y;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-6" interval="1e-3" steps="400">
+      <samples>10 1 100</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="nx ny">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*(nx + ny + 1.0)*omega;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dpsi_dt = L[psi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="nx ny" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(0)" initial_sample="yes">
+        <moments>mean_x mean_sigmay</moments>
+        <dependencies>main normalisation</dependencies>
+        <![CDATA[
+          mean_x = mod2(psi)*x/N;
+          mean_sigmay = sqrt(integral_y2/N);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/openmp/hermitegauss_transform_2d_openmp_small.xmds b/testsuite/openmp/hermitegauss_transform_2d_openmp_small.xmds
new file mode 100644
index 0000000..86d4b23
--- /dev/null
+++ b/testsuite/openmp/hermitegauss_transform_2d_openmp_small.xmds
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="hermitegauss_transform_2d_openmp_small.xsil" expected="../mpi/hermitegauss_transform_2d_mpi_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+  </testing>
+
+  <name>hermitegauss_transform_2d_openmp_small</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the Schroedinger equation in 2D using the hermite-Gauss basis.
+	
+	Checking that when the number of processes is of the same order as the number of grid points that things don't go awry
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <validation kind="run-time" />
+    <openmp />
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="10" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+      <dimension name="y" lattice="10" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+        // initial state is the groundstate in the x axis, but shifted by offset
+      psi = pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.5*(M*omega/hbar)*(x - offset)*(x - offset));
+        // and an expanded gaussian in the y axis
+      psi *= pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.25*(M*omega/hbar)*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>N integral_y2</components>
+    <evaluation>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        N = mod2(psi);
+        integral_y2 = mod2(psi)*y*y;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-6" interval="1e-3" steps="400">
+      <samples>10 1 100</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="nx ny">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*(nx + ny + 1.0)*omega;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dpsi_dt = L[psi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="nx ny" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(0)" initial_sample="yes">
+        <moments>mean_x mean_sigmay</moments>
+        <dependencies>main normalisation</dependencies>
+        <![CDATA[
+          mean_x = mod2(psi)*x/N;
+          mean_sigmay = sqrt(integral_y2/N);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/openmp/kubo_integer_dimensions_openmp.xmds b/testsuite/openmp/kubo_integer_dimensions_openmp.xmds
new file mode 100644
index 0000000..9706b63
--- /dev/null
+++ b/testsuite/openmp/kubo_integer_dimensions_openmp.xmds
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="kubo_integer_dimensions_openmp.xsil" expected="kubo_integer_dimensions_openmp_expected.xsil" absolute_tolerance="5e-2" relative_tolerance="1e-1" />
+    <xsil_file name="kubo_integer_dimensions_openmp_break.xsil" expected="kubo_integer_dimensions_openmp_break_expected.xsil" absolute_tolerance="5e-2" relative_tolerance="1e-1" />
+  </testing>
+  
+  <name>kubo_integer_dimensions_openmp</name>
+  <author>Graham Dennis</author>
+  <description>
+    Example Kubo oscillator simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" type="integer" lattice="1024" domain="(1, 1024)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <features>
+      <openmp />
+  </features>
+  
+  <vector name="main" type="complex">
+    <components>
+      z
+    </components>
+    <initialisation>
+      <![CDATA[
+        z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <noise_vector name="noise" kind="wiener" type="real" seed="157 9348 234">
+    <components>n_1</components>
+  </noise_vector>
+  
+  <sequence>
+    <integrate algorithm="RK9" interval="10" steps="1000" tolerance="1e-8">
+      <samples>500 10</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>noise</dependencies>
+        <![CDATA[
+          dz_dt(j => j) = i*z*n_1;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="kubo_integer_dimensions_openmp_break.xsil">
+      <dependencies>main</dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="j(0)" initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          zR = z.Re()/_lattice_j;
+          zI = z.Im()/_lattice_j;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="j" initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+            _SAMPLE_COMPLEX(z);
+          zR = z.Re();
+          zI = z.Im();
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/openmp/kubo_integer_dimensions_openmp_break_expected.dat b/testsuite/openmp/kubo_integer_dimensions_openmp_break_expected.dat
new file mode 100644
index 0000000..0656b1c
Binary files /dev/null and b/testsuite/openmp/kubo_integer_dimensions_openmp_break_expected.dat differ
diff --git a/testsuite/openmp/kubo_integer_dimensions_openmp_break_expected.xsil b/testsuite/openmp/kubo_integer_dimensions_openmp_break_expected.xsil
new file mode 100644
index 0000000..5407858
--- /dev/null
+++ b/testsuite/openmp/kubo_integer_dimensions_openmp_break_expected.xsil
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="kubo_integer_dimensions_openmp.xsil" expected="kubo_integer_dimensions_openmp_expected.xsil" absolute_tolerance="5e-2" relative_tolerance="1e-1" />
+    <xsil_file name="kubo_integer_dimensions_openmp_break.xsil" expected="kubo_integer_dimensions_openmp_break_expected.xsil" absolute_tolerance="5e-2" relative_tolerance="1e-1" />
+  </testing>
+  
+  <name>kubo_integer_dimensions_openmp</name>
+  <author>Graham Dennis</author>
+  <description>
+    Example Kubo oscillator simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" type="integer" lattice="1024" domain="(1, 1024)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <features>
+      <openmp />
+  </features>
+  
+  <vector name="main" type="complex">
+    <components>
+      z
+    </components>
+    <initialisation>
+      <![CDATA[
+        z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <noise_vector name="noise" kind="wiener" type="real" seed="157 9348 234">
+    <components>n_1</components>
+  </noise_vector>
+  
+  <sequence>
+    <integrate algorithm="RK9" interval="10" steps="1000" tolerance="1e-8">
+      <samples>500 10</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>noise</dependencies>
+        <![CDATA[
+          dz_dt(j => j) = i*z*n_1;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="kubo_integer_dimensions_openmp_break.xsil">
+      <dependencies>main</dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="j(0)" initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          zR = z.Re()/_lattice_j;
+          zI = z.Im()/_lattice_j;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="j" initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+            _SAMPLE_COMPLEX(z);
+          zR = z.Re();
+          zI = z.Im();
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+j zR zI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>1024</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+kubo_integer_dimensions_openmp_break_expected.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/openmp/kubo_integer_dimensions_openmp_expected.xsil b/testsuite/openmp/kubo_integer_dimensions_openmp_expected.xsil
new file mode 100644
index 0000000..65302dc
--- /dev/null
+++ b/testsuite/openmp/kubo_integer_dimensions_openmp_expected.xsil
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="kubo_integer_dimensions_openmp.xsil" expected="kubo_integer_dimensions_openmp_expected.xsil" absolute_tolerance="5e-2" relative_tolerance="1e-1" />
+    <xsil_file name="kubo_integer_dimensions_openmp_break.xsil" expected="kubo_integer_dimensions_openmp_break_expected.xsil" absolute_tolerance="5e-2" relative_tolerance="1e-1" />
+  </testing>
+  
+  <name>kubo_integer_dimensions_openmp</name>
+  <author>Graham Dennis</author>
+  <description>
+    Example Kubo oscillator simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" type="integer" lattice="1024" domain="(1, 1024)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <features>
+      <openmp />
+  </features>
+  
+  <vector name="main" type="complex">
+    <components>
+      z
+    </components>
+    <initialisation>
+      <![CDATA[
+        z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <noise_vector name="noise" kind="wiener" type="real" seed="157 9348 234">
+    <components>n_1</components>
+  </noise_vector>
+  
+  <sequence>
+    <integrate algorithm="RK9" interval="10" steps="1000" tolerance="1e-8">
+      <samples>500 10</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>noise</dependencies>
+        <![CDATA[
+          dz_dt(j => j) = i*z*n_1;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="kubo_integer_dimensions_openmp_break.xsil">
+      <dependencies>main</dependencies>
+    </breakpoint>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="j(0)" initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          zR = z.Re()/_lattice_j;
+          zI = z.Im()/_lattice_j;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="j" initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+            _SAMPLE_COMPLEX(z);
+          zR = z.Re();
+          zI = z.Im();
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t zR zI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>501</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+kubo_integer_dimensions_openmp_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t j zR zI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>11</Dim>
+    <Dim>1024</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+kubo_integer_dimensions_openmp_expected_mg1.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/openmp/kubo_integer_dimensions_openmp_expected_mg0.dat b/testsuite/openmp/kubo_integer_dimensions_openmp_expected_mg0.dat
new file mode 100644
index 0000000..cf9c476
Binary files /dev/null and b/testsuite/openmp/kubo_integer_dimensions_openmp_expected_mg0.dat differ
diff --git a/testsuite/openmp/kubo_integer_dimensions_openmp_expected_mg1.dat b/testsuite/openmp/kubo_integer_dimensions_openmp_expected_mg1.dat
new file mode 100644
index 0000000..7c3d712
Binary files /dev/null and b/testsuite/openmp/kubo_integer_dimensions_openmp_expected_mg1.dat differ
diff --git a/testsuite/openmp/lorenz_openmp.xmds b/testsuite/openmp/lorenz_openmp.xmds
new file mode 100644
index 0000000..cffba15
--- /dev/null
+++ b/testsuite/openmp/lorenz_openmp.xmds
@@ -0,0 +1,84 @@
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="lorenz_openmp.xsil" expected="../mpi/lorenz_mpi_expected.xsil" absolute_tolerance="4e-2" relative_tolerance="4e-2" />
+  </testing>
+  
+  <name>lorenz_openmp</name>
+  
+  <!-- While not strictly necessary, the following two tags are handy. -->
+  <author>Graham Dennis</author>
+  <description>
+    The Lorenz Attractor, an example of chaos.
+    
+    This example is designed to check that when the number of processors is of the same order
+    as the number of lattice points that things don't go awry
+  </description>
+  
+  <!-- 
+  This element defines some constants.  It can be used for other 
+  features as well, but we will go into that in more detail later.
+  -->
+  <features>
+    <globals>
+        <![CDATA[
+        real b = 8.0/3.0;
+        real r = 28.0;
+        ]]>
+     </globals>
+     <openmp />
+   </features>
+   
+  <!-- 
+  This part defines all of the dimensions used in the problem,
+  in this case, only the dimension of 'time' is needed.
+  -->
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+        <dimension name="sigma" domain="(5.0,15.0)" lattice="10" transform="none"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <!-- A 'vector' describes the variables that we will be evolving. -->
+  <vector name="position" type="real">
+    <components>
+      x y z
+    </components>
+    <initialisation>
+      <![CDATA[
+      x = y = z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <!--
+    Here we define what differential equations need to be solved
+    and what algorithm we want to use.
+    -->
+    <integrate algorithm="ARK89" interval="20.0" tolerance="1e-7">
+      <samples>5</samples>
+      <operators>
+        <integration_vectors>position</integration_vectors>
+        <![CDATA[
+        dx_dt = sigma*(y-x);
+        dy_dt = r*x - y - x*z;
+        dz_dt = x*y - b*z;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <!-- This part defines what data will be saved in the output file -->
+  <output format="binary">
+      <sampling_group basis="sigma" initial_sample="yes">
+        <moments>xR yR zR</moments>
+        <dependencies>position</dependencies>
+        <![CDATA[
+          xR = x;
+          yR = y;
+          zR = z;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/openmp/openmp_dft.xmds b/testsuite/openmp/openmp_dft.xmds
new file mode 100644
index 0000000..beebb3f
--- /dev/null
+++ b/testsuite/openmp/openmp_dft.xmds
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="openmp_dft_xspace1.xsil" expected="../mpi/mpi_dft_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="openmp_dft_kspace.xsil" expected="../mpi/mpi_dft_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="openmp_dft_kspace2.xsil" expected="../mpi/mpi_dft_kspace2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="openmp_dft_xspace2.xsil" expected="../mpi/mpi_dft_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  
+  <name>openmp_dft</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test of the fourier transforms using MPI.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" threads="4" />
+    <openmp />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="32"  domain="(-1, 1)" />
+      <dimension name="y" lattice="32"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      u
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="openmp_dft_xspace1.xsil">
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="openmp_dft_kspace.xsil">
+      <dependencies basis="ky kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="openmp_dft_kspace2.xsil">
+      <dependencies basis="ky x">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="openmp_dft_xspace2.xsil">
+      <dependencies basis="y x">main</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/openmp/openmp_dft_hdf5.xmds b/testsuite/openmp/openmp_dft_hdf5.xmds
new file mode 100644
index 0000000..acc133f
--- /dev/null
+++ b/testsuite/openmp/openmp_dft_hdf5.xmds
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="openmp_dft_hdf5_xspace1.xsil" expected="../mpi/mpi_dft_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="openmp_dft_hdf5_kspace.xsil" expected="../mpi/mpi_dft_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="openmp_dft_hdf5_kspace2.xsil" expected="../mpi/mpi_dft_kspace2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="openmp_dft_hdf5_xspace2.xsil" expected="../mpi/mpi_dft_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  
+  <name>openmp_dft_hdf5</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test of the fourier transforms using MPI.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" threads="4" />
+    <openmp />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="32"  domain="(-1, 1)" />
+      <dimension name="y" lattice="32"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      u
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="openmp_dft_hdf5_xspace1.xsil" format="hdf5">
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="openmp_dft_hdf5_kspace.xsil" format="hdf5">
+      <dependencies basis="ky kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="openmp_dft_hdf5_kspace2.xsil" format="hdf5">
+      <dependencies basis="ky x">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="openmp_dft_hdf5_xspace2.xsil" format="hdf5">
+      <dependencies basis="y x">main</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/openmp/openmp_dft_small.xmds b/testsuite/openmp/openmp_dft_small.xmds
new file mode 100644
index 0000000..ba561e9
--- /dev/null
+++ b/testsuite/openmp/openmp_dft_small.xmds
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="openmp_dft_small_xspace1.xsil" expected="../mpi/mpi_dft_small_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="openmp_dft_small_kspace.xsil"  expected="../mpi/mpi_dft_small_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="openmp_dft_small_kspace2.xsil" expected="../mpi/mpi_dft_small_kspace2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="openmp_dft_small_xspace2.xsil" expected="../mpi/mpi_dft_small_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  
+  <name>openmp_dft_small</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test of the fourier transforms using MPI.
+    
+    Checking that when the number of processors is of the same order as the number of grid points that things don't go awry
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" threads="4"/>
+    <openmp />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="10"  domain="(-1, 1)" />
+      <dimension name="y" lattice="10"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      u
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="openmp_dft_small_xspace1.xsil">
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="openmp_dft_small_kspace.xsil">
+      <dependencies basis="ky kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="openmp_dft_small_kspace2.xsil">
+      <dependencies basis="ky x">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="openmp_dft_small_xspace2.xsil">
+      <dependencies basis="y x">main</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/openmp/openmp_highdimcrossprop.xmds b/testsuite/openmp/openmp_highdimcrossprop.xmds
new file mode 100644
index 0000000..33e3468
--- /dev/null
+++ b/testsuite/openmp/openmp_highdimcrossprop.xmds
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="openmp_highdimcrossprop.xsil" expected="../operators/highdimcrossprop_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-4" />
+  </testing>
+  <name>openmp_highdimcrossprop</name>
+  
+  <features>
+    <benchmark />
+   <openmp />
+   <fftw threads="4" />
+    <bing />
+      <globals>
+<![CDATA[
+const real pi=3.14159265358979;
+const real g =2*pi*11.4005; // Sqrt(density)/Hz
+const real sample_length = 0.2; //m
+const real time_input =2.5e-6; // sec (5)
+const real sigma=1e-6; // sec (2)
+const real inp_hgt=1e3; //photonnum
+const real gama=2*pi*5.6e6; //Hz
+const real eta =2*pi*10e6/sample_length; //Hz/m (was 2*pi*10e6)
+const real omc=2*pi*20e6; //Hz (was 2*pi*20e6)
+
+const real gama0=0; //2*pi*2e3; //Hz
+const real gamac=0; //2*pi*1e3; //Hz
+const real c=3e8; // m/s
+const real timeswitchz=10e-6; // sec (10)
+
+const real N=1e18; // density 
+const real gNonc = g*N/c; 
+const real delta=2*pi*3e9; //Hz
+
+const real width = 0.001; //m
+const real k0 = 6.28 / (795e-9);
+
+const real alpha=0.00; //m^2/s
+
+]]> 
+  </globals>
+    
+  </features>
+
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+	   <dimension name="x" lattice="16" domain="(-0.004,0.004)"  /> 
+	   <dimension name="y" lattice="16" domain="(-0.003,0.003)"  /> 
+	   <dimension name="z" lattice="512"  domain="(0,0.2)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="z x y" type="complex">
+    <components>
+    alpha12
+    </components>
+    <initialisation>
+      <![CDATA[
+      alpha12 =  0.0;
+    
+      ]]>
+    </initialisation>
+  </vector>
+
+    <vector name="crossinitial" initial_basis="x y" type="complex">
+    <components>
+    beamprofile
+    </components>
+    <initialisation>
+      <![CDATA[
+      beamprofile=inp_hgt * (2*sqrt(2)*x/width) * exp(-x*x/(width*width)) * exp(-y*y/(width*width))* exp(-i*k0*(x*x+y*y)/0.5);
+      ]]>
+    </initialisation>
+  </vector>
+
+<vector name="cross1" initial_basis="x y z" type="complex">
+    <components>
+     E
+    </components>
+  </vector>
+  
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="20e-8" steps="20" tolerance="1.0e-6">
+          <samples>2 1 2 2 1 1 1 1 1 1</samples>
+      
+       <operators>
+        <operator kind="cross_propagation" algorithm="RK4"  propagation_dimension="z">
+            <operator kind="ip" constant="yes">
+              <operator_names>Btt</operator_names>
+              <![CDATA[
+                Btt = 0; //i*(kx*kx + ky*ky)/(2*k0);
+              ]]>
+            </operator>
+
+          <integration_vectors>cross1</integration_vectors>
+          <!-- You can have a dependencies tag in here -->
+          <dependencies>main</dependencies>
+          <boundary_condition kind="left">
+            <!-- You can also have a dependencies tag in here -->
+            <!-- like the one shown below, but none are needed -->
+            <!-- in this example -->
+			<dependencies>crossinitial</dependencies> 
+      <![CDATA[
+	  
+	  //E=inp_hgt*exp(-(t-time_input)*(t-time_input)/(sigma*sigma)) * exp(-x*x/(width*width))*exp(-y*y/(width*width));
+	  E = exp(-(t-time_input)*(t-time_input)/(sigma*sigma)) * beamprofile;
+			
+			]]>
+          </boundary_condition>
+          <![CDATA[
+      complex aalpha13 = (alpha12*omc+g*E)/delta;
+	  
+	  dE_dz =  i*gNonc*(aalpha13) + Btt[E]; 
+	   
+          ]]>
+        </operator>
+           <operator kind="ip" constant="yes">
+              <operator_names>Ltt</operator_names>
+              <![CDATA[
+                Ltt = -alpha*(kz*kz+kx*kx+ky*ky);
+              ]]>
+            </operator>
+        
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+
+complex sw  = -1.0; //( t<timeswitchz ? -1.0:1.0);
+
+complex aalpha13 = (alpha12*omc+g*E)/(delta-i*(gamac/2+gama+gama0/2));
+dalpha12_dt  = ((-gama0 - gamac-i*(sw*eta*(z-sample_length/2) +(omc*omc)/delta))*alpha12+i*aalpha13*(omc)) + Ltt[alpha12];
+
+
+        ]]>
+      </operators>
+      
+    </integrate>
+  </sequence>
+  
+  <output format="hdf5">
+    <group>
+      <sampling basis="z(128) x(16) y(16)" initial_sample="yes">
+        <moments>bprobereal bprobeimag</moments>
+        <dependencies>cross1</dependencies>
+        <![CDATA[
+bprobereal = E.Re();
+bprobeimag = E.Im();
+        ]]>
+      </sampling>
+     </group> 
+     <sampling_group basis="kx(16) ky(16) kz(128)" initial_sample="yes">
+        <moments>bproberealK bprobeimagK bintensityK</moments>
+        <dependencies>cross1</dependencies>
+        <![CDATA[
+          bproberealK = E.Re();
+          bprobeimagK = E.Im();
+          bintensityK = mod2(E);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(16) y(16) z(256)" initial_sample="yes">
+        <moments>balpreal12 balpimag12</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+balpreal12 = (alpha12).Re();
+balpimag12 = (alpha12).Im();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx(2) ky(2) kz(256)" initial_sample="yes">
+        <moments>balpreal12K balpimag12K</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          balpreal12K = (alpha12).Re();
+          balpimag12K = (alpha12).Im();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(0) z(512)" initial_sample="yes">
+        <moments>bprobereal bprobeimag</moments>
+        <dependencies>cross1</dependencies>
+        <![CDATA[
+bprobereal = E.Re();
+bprobeimag = E.Im();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(16) z(0)" initial_sample="yes">
+        <moments>bprobereal bprobeimag</moments>
+        <dependencies>cross1</dependencies>
+        <![CDATA[
+bprobereal = E.Re();
+bprobeimag = E.Im();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(16) y(0) z(0)" initial_sample="yes">
+        <moments>bprobereal bprobeimag</moments>
+        <dependencies>cross1</dependencies>
+        <![CDATA[
+bprobereal = E.Re();
+bprobeimag = E.Im();
+        ]]>
+      </sampling_group>
+       <sampling_group basis="x(0) y(0) z(512)" initial_sample="no">
+        <moments>balpreal12 balpimag12</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          balpreal12 = Re(alpha12);
+          balpimag12 = Im(alpha12);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(16) y(0) z(0)" initial_sample="no">
+        <moments>balpreal12 balpimag12</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          balpreal12 = Re(alpha12);
+          balpimag12 = Im(alpha12);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(16) z(0)" initial_sample="no">
+        <moments>balpreal12 balpimag12</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          balpreal12 = Re(alpha12);
+          balpimag12 = Im(alpha12);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/openmp/partial_integration_computed_vector.xmds b/testsuite/openmp/partial_integration_computed_vector.xmds
new file mode 100644
index 0000000..218928c
--- /dev/null
+++ b/testsuite/openmp/partial_integration_computed_vector.xmds
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="partial_integration_computed_vector.xsil" expected="../fast/bessel_cosine_groundstate_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="partial_integration_computed_vector_breakpoint.xsil" expected="../fast/bessel_cosine_groundstate_breakpoint_expected.xsil" absolute_tolerance="1e0" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>partial_integration_computed_vector</name>
+  <author>Graham Dennis</author>
+  <description>
+    Calculate the 3D ground state of a Rubidium BEC in a harmonic magnetic trap assuming
+    cylindrical symmetry about the z axis and reflection symmetry about z=0.
+    This permits us to use the cylindrical bessel functions to expand the solution transverse
+    to z and a cosine series to expand the solution along z.
+    
+    This testcase tests using both Fourier transforms and Matrix transforms in a single simulation.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <fftw threads="4" />
+    <openmp />
+    <globals>
+      <![CDATA[
+        const real omegaz = 2*M_PI*20;
+        const real omegarho = 2*M_PI*200;
+        const real hbar = 1.05457148e-34;
+        const real M = 1.409539200000000e-25;
+        const real g = 9.8;
+        const real scatteringLength = 5.57e-9;
+        const real Uint = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+        const real Nparticles = 5.0e5;
+
+        /* offset constants */
+        const real EnergyOffset = pow(15.0*Nparticles*Uint*omegaz*omegarho*omegarho/(8*M_PI), 2.0/5.0)
+                                    * pow(M/2.0, 3.0/5.0);
+
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="z" lattice="32"  domain="(0.0, 1.0e-4)" transform="dct" volume_prefactor="2.0" />
+      <dimension name="r" lattice="32"  domain="(0.0, 1.0e-5)" transform="bessel" volume_prefactor="2.0*M_PI"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" type="complex">
+    <components>
+      V1
+    </components>
+    <initialisation>
+      <![CDATA[
+        real Vtrap = 0.5*M*(omegarho*omegarho*r*r + omegaz*omegaz*z*z);
+      
+        V1  = -i/hbar*(Vtrap - EnergyOffset);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+      
+        if ((abs(r) < 0.9e-5) && abs(z) < 0.9e-4) {
+          phi = 1.0; //sqrt(Nparticles/2.0e-5);
+          // This will be automatically normalised later
+        } else {
+          phi = 0.0;
+        }
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="partial_r" dimensions="r" type="real">
+      <components>Nr</components>
+      <evaluation>
+          <dependencies>wavefunction</dependencies>
+          <![CDATA[
+                  Nr = mod2(phi);
+          ]]>
+      </evaluation>
+  </computed_vector>
+
+  <computed_vector name="partial_z" dimensions="z" type="real">
+      <components>Nz</components>
+      <evaluation>
+          <dependencies>wavefunction</dependencies>
+          <![CDATA[
+                  Nz = mod2(phi);
+          ]]>
+      </evaluation>
+  </computed_vector>
+  
+  <computed_vector name="norm_r" dimensions="" type="real">
+      <components>NcalcR</components>
+      <evaluation>
+          <dependencies>partial_r</dependencies>
+          <![CDATA[
+                      NcalcR = Nr;
+          ]]>
+      </evaluation>
+  </computed_vector>
+  
+  <computed_vector name="norm_z" dimensions="" type="real">
+      <components>NcalcZ</components>
+      <evaluation>
+          <dependencies>partial_z</dependencies>
+          <![CDATA[
+                      NcalcZ = Nz;
+        ]]>
+      </evaluation>
+  </computed_vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>
+      Ncalc
+    </components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="1e-4" steps="1000">
+      <samples>100</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation norm_r norm_z</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+                  real mean_number = (Ncalc + NcalcR + NcalcZ)/3.0;
+            phi *= sqrt(Nparticles/mean_number);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*hbar/M*(kr*kr + kz*kz);
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] - (i*V1 + Uint/hbar*mod2(phi))*phi;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="partial_integration_computed_vector_breakpoint.xsil" format="hdf5">
+      <dependencies>wavefunction</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="r z" initial_sample="no">
+        <moments>norm_dens</moments>
+        <dependencies>wavefunction normalisation norm_r norm_z</dependencies>
+        <![CDATA[
+                    real mean_number = (Ncalc + NcalcR + NcalcZ)/3.0;
+          norm_dens = mod2(phi)/mean_number;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/openmp/vibstring_dst_openmp.xmds b/testsuite/openmp/vibstring_dst_openmp.xmds
new file mode 100644
index 0000000..85979e5
--- /dev/null
+++ b/testsuite/openmp/vibstring_dst_openmp.xmds
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="vibstring_dst_openmp.xsil" expected="../mpi/vibstring_dst_mpi_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>vibstring_dst_openmp</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string with Dirichlet boundary conditions on a square using DST's.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" threads="4"/>
+    <openmp />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="256"  domain="(-1, 1)" transform="dst"/>
+      <dimension name="y" lattice="256"  domain="(-1, 1)" transform="dst"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="real">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-5" interval="2e-3" steps="1000">
+      <samples>5 5</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*(kx*kx + ky*ky)/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x(32) y(32)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx(32) ky(32)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = mod2(u);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/openmp/vibstring_dst_openmp_chunked.xmds b/testsuite/openmp/vibstring_dst_openmp_chunked.xmds
new file mode 100644
index 0000000..6334222
--- /dev/null
+++ b/testsuite/openmp/vibstring_dst_openmp_chunked.xmds
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="vibstring_dst_openmp_chunked.xsil" expected="../mpi/vibstring_dst_mpi_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>vibstring_dst_openmp_chunked</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string with Dirichlet boundary conditions on a square using DST's.
+  </description>
+  
+  <features>
+    <chunked_output size="2KB" />
+    <fftw plan="patient" threads="4"/>
+    <openmp />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="256"  domain="(-1, 1)" transform="dst"/>
+      <dimension name="y" lattice="256"  domain="(-1, 1)" transform="dst"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="real">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-5" interval="2e-3" steps="1000">
+      <samples>5 5</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*(kx*kx + ky*ky)/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x(32) y(32)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx(32) ky(32)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = mod2(u);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/operators/constant_complex_ip.xmds b/testsuite/operators/constant_complex_ip.xmds
new file mode 100644
index 0000000..3d56a68
--- /dev/null
+++ b/testsuite/operators/constant_complex_ip.xmds
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="constant_complex_ip.xsil" expected="derivative_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>constant_complex_ip</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion using the IP operator (of complex type)
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="10.0" steps="2400" tolerance="1e-5">
+      <samples>24</samples>
+      <operators>
+        <operator kind="ip" constant="yes" type="complex">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/operators/constant_double_ip.xmds b/testsuite/operators/constant_double_ip.xmds
new file mode 100644
index 0000000..37f4eee
--- /dev/null
+++ b/testsuite/operators/constant_double_ip.xmds
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="constant_double_ip.xsil" expected="derivative_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>constant_double_ip</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion using the IP operator (of double type)
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="10.0" steps="2400" tolerance="1e-5">
+      <samples>24</samples>
+      <operators>
+        <operator kind="ip" constant="yes" type="real">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/operators/constant_ex.xmds b/testsuite/operators/constant_ex.xmds
new file mode 100644
index 0000000..32ed601
--- /dev/null
+++ b/testsuite/operators/constant_ex.xmds
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="constant_ex.xsil" expected="derivative_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>constant_ex</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion using the EX operator
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="10.0" steps="24000" tolerance="1e-5">
+      <samples>24</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/operators/constant_ex_arbitrary_code.xmds b/testsuite/operators/constant_ex_arbitrary_code.xmds
new file mode 100644
index 0000000..547c320
--- /dev/null
+++ b/testsuite/operators/constant_ex_arbitrary_code.xmds
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="constant_ex_arbitrary_code.xsil" expected="derivative_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>constant_ex_arbitrary_code</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion using the EX operator acting on a general expression
+    forcing the construction of a 'special targets' computed vector.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="10.0" steps="24000" tolerance="1e-5">
+      <samples>24</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[1.0*phi+0.0];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/operators/constant_ex_arbitrary_order.xmds b/testsuite/operators/constant_ex_arbitrary_order.xmds
new file mode 100644
index 0000000..ae37684
--- /dev/null
+++ b/testsuite/operators/constant_ex_arbitrary_order.xmds
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="constant_ex_arbitrary_order.xsil" expected="constant_ex_arbitrary_order_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>constant_ex_arbitrary_order</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion using the EX operator
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="y" type="complex">
+    <components>
+      phi1 phi2
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi1 = exp(-y*y);
+        phi2 = exp(-5.0*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="10.0" steps="24000" tolerance="1e-5">
+      <samples>24</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi1_dt = L[phi1];
+          dphi2_dt = L[phi2];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="y" initial_sample="yes">
+        <moments>dens1 dens2</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens1 = mod2(phi1);
+          dens2 = mod2(phi2);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/operators/constant_ex_arbitrary_order2.xmds b/testsuite/operators/constant_ex_arbitrary_order2.xmds
new file mode 100644
index 0000000..842450e
--- /dev/null
+++ b/testsuite/operators/constant_ex_arbitrary_order2.xmds
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="constant_ex_arbitrary_order2.xsil" expected="constant_ex_arbitrary_order_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>constant_ex_arbitrary_order2</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion using the EX operator
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="y" type="complex">
+    <components>
+      phi1 phi2
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi1 = exp(-y*y);
+        phi2 = exp(-5.0*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="10.0" steps="24000" tolerance="1e-5">
+      <samples>24</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi2_dt = L[phi2];
+          dphi1_dt = L[phi1];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="y" initial_sample="yes">
+        <moments>dens1 dens2</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens1 = mod2(phi1);
+          dens2 = mod2(phi2);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/operators/constant_ex_arbitrary_order_expected.xsil b/testsuite/operators/constant_ex_arbitrary_order_expected.xsil
new file mode 100644
index 0000000..974f10d
--- /dev/null
+++ b/testsuite/operators/constant_ex_arbitrary_order_expected.xsil
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="constant_ex_arbitrary_order.xsil" expected="constant_ex_arbitrary_order_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>constant_ex_arbitrary_order</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion using the EX operator
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="y" type="complex">
+    <components>
+      phi1 phi2
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi1 = exp(-y*y);
+        phi2 = exp(-5.0*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="10.0" steps="24000" tolerance="1e-5">
+      <samples>24</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi1_dt = L[phi1];
+          dphi2_dt = L[phi2];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="y" initial_sample="yes">
+        <moments>dens1 dens2</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens1 = mod2(phi1);
+          dens2 = mod2(phi2);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t y dens1 dens2 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>25</Dim>
+    <Dim>128</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+constant_ex_arbitrary_order_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/operators/constant_ex_arbitrary_order_expected_mg0.dat b/testsuite/operators/constant_ex_arbitrary_order_expected_mg0.dat
new file mode 100644
index 0000000..4d511ad
Binary files /dev/null and b/testsuite/operators/constant_ex_arbitrary_order_expected_mg0.dat differ
diff --git a/testsuite/operators/cross_propagation.xmds b/testsuite/operators/cross_propagation.xmds
new file mode 100644
index 0000000..abd1834
--- /dev/null
+++ b/testsuite/operators/cross_propagation.xmds
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="cross_propagation.xsil" expected="cross_propagation_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  <name>cross_propagation</name>
+  <author>Graham Dennis</author>
+  <description>
+    Sine cross-propagation validity tests.
+    
+    The 'u' variable checks for errors caused by poorly interpolating
+    dependencies. The 'v' variable checks for errors just in the
+    cross-propagation algorithm. The 'w' variable checks for errors due
+    to IP cross-propagation (should be the smallest). The 'x' variable checks
+    for errors due to EX cross-propagation, they should be the same as 'v'.
+    You can choose the cross-propagation algorithm to be either 'SI' or 'RK4'.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> z </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="t" lattice="128"  domain="(0, 10)" transform="none" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" type="complex">
+    <components>
+      foo
+    </components>
+    <initialisation>
+      <![CDATA[
+      foo = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="constants" type="real">
+    <components>cosine</components>
+    <initialisation>
+      <![CDATA[
+        cosine = cos(t);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="zerodConstants" type="real">
+    <components>bar</components>
+    <initialisation>
+      <![CDATA[
+        bar = M_PI;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="cross" type="complex">
+    <components>u v w x</components>
+    <initialisation>
+      <![CDATA[
+        u = 0.0;
+        v = 0.0;
+        w = 0.0;
+        x = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK9" interval="1" steps="2">
+      <samples>1</samples>
+      <operators>
+        <operator kind="cross_propagation" algorithm="SI" propagation_dimension="t">
+          <integration_vectors>cross</integration_vectors>
+          <dependencies>constants zerodConstants</dependencies>
+          <boundary_condition kind="left">
+            <![CDATA[
+              u = 0.0;
+              v = 1.0;
+              w = 1.0;
+              x = 1.0;
+            ]]>
+          </boundary_condition>
+          
+          <operator kind="ip" constant="yes">
+            <operator_names>L</operator_names>
+            <![CDATA[
+              L = i;
+            ]]>
+          </operator>
+          
+          <operator kind="ex" constant="yes">
+            <operator_names>M</operator_names>
+            <![CDATA[
+              M = i;
+            ]]>
+          </operator>
+          <![CDATA[
+            du_dt = cosine;
+            dv_dt = i*v;
+            dw_dt = L[w]; // this one is pretty much exact
+            dx_dt = M[x];
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        dfoo_dz = 0.0;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="t" initial_sample="no">
+        <moments>error_u error_v error_w error_x</moments>
+        <dependencies>cross</dependencies>
+        <![CDATA[
+          error_u = abs(u - sin(t));
+          error_v = abs(v - polar(1.0, t));
+          error_w = abs(w - polar(1.0, t));
+          error_x = abs(x - polar(1.0, t));
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/operators/cross_propagation2.xmds b/testsuite/operators/cross_propagation2.xmds
new file mode 100644
index 0000000..1955484
--- /dev/null
+++ b/testsuite/operators/cross_propagation2.xmds
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="cross_propagation2.xsil" expected="cross_propagation2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  <name>cross_propagation2</name>
+  <author>Graham Dennis</author>
+  <description>
+    Sine cross-propagation validity tests.
+    
+    The 'u' variable checks for errors caused by poorly interpolating
+    dependencies. The 'v' variable checks for the existence of the
+    cross-propagation variable. The results for 'v' should be fairly
+    similar to those for 'u', but slightly more accurate.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> z </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="t" lattice="128"  domain="(0, 10)" transform="none" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" type="complex">
+    <components>
+      foo
+    </components>
+    <initialisation>
+      <![CDATA[
+      foo = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="constants" type="real">
+    <components>cosine</components>
+    <initialisation>
+      <![CDATA[
+        cosine = cos(t);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="cross" type="complex">
+    <components>u v</components>
+    <initialisation>
+      <![CDATA[
+        u = 0.0;
+        v = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK9" interval="1" steps="2">
+      <samples>1</samples>
+      <operators>
+        <operator kind="cross_propagation" algorithm="SI" propagation_dimension="t">
+          <integration_vectors>cross</integration_vectors>
+          <dependencies>constants</dependencies>
+          <boundary_condition kind="left">
+            <![CDATA[
+              u = 0.0;
+              v = 0.0;
+            ]]>
+          </boundary_condition>
+          
+          <![CDATA[
+            du_dt = cosine;
+            dv_dt = cos(t);
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        dfoo_dz = 0.0;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="t" initial_sample="no">
+        <moments>error_u error_v</moments>
+        <dependencies>cross</dependencies>
+        <![CDATA[
+          error_u = abs(u - sin(t));
+          error_v = abs(v - sin(t));
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/operators/cross_propagation2_expected.xsil b/testsuite/operators/cross_propagation2_expected.xsil
new file mode 100644
index 0000000..783eca3
--- /dev/null
+++ b/testsuite/operators/cross_propagation2_expected.xsil
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="cross_propagation2.xsil" expected="cross_propagation2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  <name>cross_propagation2</name>
+  <author>Graham Dennis</author>
+  <description>
+    Sine cross-propagation validity tests.
+    
+    The 'u' variable checks for errors caused by poorly interpolating
+    dependencies. The 'v' variable checks for the existence of the
+    cross-propagation variable. The results for 'v' should be fairly
+    similar to those for 'u', but slightly more accurate.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw version="none" />
+    <!-- That's right, this script breaks the shackles with FFTW! -->
+  </features>
+  
+  <geometry>
+    <propagation_dimension> z </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="t" lattice="128"  domain="(0, 10)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" type="complex">
+    <components>
+      foo
+    </components>
+    <initialisation>
+      <![CDATA[
+      foo = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="constants" type="double">
+    <components>cosine</components>
+    <initialisation>
+      <![CDATA[
+        cosine = cos(t);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="cross" type="complex">
+    <components>u v</components>
+    <![CDATA[
+      u = 0.0;
+      v = 0.0;
+    ]]>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK9" interval="1" steps="2">
+      <samples>1</samples>
+      <operators>
+        <operator kind="cross_propagation" algorithm="SI" propagation_dimension="t">
+          <integration_vectors>cross</integration_vectors>
+          <dependencies>constants</dependencies>
+          <boundary_condition kind="left">
+            <![CDATA[
+              u = 0.0;
+              v = 0.0;
+            ]]>
+          </boundary_condition>
+          
+          <![CDATA[
+            du_dt = cosine;
+            dv_dt = cos(t);
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        dfoo_dz = 0.0;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="no">
+        <dimension name="t" />
+        <moments>error_u error_v</moments>
+        <dependencies>cross</dependencies>
+        <![CDATA[
+          error_u = mod(u - sin(t));
+          error_v = mod(v - sin(t));
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t error_u error_v 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>128</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+cross_propagation2_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/operators/cross_propagation2_expected_mg0.dat b/testsuite/operators/cross_propagation2_expected_mg0.dat
new file mode 100644
index 0000000..87775fc
Binary files /dev/null and b/testsuite/operators/cross_propagation2_expected_mg0.dat differ
diff --git a/testsuite/operators/cross_propagation_expected.xsil b/testsuite/operators/cross_propagation_expected.xsil
new file mode 100644
index 0000000..ee7d426
--- /dev/null
+++ b/testsuite/operators/cross_propagation_expected.xsil
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="cross_propagation.xsil" expected="cross_propagation_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  <name>cross_propagation</name>
+  <author>Graham Dennis</author>
+  <description>
+    Sine cross-propagation validity tests.
+    
+    The 'u' variable checks for errors caused by poorly interpolating
+    dependencies. The 'v' variable checks for errors just in the
+    cross-propagation algorithm. The 'w' variable checks for errors due
+    to IP cross-propagation (should be the smallest). The 'x' variable checks
+    for errors due to EX cross-propagation, they should be the same as 'v'.
+    You can choose the cross-propagation algorithm to be either 'SI' or 'RK4'.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw version="none" />
+    <!-- That's right, this script breaks the shackles with FFTW! -->
+  </features>
+  
+  <geometry>
+    <propagation_dimension> z </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="t" lattice="128"  domain="(0, 10)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" type="complex">
+    <components>
+      foo
+    </components>
+    <initialisation>
+      <![CDATA[
+      foo = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="constants" type="double">
+    <components>cosine</components>
+    <initialisation>
+      <![CDATA[
+        cosine = cos(t);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="zerodConstants" type="double">
+    <components>bar</components>
+    <initialisation>
+      <![CDATA[
+        bar = M_PI;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="cross" type="complex">
+    <components>u v w x</components>
+    <![CDATA[
+      u = 0.0;
+      v = 1.0;
+      w = 1.0;
+      x = 1.0;
+    ]]>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK9" interval="1" steps="2">
+      <samples>1</samples>
+      <operators>
+        <operator kind="cross_propagation" algorithm="SI" propagation_dimension="t">
+          <integration_vectors>cross</integration_vectors>
+          <dependencies>constants zerodConstants</dependencies>
+          <boundary_condition kind="left">
+            <![CDATA[
+              u = 0.0;
+              v = 1.0;
+              w = 1.0;
+              x = 1.0;
+            ]]>
+          </boundary_condition>
+          
+          <operator kind="ip" constant="yes">
+            <operator_names>L</operator_names>
+            <![CDATA[
+              L = i;
+            ]]>
+          </operator>
+          
+          <operator kind="ex" constant="yes">
+            <operator_names>M</operator_names>
+            <![CDATA[
+              M = i;
+            ]]>
+          </operator>
+          <![CDATA[
+            du_dt = cosine;
+            dv_dt = i*v;
+            dw_dt = L[w]; // this one is pretty much exact
+            dx_dt = M[x];
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        dfoo_dz = 0.0;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="no">
+        <dimension name="t" />
+        <moments>error_u error_v error_w error_x</moments>
+        <dependencies>cross</dependencies>
+        <![CDATA[
+          error_u = mod(u - sin(t));
+          error_v = mod(v - pcomplex(1.0, t));
+          error_w = mod(w - pcomplex(1.0, t));
+          error_x = mod(x - pcomplex(1.0, t));
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t error_u error_v error_w error_x 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>128</Dim>
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+cross_propagation_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/operators/cross_propagation_expected_mg0.dat b/testsuite/operators/cross_propagation_expected_mg0.dat
new file mode 100644
index 0000000..06cf421
Binary files /dev/null and b/testsuite/operators/cross_propagation_expected_mg0.dat differ
diff --git a/testsuite/operators/cross_propagation_right.xmds b/testsuite/operators/cross_propagation_right.xmds
new file mode 100644
index 0000000..5dfac58
--- /dev/null
+++ b/testsuite/operators/cross_propagation_right.xmds
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="cross_propagation_right.xsil" expected="cross_propagation_right_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  <name>cross_propagation_right</name>
+  <author>Graham Dennis</author>
+  <description>
+    Sine cross-propagation validity tests.
+    
+    The 'u' variable checks for errors caused by poorly interpolating
+    dependencies. The 'v' variable checks for errors just in the
+    cross-propagation algorithm. The 'w' variable checks for errors due
+    to IP cross-propagation (should be the smallest). The 'x' variable checks
+    for errors due to EX cross-propagation, they should be the same as 'v'.
+    You can choose the cross-propagation algorithm to be either 'SI' or 'RK4'.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> z </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="t" lattice="128"  domain="(-10, 0)" transform="none" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" type="complex">
+    <components>
+      foo
+    </components>
+    <initialisation>
+      <![CDATA[
+      foo = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="constants" type="real">
+    <components>cosine</components>
+    <initialisation>
+      <![CDATA[
+        cosine = cos(t);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="zerodConstants" type="real">
+    <components>bar</components>
+    <initialisation>
+      <![CDATA[
+        bar = M_PI;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="cross" type="complex">
+    <components>u v w x</components>
+    <initialisation>
+      <![CDATA[
+        u = 0.0;
+        v = 0.0;
+        w = 0.0;
+        x = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK9" interval="1" steps="2">
+      <samples>1</samples>
+      <operators>
+        <operator kind="cross_propagation" algorithm="SI" propagation_dimension="t">
+          <integration_vectors>cross</integration_vectors>
+          <dependencies>constants zerodConstants</dependencies>
+          <boundary_condition kind="right">
+            <![CDATA[
+              u = sin(-t);
+              v = polar(1.0, -t);
+              w = polar(1.0, -t);
+              x = polar(1.0, -t);
+            ]]>
+          </boundary_condition>
+          
+          <operator kind="ip" constant="yes">
+            <operator_names>L</operator_names>
+            <![CDATA[
+              L = -i;
+            ]]>
+          </operator>
+          
+          <operator kind="ex" constant="yes">
+            <operator_names>M</operator_names>
+            <![CDATA[
+              M = -i;
+            ]]>
+          </operator>
+          <![CDATA[
+            du_dt = -cosine;
+            dv_dt = -i*v;
+            dw_dt = L[w]; // this one is pretty much exact
+            dx_dt = M[x];
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        dfoo_dz = 0.0;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="t" initial_sample="no">
+        <moments>error_u error_v error_w error_x</moments>
+        <dependencies>cross</dependencies>
+        <![CDATA[
+          error_u = abs(u - sin(-t));
+          error_v = abs(v - polar(1.0, -t));
+          error_w = abs(w - polar(1.0, -t));
+          error_x = abs(x - polar(1.0, -t));
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/operators/cross_propagation_right_expected.xsil b/testsuite/operators/cross_propagation_right_expected.xsil
new file mode 100644
index 0000000..42f5607
--- /dev/null
+++ b/testsuite/operators/cross_propagation_right_expected.xsil
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="cross_propagation_right.xsil" expected="cross_propagation_right_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  <name>cross_propagation_right</name>
+  <author>Graham Dennis</author>
+  <description>
+    Sine cross-propagation validity tests.
+    
+    The 'u' variable checks for errors caused by poorly interpolating
+    dependencies. The 'v' variable checks for errors just in the
+    cross-propagation algorithm. The 'w' variable checks for errors due
+    to IP cross-propagation (should be the smallest). The 'x' variable checks
+    for errors due to EX cross-propagation, they should be the same as 'v'.
+    You can choose the cross-propagation algorithm to be either 'SI' or 'RK4'.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> z </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="t" lattice="128"  domain="(-10, 0)" transform="none" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" type="complex">
+    <components>
+      foo
+    </components>
+    <initialisation>
+      <![CDATA[
+      foo = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="constants" type="real">
+    <components>cosine</components>
+    <initialisation>
+      <![CDATA[
+        cosine = cos(t);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="zerodConstants" type="real">
+    <components>bar</components>
+    <initialisation>
+      <![CDATA[
+        bar = M_PI;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="cross" type="complex">
+    <components>u v w x</components>
+    <initialisation>
+      <![CDATA[
+        u = 0.0;
+        v = 0.0;
+        w = 0.0;
+        x = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK9" interval="1" steps="2">
+      <samples>1</samples>
+      <operators>
+        <operator kind="cross_propagation" algorithm="SI" propagation_dimension="t">
+          <integration_vectors>cross</integration_vectors>
+          <dependencies>constants zerodConstants</dependencies>
+          <boundary_condition kind="right">
+            <![CDATA[
+              u = sin(-t);
+              v = polar(1.0, -t);
+              w = polar(1.0, -t);
+              x = polar(1.0, -t);
+            ]]>
+          </boundary_condition>
+          
+          <operator kind="ip" constant="yes">
+            <operator_names>L</operator_names>
+            <![CDATA[
+              L = -i;
+            ]]>
+          </operator>
+          
+          <operator kind="ex" constant="yes">
+            <operator_names>M</operator_names>
+            <![CDATA[
+              M = -i;
+            ]]>
+          </operator>
+          <![CDATA[
+            du_dt = -cosine;
+            dv_dt = -i*v;
+            dw_dt = L[w]; // this one is pretty much exact
+            dx_dt = M[x];
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        dfoo_dz = 0.0;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="no">
+        <dimension name="t" />
+        <moments>error_u error_v error_w error_x</moments>
+        <dependencies>cross</dependencies>
+        <![CDATA[
+          error_u = abs(u - sin(-t));
+          error_v = abs(v - polar(1.0, -t));
+          error_w = abs(w - polar(1.0, -t));
+          error_x = abs(x - polar(1.0, -t));
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t error_u error_v error_w error_x 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>128</Dim>
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+cross_propagation_right_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/operators/cross_propagation_right_expected_mg0.dat b/testsuite/operators/cross_propagation_right_expected_mg0.dat
new file mode 100644
index 0000000..8868639
Binary files /dev/null and b/testsuite/operators/cross_propagation_right_expected_mg0.dat differ
diff --git a/testsuite/operators/cross_propagation_sic.xmds b/testsuite/operators/cross_propagation_sic.xmds
new file mode 100644
index 0000000..09e0974
--- /dev/null
+++ b/testsuite/operators/cross_propagation_sic.xmds
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="cross_propagation_sic.xsil" expected="cross_propagation_sic_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  <name>cross_propagation_sic</name>
+  <author>Graham Dennis</author>
+  <description>
+    Sine cross-propagation validity tests, using the SIC integrator.
+    
+    The 'u' variable checks for errors caused by poorly interpolating
+    dependencies. The 'v' variable checks for errors just in the
+    cross-propagation algorithm.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <!-- That's right, this script breaks the shackles with FFTW! -->
+  </features>
+  
+  <geometry>
+    <propagation_dimension> z </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="t" lattice="128"  domain="(0, 10)" transform="none" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" type="complex">
+    <components>
+      foo
+    </components>
+    <initialisation>
+      <![CDATA[
+      foo = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="constants" type="real">
+    <components>cosine</components>
+    <initialisation>
+      <![CDATA[
+        cosine = cos(t);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="zerodConstants" type="real" dimensions="">
+    <components>bar</components>
+    <initialisation>
+      <![CDATA[
+        bar = M_PI;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="cross" type="complex">
+    <components>u v</components>
+    <initialisation>
+      <![CDATA[
+        u = 0.0;
+        v = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="SIC" interval="1" steps="2">
+      <samples>1</samples>
+      <operators>
+        <operator kind="cross_propagation" algorithm="SI" propagation_dimension="t">
+          <integration_vectors>cross</integration_vectors>
+          <dependencies>constants zerodConstants</dependencies>
+          <boundary_condition kind="left">
+            <![CDATA[
+              // These are shifted back half a step because the interpretation
+              // of the boundary conditions for SIC is slightly different for normal
+              // cross-propagators. For normal cross-propagators, they start at the left edge
+              // for SIC, they start half a step to the left (or right).
+              u = sin(-0.5*_dt);
+              v = polar(1.0, -0.5*_dt);
+            ]]>
+          </boundary_condition>
+          
+          <![CDATA[
+            du_dt = cosine;
+            dv_dt = i*v;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        dfoo_dz = 0.0;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="t" initial_sample="no">
+        <moments>error_u error_v</moments>
+        <dependencies>cross</dependencies>
+        <![CDATA[
+          error_u = abs(u - sin(t));
+          error_v = abs(v - polar(1.0, t));
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/operators/cross_propagation_sic_expected.xsil b/testsuite/operators/cross_propagation_sic_expected.xsil
new file mode 100644
index 0000000..24422ac
--- /dev/null
+++ b/testsuite/operators/cross_propagation_sic_expected.xsil
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="cross_propagation_sic.xsil" expected="cross_propagation_sic_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  <name>cross_propagation_sic</name>
+  <author>Graham Dennis</author>
+  <description>
+    Sine cross-propagation validity tests, using the SIC integrator.
+    
+    The 'u' variable checks for errors caused by poorly interpolating
+    dependencies. The 'v' variable checks for errors just in the
+    cross-propagation algorithm.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw version="none" />
+    <!-- That's right, this script breaks the shackles with FFTW! -->
+  </features>
+  
+  <geometry>
+    <propagation_dimension> z </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="t" lattice="128"  domain="(0, 10)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" type="complex">
+    <components>
+      foo
+    </components>
+    <initialisation>
+      <![CDATA[
+      foo = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="constants" type="double">
+    <components>cosine</components>
+    <initialisation>
+      <![CDATA[
+        cosine = cos(t);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="zerodConstants" type="double">
+    <components>bar</components>
+    <initialisation>
+      <![CDATA[
+        bar = M_PI;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="cross" type="complex">
+    <components>u v</components>
+    <initialisation>
+      <![CDATA[
+        u = 0.0;
+        v = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="SIC" interval="1" steps="2">
+      <samples>1</samples>
+      <operators>
+        <operator kind="cross_propagation" algorithm="SI" propagation_dimension="t">
+          <integration_vectors>cross</integration_vectors>
+          <dependencies>constants zerodConstants</dependencies>
+          <boundary_condition kind="left">
+            <![CDATA[
+              // These are shifted back half a step because the interpretation
+              // of the boundary conditions for SIC is slightly different for normal
+              // cross-propagators. For normal cross-propagators, they start at the left edge
+              // for SIC, they start half a step to the left (or right).
+              u = sin(-0.5*_dt);
+              v = pcomplex(1.0, -0.5*_dt);
+            ]]>
+          </boundary_condition>
+          
+          <![CDATA[
+            du_dt = cosine;
+            dv_dt = i*v;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        dfoo_dz = 0.0;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="no">
+        <dimension name="t" />
+        <moments>error_u error_v</moments>
+        <dependencies>cross</dependencies>
+        <![CDATA[
+          error_u = mod(u - sin(t));
+          error_v = mod(v - pcomplex(1.0, t));
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t error_u error_v 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>128</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+cross_propagation_sic_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/operators/cross_propagation_sic_expected_mg0.dat b/testsuite/operators/cross_propagation_sic_expected_mg0.dat
new file mode 100644
index 0000000..a4a6df5
Binary files /dev/null and b/testsuite/operators/cross_propagation_sic_expected_mg0.dat differ
diff --git a/testsuite/operators/cross_propagation_sic_right.xmds b/testsuite/operators/cross_propagation_sic_right.xmds
new file mode 100644
index 0000000..79f1dc4
--- /dev/null
+++ b/testsuite/operators/cross_propagation_sic_right.xmds
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="cross_propagation_sic_right.xsil" expected="cross_propagation_sic_right_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  <name>cross_propagation_sic_right</name>
+  <author>Graham Dennis</author>
+  <description>
+    Sine cross-propagation validity tests, using the SIC integrator.
+    
+    The 'u' variable checks for errors caused by poorly interpolating
+    dependencies. The 'v' variable checks for errors just in the
+    cross-propagation algorithm.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <!-- That's right, this script breaks the shackles with FFTW! -->
+  </features>
+  
+  <geometry>
+    <propagation_dimension> z </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="t" lattice="128"  domain="(-10, 0)" transform="none" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" type="complex">
+    <components>
+      foo
+    </components>
+    <initialisation>
+      <![CDATA[
+      foo = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="constants" type="real">
+    <components>cosine</components>
+    <initialisation>
+      <![CDATA[
+        cosine = cos(-t);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="zerodConstants" type="real" dimensions="">
+    <components>bar</components>
+    <initialisation>
+      <![CDATA[
+        bar = M_PI;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="cross" type="complex">
+    <components>u v</components>
+    <initialisation>
+      <![CDATA[
+        u = 0.0;
+        v = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="SIC" interval="1" steps="2">
+      <samples>1</samples>
+      <operators>
+        <operator kind="cross_propagation" algorithm="SI" propagation_dimension="t">
+          <integration_vectors>cross</integration_vectors>
+          <dependencies>constants zerodConstants</dependencies>
+          <boundary_condition kind="right">
+            <![CDATA[
+              // These are shifted back half a step because the interpretation
+              // of the boundary conditions for SIC is slightly different for normal
+              // cross-propagators. For normal cross-propagators, they start at the left edge
+              // for SIC, they start half a step to the left (or right).
+              u = sin(-t-0.5*_dt);
+              v = polar(1.0, -t-0.5*_dt);
+            ]]>
+          </boundary_condition>
+          
+          <![CDATA[
+            du_dt = -cosine;
+            dv_dt = -i*v;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        dfoo_dz = 0.0;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="t" initial_sample="no">
+        <moments>error_u error_v</moments>
+        <dependencies>cross</dependencies>
+        <![CDATA[
+          error_u = abs(u - sin(-t));
+          error_v = abs(v - polar(1.0, -t));
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/operators/cross_propagation_sic_right_expected.xsil b/testsuite/operators/cross_propagation_sic_right_expected.xsil
new file mode 100644
index 0000000..a3f4eac
--- /dev/null
+++ b/testsuite/operators/cross_propagation_sic_right_expected.xsil
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="cross_propagation_sic_right.xsil" expected="cross_propagation_sic_right_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  <name>cross_propagation_sic_right</name>
+  <author>Graham Dennis</author>
+  <description>
+    Sine cross-propagation validity tests, using the SIC integrator.
+    
+    The 'u' variable checks for errors caused by poorly interpolating
+    dependencies. The 'v' variable checks for errors just in the
+    cross-propagation algorithm.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <!-- That's right, this script breaks the shackles with FFTW! -->
+  </features>
+  
+  <geometry>
+    <propagation_dimension> z </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="t" lattice="128"  domain="(-10, 0)" transform="none" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" type="complex">
+    <components>
+      foo
+    </components>
+    <initialisation>
+      <![CDATA[
+      foo = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="constants" type="real">
+    <components>cosine</components>
+    <initialisation>
+      <![CDATA[
+        cosine = cos(-t);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="zerodConstants" type="real" dimensions="">
+    <components>bar</components>
+    <initialisation>
+      <![CDATA[
+        bar = M_PI;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="cross" type="complex">
+    <components>u v</components>
+    <initialisation>
+      <![CDATA[
+        u = 0.0;
+        v = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="SIC" interval="1" steps="2">
+      <samples>1</samples>
+      <operators>
+        <operator kind="cross_propagation" algorithm="SI" propagation_dimension="t">
+          <integration_vectors>cross</integration_vectors>
+          <dependencies>constants zerodConstants</dependencies>
+          <boundary_condition kind="right">
+            <![CDATA[
+              // These are shifted back half a step because the interpretation
+              // of the boundary conditions for SIC is slightly different for normal
+              // cross-propagators. For normal cross-propagators, they start at the left edge
+              // for SIC, they start half a step to the left (or right).
+              u = sin(-t-0.5*_dt);
+              v = polar(1.0, -t-0.5*_dt);
+            ]]>
+          </boundary_condition>
+          
+          <![CDATA[
+            du_dt = -cosine;
+            dv_dt = -i*v;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        dfoo_dz = 0.0;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="no">
+        <dimension name="t" />
+        <moments>error_u error_v</moments>
+        <dependencies>cross</dependencies>
+        <![CDATA[
+          error_u = abs(u - sin(-t));
+          error_v = abs(v - polar(1.0, -t));
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t error_u error_v 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>128</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+cross_propagation_sic_right_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/operators/cross_propagation_sic_right_expected_mg0.dat b/testsuite/operators/cross_propagation_sic_right_expected_mg0.dat
new file mode 100644
index 0000000..b7876ad
Binary files /dev/null and b/testsuite/operators/cross_propagation_sic_right_expected_mg0.dat differ
diff --git a/testsuite/operators/derivative_expected.xsil b/testsuite/operators/derivative_expected.xsil
new file mode 100644
index 0000000..9439065
--- /dev/null
+++ b/testsuite/operators/derivative_expected.xsil
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="constant_complex_ip.xsil" expected="derivative_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>constant_complex_ip</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion using the IP operator (of complex type)
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="10.0" steps="2400" tolerance="1e-5">
+      <samples>24</samples>
+      <operators>
+        <operator kind="ip" constant="yes" type="complex">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <dimension name="y" lattice="128" fourier_space="y" />
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t y dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>25</Dim>
+    <Dim>128</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+derivative_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/operators/derivative_expected_mg0.dat b/testsuite/operators/derivative_expected_mg0.dat
new file mode 100644
index 0000000..b068af0
Binary files /dev/null and b/testsuite/operators/derivative_expected_mg0.dat differ
diff --git a/testsuite/operators/highdimcrossprop.xmds b/testsuite/operators/highdimcrossprop.xmds
new file mode 100644
index 0000000..226a6a4
--- /dev/null
+++ b/testsuite/operators/highdimcrossprop.xmds
@@ -0,0 +1,222 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="highdimcrossprop.xsil" expected="highdimcrossprop_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-4" />
+  </testing>
+  <name>highdimcrossprop</name>
+  
+  <features>
+    <benchmark />
+   
+    <bing />
+      <globals>
+<![CDATA[
+const real pi=3.14159265358979;
+const real g =2*pi*11.4005; // Sqrt(density)/Hz
+const real sample_length = 0.2; //m
+const real time_input =2.5e-6; // sec (5)
+const real sigma=1e-6; // sec (2)
+const real inp_hgt=1e3; //photonnum
+const real gama=2*pi*5.6e6; //Hz
+const real eta =2*pi*10e6/sample_length; //Hz/m (was 2*pi*10e6)
+const real omc=2*pi*20e6; //Hz (was 2*pi*20e6)
+
+const real gama0=0; //2*pi*2e3; //Hz
+const real gamac=0; //2*pi*1e3; //Hz
+const real c=3e8; // m/s
+const real timeswitchz=10e-6; // sec (10)
+
+const real N=1e18; // density 
+const real gNonc = g*N/c; 
+const real delta=2*pi*3e9; //Hz
+
+const real width = 0.001; //m
+const real k0 = 6.28 / (795e-9);
+
+const real alpha=0.00; //m^2/s
+
+]]> 
+  </globals>
+    
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+	   <dimension name="x" lattice="16" domain="(-0.004,0.004)"  /> 
+	   <dimension name="y" lattice="16" domain="(-0.003,0.003)"  /> 
+	   <dimension name="z" lattice="512"  domain="(0,0.2)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="z x y" type="complex">
+    <components>
+    alpha12
+    </components>
+    <initialisation>
+      <![CDATA[
+      alpha12 =  0.0;
+    
+      ]]>
+    </initialisation>
+  </vector>
+
+    <vector name="crossinitial" initial_basis="x y" type="complex">
+    <components>
+    beamprofile
+    </components>
+    <initialisation>
+      <![CDATA[
+      beamprofile=inp_hgt * (2*sqrt(2)*x/width) * exp(-x*x/(width*width)) * exp(-y*y/(width*width))* exp(-i*k0*(x*x+y*y)/0.5);
+      ]]>
+    </initialisation>
+  </vector>
+
+<vector name="cross1" initial_basis="x y z" type="complex">
+    <components>
+     E
+    </components>
+  </vector>
+  
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="20e-8" steps="20" tolerance="1.0e-6">
+          <samples>2 1 2 2 1 1 1 1 1 1</samples>
+      
+       <operators>
+        <operator kind="cross_propagation" algorithm="RK4"  propagation_dimension="z">
+            <operator kind="ip" constant="yes">
+              <operator_names>Btt</operator_names>
+              <![CDATA[
+                Btt = 0; //i*(kx*kx + ky*ky)/(2*k0);
+              ]]>
+            </operator>
+
+          <integration_vectors>cross1</integration_vectors>
+          <!-- You can have a dependencies tag in here -->
+          <dependencies>main</dependencies>
+          <boundary_condition kind="left">
+            <!-- You can also have a dependencies tag in here -->
+            <!-- like the one shown below, but none are needed -->
+            <!-- in this example -->
+			<dependencies>crossinitial</dependencies> 
+      <![CDATA[
+	  
+	  //E=inp_hgt*exp(-(t-time_input)*(t-time_input)/(sigma*sigma)) * exp(-x*x/(width*width))*exp(-y*y/(width*width));
+	  E = exp(-(t-time_input)*(t-time_input)/(sigma*sigma)) * beamprofile;
+			
+			]]>
+          </boundary_condition>
+          <![CDATA[
+      complex aalpha13 = (alpha12*omc+g*E)/delta;
+	  
+	  dE_dz =  i*gNonc*(aalpha13) + Btt[E]; 
+	   
+          ]]>
+        </operator>
+           <operator kind="ip" constant="yes">
+              <operator_names>Ltt</operator_names>
+              <![CDATA[
+                Ltt = -alpha*(kz*kz+kx*kx+ky*ky);
+              ]]>
+            </operator>
+        
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+
+complex sw  = -1.0;
+
+complex aalpha13 = (alpha12*omc+g*E)/(delta-i*(gamac/2+gama+gama0/2));
+dalpha12_dt  = ((-gama0 - gamac-i*(sw*eta*(z-sample_length/2) +(omc*omc)/delta))*alpha12+i*aalpha13*(omc)) + Ltt[alpha12];
+
+
+        ]]>
+      </operators>
+      
+    </integrate>
+  </sequence>
+  
+  <output format="hdf5" filename="highdimcrossprop.xsil">
+      <sampling_group basis="x(16) y(16) z(128)" initial_sample="yes">
+        <moments>bprobereal bprobeimag</moments>
+        <dependencies>cross1</dependencies>
+        <![CDATA[
+bprobereal = E.Re();
+bprobeimag = E.Im();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx(16) ky(16) kz(128)" initial_sample="yes">
+        <moments>bproberealK bprobeimagK bintensityK</moments>
+        <dependencies>cross1</dependencies>
+        <![CDATA[
+          bproberealK = E.Re();
+          bprobeimagK = E.Im();
+          bintensityK = mod2(E);
+        ]]>
+      </sampling_group>
+       <sampling_group basis="x(16) y(16) z(256)" initial_sample="yes">
+        <moments>balpreal12 balpimag12</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+balpreal12 = (alpha12).Re();
+balpimag12 = (alpha12).Im();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx(2) ky(2) kz(256)" initial_sample="yes">
+        <moments>balpreal12K balpimag12K</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          balpreal12K = (alpha12).Re();
+          balpimag12K = (alpha12).Im();
+        ]]>
+      </sampling_group>
+        <sampling_group basis="x(0) y(0) z(512)" initial_sample="yes">
+        <moments>bprobereal bprobeimag</moments>
+        <dependencies>cross1</dependencies>
+        <![CDATA[
+bprobereal = E.Re();
+bprobeimag = E.Im();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(16) z(0)" initial_sample="yes">
+        <moments>bprobereal bprobeimag</moments>
+        <dependencies>cross1</dependencies>
+        <![CDATA[
+bprobereal = E.Re();
+bprobeimag = E.Im();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(16) y(0) z(0)" initial_sample="yes">
+        <moments>bprobereal bprobeimag</moments>
+        <dependencies>cross1</dependencies>
+        <![CDATA[
+bprobereal = E.Re();
+bprobeimag = E.Im();
+        ]]>
+      </sampling_group>
+       <sampling_group basis="x(0) y(0) z(512)" initial_sample="no">
+        <moments>balpreal12 balpimag12</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          balpreal12 = Re(alpha12);
+          balpimag12 = Im(alpha12);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(16) y(0) z(0)" initial_sample="no">
+        <moments>balpreal12 balpimag12</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          balpreal12 = Re(alpha12);
+          balpimag12 = Im(alpha12);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(16) z(0)" initial_sample="no">
+        <moments>balpreal12 balpimag12</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          balpreal12 = Re(alpha12);
+          balpimag12 = Im(alpha12);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/operators/highdimcrossprop_expected.h5 b/testsuite/operators/highdimcrossprop_expected.h5
new file mode 100644
index 0000000..62dc6a2
Binary files /dev/null and b/testsuite/operators/highdimcrossprop_expected.h5 differ
diff --git a/testsuite/operators/highdimcrossprop_expected.xsil b/testsuite/operators/highdimcrossprop_expected.xsil
new file mode 100644
index 0000000..2166618
--- /dev/null
+++ b/testsuite/operators/highdimcrossprop_expected.xsil
@@ -0,0 +1,412 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="highdimcrossprop.xsil" expected="highdimcrossprop_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-4" />
+  </testing>
+  <name>highdimcrossprop</name>
+  
+  <features>
+    <benchmark />
+   
+    <bing />
+      <globals>
+<![CDATA[
+const real pi=3.14159265358979;
+const real g =2*pi*11.4005; // Sqrt(density)/Hz
+const real sample_length = 0.2; //m
+const real time_input =2.5e-6; // sec (5)
+const real sigma=1e-6; // sec (2)
+const real inp_hgt=1e3; //photonnum
+const real gama=2*pi*5.6e6; //Hz
+const real eta =2*pi*10e6/sample_length; //Hz/m (was 2*pi*10e6)
+const real omc=2*pi*20e6; //Hz (was 2*pi*20e6)
+
+const real gama0=0; //2*pi*2e3; //Hz
+const real gamac=0; //2*pi*1e3; //Hz
+const real c=3e8; // m/s
+const real timeswitchz=10e-6; // sec (10)
+
+const real N=1e18; // density 
+const real gNonc = g*N/c; 
+const real delta=2*pi*3e9; //Hz
+
+const real width = 0.001; //m
+const real k0 = 6.28 / (795e-9);
+
+const real alpha=0.00; //m^2/s
+
+]]> 
+  </globals>
+    
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+           <dimension name="x" lattice="16" domain="(-0.004,0.004)"  /> 
+           <dimension name="y" lattice="16" domain="(-0.003,0.003)"  /> 
+           <dimension name="z" lattice="512"  domain="(0,0.2)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="z x y" type="complex">
+    <components>
+    alpha12
+    </components>
+    <initialisation>
+      <![CDATA[
+      alpha12 =  0.0;
+    
+      ]]>
+    </initialisation>
+  </vector>
+
+    <vector name="crossinitial" initial_basis="x y" type="complex">
+    <components>
+    beamprofile
+    </components>
+    <initialisation>
+      <![CDATA[
+      beamprofile=inp_hgt * (2*sqrt(2)*x/width) * exp(-x*x/(width*width)) * exp(-y*y/(width*width))* exp(-i*k0*(x*x+y*y)/0.5);
+      ]]>
+    </initialisation>
+  </vector>
+
+<vector name="cross1" initial_basis="x y z" type="complex">
+    <components>
+     E
+    </components>
+  </vector>
+  
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="20e-8" steps="20" tolerance="1.0e-6">
+          <samples>2 1 2 2 1 1 1 1 1 1</samples>
+      
+       <operators>
+        <operator kind="cross_propagation" algorithm="RK4"  propagation_dimension="z">
+            <operator kind="ip" constant="yes">
+              <operator_names>Btt</operator_names>
+              <![CDATA[
+                Btt = 0; //i*(kx*kx + ky*ky)/(2*k0);
+              ]]>
+            </operator>
+
+          <integration_vectors>cross1</integration_vectors>
+          <!-- You can have a dependencies tag in here -->
+          <dependencies>main</dependencies>
+          <boundary_condition kind="left">
+            <!-- You can also have a dependencies tag in here -->
+            <!-- like the one shown below, but none are needed -->
+            <!-- in this example -->
+                        <dependencies>crossinitial</dependencies> 
+      <![CDATA[
+          
+          //E=inp_hgt*exp(-(t-time_input)*(t-time_input)/(sigma*sigma)) * exp(-x*x/(width*width))*exp(-y*y/(width*width));
+          E = exp(-(t-time_input)*(t-time_input)/(sigma*sigma)) * beamprofile;
+                        
+                        ]]>
+          </boundary_condition>
+          <![CDATA[
+      complex aalpha13 = (alpha12*omc+g*E)/delta;
+          
+          dE_dz =  i*gNonc*(aalpha13) + Btt[E]; 
+           
+          ]]>
+        </operator>
+           <operator kind="ip" constant="yes">
+              <operator_names>Ltt</operator_names>
+              <![CDATA[
+                Ltt = -alpha*(kz*kz+kx*kx+ky*ky);
+              ]]>
+            </operator>
+        
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+
+complex sw  = -1.0;
+
+complex aalpha13 = (alpha12*omc+g*E)/(delta-i*(gamac/2+gama+gama0/2));
+dalpha12_dt  = ((-gama0 - gamac-i*(sw*eta*(z-sample_length/2) +(omc*omc)/delta))*alpha12+i*aalpha13*(omc)) + Ltt[alpha12];
+
+
+        ]]>
+      </operators>
+      
+    </integrate>
+  </sequence>
+  
+  <output format="hdf5" filename="highdimcrossprop.xsil">
+      <sampling_group basis="x(16) y(16) z(128)" initial_sample="yes">
+        <moments>bprobereal bprobeimag</moments>
+        <dependencies>cross1</dependencies>
+        <![CDATA[
+bprobereal = E.Re();
+bprobeimag = E.Im();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx(16) ky(16) kz(128)" initial_sample="yes">
+        <moments>bproberealK bprobeimagK bintensityK</moments>
+        <dependencies>cross1</dependencies>
+        <![CDATA[
+          bproberealK = E.Re();
+          bprobeimagK = E.Im();
+          bintensityK = mod2(E);
+        ]]>
+      </sampling_group>
+       <sampling_group basis="x(16) y(16) z(256)" initial_sample="yes">
+        <moments>balpreal12 balpimag12</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+balpreal12 = (alpha12).Re();
+balpimag12 = (alpha12).Im();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx(2) ky(2) kz(256)" initial_sample="yes">
+        <moments>balpreal12K balpimag12K</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          balpreal12K = (alpha12).Re();
+          balpimag12K = (alpha12).Im();
+        ]]>
+      </sampling_group>
+        <sampling_group basis="x(0) y(0) z(512)" initial_sample="yes">
+        <moments>bprobereal bprobeimag</moments>
+        <dependencies>cross1</dependencies>
+        <![CDATA[
+bprobereal = E.Re();
+bprobeimag = E.Im();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(16) z(0)" initial_sample="yes">
+        <moments>bprobereal bprobeimag</moments>
+        <dependencies>cross1</dependencies>
+        <![CDATA[
+bprobereal = E.Re();
+bprobeimag = E.Im();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(16) y(0) z(0)" initial_sample="yes">
+        <moments>bprobereal bprobeimag</moments>
+        <dependencies>cross1</dependencies>
+        <![CDATA[
+bprobereal = E.Re();
+bprobeimag = E.Im();
+        ]]>
+      </sampling_group>
+       <sampling_group basis="x(0) y(0) z(512)" initial_sample="no">
+        <moments>balpreal12 balpimag12</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          balpreal12 = Re(alpha12);
+          balpimag12 = Im(alpha12);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(16) y(0) z(0)" initial_sample="no">
+        <moments>balpreal12 balpimag12</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          balpreal12 = Re(alpha12);
+          balpimag12 = Im(alpha12);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(16) z(0)" initial_sample="no">
+        <moments>balpreal12 balpimag12</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          balpreal12 = Re(alpha12);
+          balpimag12 = Im(alpha12);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">4</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>6</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t x y z bprobereal bprobeimag 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>3</Dim>
+    <Dim>16</Dim>
+    <Dim>16</Dim>
+    <Dim>128</Dim>
+    <Dim>6</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+highdimcrossprop_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">4</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>7</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t kx ky kz bproberealK bprobeimagK bintensityK 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>2</Dim>
+    <Dim>16</Dim>
+    <Dim>16</Dim>
+    <Dim>128</Dim>
+    <Dim>7</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/2"/>
+highdimcrossprop_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_3">
+  <Param Name="n_independent">4</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>6</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t x y z balpreal12 balpimag12 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>3</Dim>
+    <Dim>16</Dim>
+    <Dim>16</Dim>
+    <Dim>256</Dim>
+    <Dim>6</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/3"/>
+highdimcrossprop_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_4">
+  <Param Name="n_independent">4</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>6</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t kx ky kz balpreal12K balpimag12K 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>3</Dim>
+    <Dim>2</Dim>
+    <Dim>2</Dim>
+    <Dim>256</Dim>
+    <Dim>6</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/4"/>
+highdimcrossprop_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_5">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t z bprobereal bprobeimag 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>2</Dim>
+    <Dim>512</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/5"/>
+highdimcrossprop_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_6">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t y bprobereal bprobeimag 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>2</Dim>
+    <Dim>16</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/6"/>
+highdimcrossprop_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_7">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t x bprobereal bprobeimag 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>2</Dim>
+    <Dim>16</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/7"/>
+highdimcrossprop_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_8">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+z balpreal12 balpimag12 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>512</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/8"/>
+highdimcrossprop_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_9">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x balpreal12 balpimag12 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>16</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/9"/>
+highdimcrossprop_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_10">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+y balpreal12 balpimag12 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>16</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/10"/>
+highdimcrossprop_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/operators/nonconstant_complex_ip.xmds b/testsuite/operators/nonconstant_complex_ip.xmds
new file mode 100644
index 0000000..3c220c1
--- /dev/null
+++ b/testsuite/operators/nonconstant_complex_ip.xmds
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="nonconstant_complex_ip.xsil" expected="derivative_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>nonconstant_complex_ip</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion using the IP operator (of complex type)
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="10.0" steps="2400" tolerance="1e-5">
+      <samples>24</samples>
+      <operators>
+        <operator kind="ip" constant="no" type="complex">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/operators/nonconstant_double_ip.xmds b/testsuite/operators/nonconstant_double_ip.xmds
new file mode 100644
index 0000000..1360b05
--- /dev/null
+++ b/testsuite/operators/nonconstant_double_ip.xmds
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="nonconstant_double_ip.xsil" expected="derivative_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>nonconstant_double_ip</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion using the IP operator (of double type)
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="10.0" steps="2400" tolerance="1e-5">
+      <samples>24</samples>
+      <operators>
+        <operator kind="ip" constant="no" type="real">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/operators/nonconstant_ex.xmds b/testsuite/operators/nonconstant_ex.xmds
new file mode 100644
index 0000000..07d4a64
--- /dev/null
+++ b/testsuite/operators/nonconstant_ex.xmds
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="nonconstant_ex.xsil" expected="derivative_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>nonconstant_ex</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion using the EX operator
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="estimate" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="y" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="10.0" steps="24000" tolerance="1e-5">
+      <samples>24</samples>
+      <operators>
+        <operator kind="ex" constant="no">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/runtime_lattice/breakpoints_hdf5.xmds b/testsuite/runtime_lattice/breakpoints_hdf5.xmds
new file mode 100644
index 0000000..3a8c10c
--- /dev/null
+++ b/testsuite/runtime_lattice/breakpoints_hdf5.xmds
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="breakpoints_hdf5_xspace.xsil"          expected="../io/breakpoints_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_kspace.xsil"          expected="../io/breakpoints_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_2d_xspace.xsil"       expected="../io/breakpoints_2d_xspace_expected.xsil"  absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space1.xsil"    expected="../io/breakpoints_mixed_space1_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space2.xsil"    expected="../io/breakpoints_mixed_space2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_xspace.xsil"          expected="../io/breakpoints_hdf5_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_kspace.xsil"          expected="../io/breakpoints_hdf5_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_2d_xspace.xsil"       expected="../io/breakpoints_hdf5_2d_xspace_expected.xsil"  absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space1.xsil"    expected="../io/breakpoints_hdf5_mixed_space1_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="breakpoints_hdf5_mixed_space2.xsil"    expected="../io/breakpoints_hdf5_mixed_space2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>breakpoints_hdf5</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test making a breakpoints in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+    <validation kind="run-time" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100*1"  domain="(0, 1)" />
+      <dimension name="y" lattice="256*1"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="x" type="complex">
+    <components>u</components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5))*(sin(x) + i*cos(2*x)*cos(2*x));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="x y">
+    <components>v</components>
+    <initialisation>
+      <![CDATA[
+        v = abs(x - 0.5) < 0.3 ? 1.0 : 0.0;
+        v *= abs(y) < 0.5 ? (cos(y) + i*sin(x)*sin(y)) : complex(0.0, 0.0);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="breakpoints_hdf5_xspace.xsil">
+      <dependencies basis="x">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_kspace.xsil">
+      <dependencies basis="kx">oned</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_2d_xspace.xsil">
+      <dependencies basis="x y">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_mixed_space1.xsil">
+      <dependencies basis="x ky">twod</dependencies>
+    </breakpoint>
+    <breakpoint filename="breakpoints_hdf5_mixed_space2.xsil">
+      <dependencies basis="kx y">twod</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="hdf5" />
+</simulation>
\ No newline at end of file
diff --git a/testsuite/runtime_lattice/integer_dimensions.xmds b/testsuite/runtime_lattice/integer_dimensions.xmds
new file mode 100644
index 0000000..7d0e2ee
--- /dev/null
+++ b/testsuite/runtime_lattice/integer_dimensions.xmds
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <arguments>--j_max 4</arguments>
+    <xsil_file name="integer_dimensions.xsil" expected="../geometry/integer_dimensions_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>integer_dimensions</name>
+  <author>Graham Dennis</author>
+  <description>
+    xpdeint script to test integer dimensions.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+	<validation kind="run-time" />
+	<arguments>
+		<argument name="j_max" type="integer" default_value="100" />
+	</arguments>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" type="integer" domain="(0, j_max)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" type="complex">
+    <components>
+      x
+    </components>
+    <initialisation>
+      <![CDATA[
+      x(j => j) = 1.0e-3;
+      x(j => 0) = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="60.0" steps="25000">
+      <samples>100</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        long j_minus_one = (j-1) % _lattice_j;
+        if (j_minus_one < 0)
+          j_minus_one += _lattice_j;
+        long j_plus_one  = (j+1) % _lattice_j;
+        dx_dt(j => j) = x(j => j)*(x(j => j_minus_one) - x(j => j_plus_one));
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="j" initial_sample="yes">
+        <moments>xR</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          xR = x.Re();
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/runtime_lattice/integer_dimensions_with_fixed_lattice.xmds b/testsuite/runtime_lattice/integer_dimensions_with_fixed_lattice.xmds
new file mode 100644
index 0000000..ef52fcb
--- /dev/null
+++ b/testsuite/runtime_lattice/integer_dimensions_with_fixed_lattice.xmds
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <arguments>--j_max 4</arguments>
+    <xsil_file name="integer_dimensions_with_runtime_lattice.xsil" expected="../geometry/integer_dimensions_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>integer_dimensions_with_runtime_lattice</name>
+  <author>Graham Dennis</author>
+  <description>
+    xpdeint script to test integer dimensions.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+	<validation kind="run-time" />
+	<arguments>
+		<argument name="j_max" type="integer" default_value="100" />
+	</arguments>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" type="integer" lattice="5" domain="(0, j_max)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" type="complex">
+    <components>
+      x
+    </components>
+    <initialisation>
+      <![CDATA[
+      x(j => j) = 1.0e-3;
+      x(j => 0) = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="60.0" steps="25000">
+      <samples>100</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        long j_minus_one = (j-1) % _lattice_j;
+        if (j_minus_one < 0)
+          j_minus_one += _lattice_j;
+        long j_plus_one  = (j+1) % _lattice_j;
+        dx_dt(j => j) = x(j => j)*(x(j => j_minus_one) - x(j => j_plus_one));
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="j" initial_sample="yes">
+        <moments>xR</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          xR = x.Re();
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/runtime_lattice/integer_dimensions_with_runtime_lattice.xmds b/testsuite/runtime_lattice/integer_dimensions_with_runtime_lattice.xmds
new file mode 100644
index 0000000..f0b4220
--- /dev/null
+++ b/testsuite/runtime_lattice/integer_dimensions_with_runtime_lattice.xmds
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <arguments>--j_max 4</arguments>
+    <xsil_file name="integer_dimensions_with_runtime_lattice.xsil" expected="../geometry/integer_dimensions_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>integer_dimensions_with_runtime_lattice</name>
+  <author>Graham Dennis</author>
+  <description>
+    xpdeint script to test integer dimensions.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+	<validation kind="run-time" />
+	<arguments>
+		<argument name="j_max" type="integer" default_value="100" />
+	</arguments>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" type="integer" lattice="5*1" domain="(0, j_max)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" type="complex">
+    <components>
+      x
+    </components>
+    <initialisation>
+      <![CDATA[
+      x(j => j) = 1.0e-3;
+      x(j => 0) = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="60.0" steps="25000">
+      <samples>100</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+        long j_minus_one = (j-1) % _lattice_j;
+        if (j_minus_one < 0)
+          j_minus_one += _lattice_j;
+        long j_plus_one  = (j+1) % _lattice_j;
+        dx_dt(j => j) = x(j => j)*(x(j => j_minus_one) - x(j => j_plus_one));
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="j" initial_sample="yes">
+        <moments>xR</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          xR = x.Re();
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/runtime_lattice/runtime_lattice_diffusion_dst.xmds b/testsuite/runtime_lattice/runtime_lattice_diffusion_dst.xmds
new file mode 100644
index 0000000..b114a50
--- /dev/null
+++ b/testsuite/runtime_lattice/runtime_lattice_diffusion_dst.xmds
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <arguments>--latticesize 128</arguments>
+    <xsil_file name="runtime_lattice_diffusion_dst.xsil" expected="../transforms/diffusion_dst_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>runtime_lattice_diffusion_dst</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion solved using a Discrete Sine Transform (odd boundary conditions at both ends)
+    Odd boundary conditions essentially mimics zero dirichlet boundary conditions for linear problems.
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw plan="exhaustive" />
+    <validation kind="run-time"/>
+    <arguments>
+      <argument name="latticesize" type="integer" default_value="70"/>
+    </arguments>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="latticesize" domain="(-1.0, 1.0)" transform="dst" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="y" type="real">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-3*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="20.0" steps="2400" tolerance="1e-5">
+      <samples>48</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="ky">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/runtime_lattice/runtime_lattice_initialisation_order.xmds b/testsuite/runtime_lattice/runtime_lattice_initialisation_order.xmds
new file mode 100644
index 0000000..d6d898e
--- /dev/null
+++ b/testsuite/runtime_lattice/runtime_lattice_initialisation_order.xmds
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <arguments>--latticesize 256</arguments>
+    <xsil_file name="runtime_lattice_initialisation_order.xsil" expected="../vectors/initialisation_order_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>runtime_lattice_initialisation_order</name>
+  <author>Graham Dennis</author>
+  <description>
+    1D TW model of the uniform Peaks system. Groundstate finder.
+    Demonstrates a phase-separated BEC groundstate.
+    Note that the initialisation of the 'wavefunction' vector
+    depends on the 'potential' vector having already been evaluated.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <fftw plan="exhaustive" />
+    <globals>
+      <![CDATA[
+      /* physical constants  */
+       const real omegaz = 2*M_PI*55.0;
+       const real omegarho = 2*M_PI*1020.0;
+       const real hbar = 1.05457148e-34;
+       const real M = 4.0026032*1.66053886e-27;
+       const real scatteringLength = 7.51e-9;
+       const real Uint3 = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+       const real Nparticles = 2.0e6;
+       const real mu = pow(15*Nparticles*Uint3*omegarho*omegarho*omegaz/(8.0*M_PI)*pow(M/2,3.0/2.0),2.0/5.0);
+       const real Uint = Uint3*5.0*omegarho*omegarho*M/(4.0*M_PI*mu);
+       const real Uint_hbar = Uint/hbar;
+       const complex miUint_hbar = -i*Uint_hbar;
+       const real otherScatteringLength = 5.56e-9;
+       const real kappa = otherScatteringLength/scatteringLength;
+       const real eta = 0.5;
+       real Delta;
+       const real hbar_M = hbar/M;
+       
+       /* absorbing boundary constants */
+        const real absorbleft = 5.0e4;
+        const real absorbright = 5.0e4;
+        const real widthPerp = 5.0e-6;
+       
+      ]]>
+    </globals>
+    <validation kind="run-time"/>
+    <arguments>
+      <argument name="latticesize" type="integer" default_value="70"/>
+    </arguments>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="z" lattice="latticesize"  domain="(-36e-5, 36e-5)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" initial_basis="z" type="complex">
+    <components>V</components>
+    <initialisation>
+      <![CDATA[
+        V = 0.5*M*omegaz*omegaz*z*z;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" initial_basis="z" type="complex">
+    <components>
+      phi1 phi0
+    </components>
+    <initialisation>
+      <dependencies>potential</dependencies>
+      <![CDATA[
+        phi1 = phi0 = 0.0;
+        if (eta*mu - V.Re() > 0.0) {
+          phi1 = sqrt((eta*mu - V.Re())/Uint);
+        }
+        if ((1.0-eta)*mu - V.Re() > 0.0) {
+          phi0 = sqrt(((1.0-eta)*mu - V.Re())/Uint);
+        }
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>N1 N0</components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        N1 = mod2(phi1);
+        N0 = mod2(phi0);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <vector name="normalisation_copy" dimensions="" type="real">
+    <components>N1_copy N0_copy</components>
+    <initialisation>
+      <dependencies>normalisation</dependencies>
+      <![CDATA[
+        N1_copy = N1;
+        N0_copy = N0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <filter>
+      <dependencies>wavefunction normalisation_copy</dependencies>
+      <![CDATA[
+        phi1 *= sqrt(eta*Nparticles/N1_copy);
+        phi0 *= sqrt((1.0-eta)*Nparticles/N0_copy);
+      ]]>
+    </filter>
+    <integrate algorithm="RK4" interval="5.0e-4" steps="500">
+      <samples>50 50</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            phi1 *= sqrt(eta*Nparticles/N1);
+            phi0 *= sqrt((1.0-eta)*Nparticles/N0);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*hbar/M*kz*kz;
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi1_dt = T[phi1] - 1.0/hbar*(V + Uint*(mod2(phi1) + mod2(phi0)) - eta*mu)*phi1;
+          dphi0_dt = T[phi0] - 1.0/hbar*(V + Uint*(mod2(phi1) + kappa*mod2(phi0)) - (1.0-eta)*mu)*phi0;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="hdf5">
+      <sampling_group basis="z" initial_sample="yes">
+        <moments>dens1 dens0</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens1 = mod2(phi1);
+          dens0 = mod2(phi0);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kz" initial_sample="yes">
+        <moments>dens1 dens0</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens1 = mod2(phi1);
+          dens0 = mod2(phi0);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/runtime_lattice/runtime_lattice_mpi_dft_small.xmds b/testsuite/runtime_lattice/runtime_lattice_mpi_dft_small.xmds
new file mode 100644
index 0000000..0b48e3d
--- /dev/null
+++ b/testsuite/runtime_lattice/runtime_lattice_mpi_dft_small.xmds
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+<testing>
+    <arguments>--latticesize_x 10 --latticesize_y 10</arguments>
+    <command_line>mpirun -n 8 ./runtime_lattice_mpi_dft_small</command_line>
+    <xsil_file name="runtime_lattice_mpi_dft_small_xspace1.xsil" expected="../mpi/mpi_dft_small_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="runtime_lattice_mpi_dft_small_kspace.xsil"  expected="../mpi/mpi_dft_small_kspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="runtime_lattice_mpi_dft_small_kspace2.xsil" expected="../mpi/mpi_dft_small_kspace2_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="runtime_lattice_mpi_dft_small_xspace2.xsil" expected="../mpi/mpi_dft_small_xspace_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+
+  
+  <name>runtime_lattice_mpi_dft_small</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test of the fourier transforms using MPI.
+    
+    Checking that when the number of processors is of the same order as the number of grid points that things don't go awry
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+    <validation kind="run-time"/>
+    <arguments>
+      <argument name="latticesize_x" type="integer" default_value="50"/>
+      <argument name="latticesize_y" type="integer" default_value="70"/>
+    </arguments>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="latticesize_x"  domain="(-1, 1)" />
+      <dimension name="y" lattice="latticesize_y"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <driver name="distributed-mpi" />
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      u
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*((x-0.5)*(x-0.5) + y*y));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="runtime_lattice_mpi_dft_small_xspace1.xsil">
+      <dependencies>main</dependencies>
+    </breakpoint>
+    <breakpoint filename="runtime_lattice_mpi_dft_small_kspace.xsil">
+      <dependencies basis="ky kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="runtime_lattice_mpi_dft_small_kspace2.xsil">
+      <dependencies basis="ky x">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="runtime_lattice_mpi_dft_small_xspace2.xsil">
+      <dependencies basis="y x">main</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+  </output>
+</simulation>
diff --git a/testsuite/runtime_lattice/runtime_lattice_nonlocal_split_uniform_access.xmds b/testsuite/runtime_lattice/runtime_lattice_nonlocal_split_uniform_access.xmds
new file mode 100644
index 0000000..71e55bc
--- /dev/null
+++ b/testsuite/runtime_lattice/runtime_lattice_nonlocal_split_uniform_access.xmds
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <arguments>--x_lattice 256</arguments>
+    <xsil_file name="runtime_lattice_nonlocal_split_uniform_access.xsil" expected="../geometry/nonlocal_split_uniform_access_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>runtime_lattice_nonlocal_split_uniform_access</name>
+  <author>Graham Dennis</author>
+  <description>
+    Script to test accessing a fourier-transformed dimension backwards.
+    Based off of vibstring.xmds
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="patient" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      const real T_mu = T/mu;
+      
+      const real xmax = _max_x;
+      const real width = 0.1;
+      const real absorb = 80.0;
+      ]]>
+    </globals>
+    <arguments>
+      <argument name="x_lattice" type="integer" default_value="300" />
+    </arguments>
+    <validation kind="run-time" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="x_lattice"  domain="(-1, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5))*exp(i*200*x);
+        uDot = u*i*200*sqrt(T_mu);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-5" interval="2e-3" steps="1000">
+      <samples>5</samples>
+      <operators>
+        <operator kind="ex" constant="no">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T_mu*kx*kx;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="kx" initial_sample="yes">
+        <moments>amp amp_reversed</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = mod2(u);
+          amp_reversed = mod2(u(kx => -kx));
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/runtime_lattice/runtime_lattice_vibstring_ark89.xmds b/testsuite/runtime_lattice/runtime_lattice_vibstring_ark89.xmds
new file mode 100644
index 0000000..63f54c1
--- /dev/null
+++ b/testsuite/runtime_lattice/runtime_lattice_vibstring_ark89.xmds
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  
+  <testing>
+    <arguments>--latticesize 100</arguments>
+    <xsil_file name="runtime_lattice_vibstring_ark89.xsil" expected="../integrators/vibstring_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5">
+      <moment_group number="1" absolute_tolerance="1e-7" relative_tolerance="1e-6" />
+      <moment_group number="2" absolute_tolerance="1e-3" relative_tolerance="1e-6" />
+    </xsil_file>
+  </testing>
+  
+  <name>runtime_lattice_vibstring_ark89</name>
+  <author>Mattias Johnsson</author>
+  <description>
+    Vibrating string
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <fftw plan="estimate" />
+    <validation kind="run-time"/>
+    
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+
+    <arguments>
+      <argument name="latticesize" type="integer" default_value="50"/>
+    </arguments>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="latticesize"  domain="(0, 1)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK89" interval="2e-3" steps="100" tolerance="1e-7">
+      <samples>50 50</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx(50)" initial_sample="no">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/runtime_lattice/runtime_lattice_xsilloading_hdf5_loose2.xmds b/testsuite/runtime_lattice/runtime_lattice_xsilloading_hdf5_loose2.xmds
new file mode 100644
index 0000000..2544efd
--- /dev/null
+++ b/testsuite/runtime_lattice/runtime_lattice_xsilloading_hdf5_loose2.xmds
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <arguments>--x_lattice 250 --y_lattice 512</arguments>
+    <input_xsil_file name="../io/breakpoints_hdf5_kspace_expected.xsil" />
+    <input_xsil_file name="../io/breakpoints_hdf5_mixed_space2_expected.xsil" />
+    <xsil_file name="runtime_lattice_xsilloading_hdf5_loose2.xsil" expected="../io/xsilloading_expected2.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>runtime_lattice_xsilloading_hdf5_loose2</name>
+  <author>Graham Dennis</author>
+  <description>
+    Test loading xsil files in various spaces
+  </description>
+  
+  <features>
+    <fftw plan="estimate" />
+    <validation kind="run-time"/>
+
+    <arguments>
+      <argument name="x_lattice" type="integer" default_value="110"/>
+      <argument name="y_lattice" type="integer" default_value="201"/>
+    </arguments>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="x_lattice"  domain="(0, 1)" />
+      <dimension name="y" lattice="y_lattice"  domain="(-2, 2)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="oned" dimensions="x" initial_basis="kx" type="complex">
+    <components>u</components>
+    <initialisation kind="hdf5" geometry_matching_mode="loose">
+      <filename>breakpoints_hdf5_kspace_expected.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <vector name="twod" dimensions="x y" initial_basis="kx y">
+    <components>v</components>
+    <initialisation kind="hdf5" geometry_matching_mode="loose">
+      <filename>breakpoints_hdf5_mixed_space2_expected.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <filter>
+      <![CDATA[
+        ;
+      ]]>
+    </filter>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="x(50) y(0)" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>oned twod</dependencies>
+        <![CDATA[
+	            amp = cos(u.Re())*sin(u.Im())/2.0 - v.Re()*v.Re()*x*y + sin(y)*v.Im(); // Some crazy function to combine the quantities
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/stochastic/bessel_cosine_stochastic_groundstate.xmds b/testsuite/stochastic/bessel_cosine_stochastic_groundstate.xmds
new file mode 100644
index 0000000..c2cf361
--- /dev/null
+++ b/testsuite/stochastic/bessel_cosine_stochastic_groundstate.xmds
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="bessel_cosine_stochastic_groundstate.xsil" expected="bessel_cosine_stochastic_groundstate_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+  </testing>
+
+  <author>Graham Dennis</author>
+  <name>bessel_cosine_stochastic_groundstate</name>
+  <description>
+    Calculate the 3D ground state of a Rubidium BEC in a harmonic magnetic trap assuming
+    cylindrical symmetry about the z axis and reflection symmetry about z=0.
+    This permits us to use the cylindrical bessel functions to expand the solution transverse
+    to z and a cosine series to expand the solution along z.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <chunked_output size="100KB" />
+    <globals>
+      <![CDATA[
+        const real omegaz = 2*M_PI*20;
+        const real omegarho = 2*M_PI*200;
+        const real hbar = 1.05457148e-34;
+        const real M = 1.409539200000000e-25;
+        const real g = 9.8;
+        const real scatteringLength = 5.57e-9;
+        const real Uint = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+        const real Nparticles = 5.0e5;
+
+        /* offset constants */
+        const real EnergyOffset = pow(15.0*Nparticles*Uint*omegaz*omegarho*omegarho/(8*M_PI), 2.0/5.0)
+                                    * pow(M/2.0, 3.0/5.0);
+
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="r" lattice="32"  domain="(0.0, 1.0e-5)" transform="bessel" volume_prefactor="2.0*M_PI" />
+      <dimension name="z" lattice="32"  domain="(0.0, 1.0e-4)" transform="dct" volume_prefactor="2.0" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" type="complex">
+    <components>
+      V1
+    </components>
+    <initialisation>
+      <![CDATA[
+        real Vtrap = 0.5*M*(omegarho*omegarho*r*r + omegaz*omegaz*z*z);
+      
+        V1  = -i/hbar*(Vtrap - EnergyOffset);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <noise_vector name="noise" kind="gaussian" method="solirte" type="complex" seed="15687 65687 684320 4057 354">
+    <components>eta</components>
+  </noise_vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <dependencies>noise</dependencies>
+      <![CDATA[
+      
+        if ((abs(r) < 0.9e-5) && abs(z) < 0.9e-4) {
+          phi = eta;
+          // This will be automatically normalised later
+        } else {
+          phi = 0.0;
+        }
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>
+      Ncalc
+    </components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="1e-4" steps="1000">
+      <samples>100</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi *= sqrt(Nparticles/Ncalc);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*hbar/M*(kr*kr + kz*kz);
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] - (i*V1 + Uint/hbar*mod2(phi))*phi;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="hdf5">
+      <sampling_group basis="r z" initial_sample="no">
+        <moments>norm_dens</moments>
+        <dependencies>wavefunction normalisation</dependencies>
+        <![CDATA[
+          norm_dens = mod2(phi)/Ncalc;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/stochastic/bessel_cosine_stochastic_groundstate_expected.h5 b/testsuite/stochastic/bessel_cosine_stochastic_groundstate_expected.h5
new file mode 100644
index 0000000..121de49
Binary files /dev/null and b/testsuite/stochastic/bessel_cosine_stochastic_groundstate_expected.h5 differ
diff --git a/testsuite/stochastic/bessel_cosine_stochastic_groundstate_expected.xsil b/testsuite/stochastic/bessel_cosine_stochastic_groundstate_expected.xsil
new file mode 100644
index 0000000..c362c50
--- /dev/null
+++ b/testsuite/stochastic/bessel_cosine_stochastic_groundstate_expected.xsil
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="bessel_cosine_stochastic_groundstate.xsil" expected="bessel_cosine_stochastic_groundstate_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+  </testing>
+
+  <author>Graham Dennis</author>
+  <name>bessel_cosine_stochastic_groundstate</name>
+  <description>
+    Calculate the 3D ground state of a Rubidium BEC in a harmonic magnetic trap assuming
+    cylindrical symmetry about the z axis and reflection symmetry about z=0.
+    This permits us to use the cylindrical bessel functions to expand the solution transverse
+    to z and a cosine series to expand the solution along z.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <chunked_output size="100KB" />
+    <globals>
+      <![CDATA[
+        const real omegaz = 2*M_PI*20;
+        const real omegarho = 2*M_PI*200;
+        const real hbar = 1.05457148e-34;
+        const real M = 1.409539200000000e-25;
+        const real g = 9.8;
+        const real scatteringLength = 5.57e-9;
+        const real Uint = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+        const real Nparticles = 5.0e5;
+
+        /* offset constants */
+        const real EnergyOffset = pow(15.0*Nparticles*Uint*omegaz*omegarho*omegarho/(8*M_PI), 2.0/5.0)
+                                    * pow(M/2.0, 3.0/5.0);
+
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="r" lattice="32"  domain="(0.0, 1.0e-5)" transform="bessel" />
+      <dimension name="z" lattice="32"  domain="(0.0, 1.0e-4)" transform="dct" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" type="complex">
+    <components>
+      V1
+    </components>
+    <initialisation>
+      <![CDATA[
+        real Vtrap = 0.5*M*(omegarho*omegarho*r*r + omegaz*omegaz*z*z);
+      
+        V1  = -i/hbar*(Vtrap - EnergyOffset);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <noise_vector name="noise" kind="gaussian" method="solirte" type="complex" seed="15687 65687 684320 4057 354">
+    <components>eta</components>
+  </noise_vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <dependencies>noise</dependencies>
+      <![CDATA[
+      
+        if ((abs(r) < 0.9e-5) && abs(z) < 0.9e-4) {
+          phi = eta;
+          // This will be automatically normalised later
+        } else {
+          phi = 0.0;
+        }
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>
+      Ncalc
+    </components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = 2.0*(2.0*M_PI)*mod2(phi);
+        // Factor of two is there due to z axis only covering half the condensate.
+        // Factor of two-pi is there for integration over the angular coordinate.
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="1e-4" steps="1000">
+      <samples>100</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+            phi *= sqrt(Nparticles/Ncalc);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*hbar/M*(kr*kr + kz*kz);
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] - (i*V1 + Uint/hbar*mod2(phi))*phi;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="hdf5">
+      <sampling_group basis="r z" initial_sample="no">
+        <moments>norm_dens</moments>
+        <dependencies>wavefunction normalisation</dependencies>
+        <![CDATA[
+          norm_dens = mod2(phi)/Ncalc;
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t r z norm_dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>100</Dim>
+    <Dim>32</Dim>
+    <Dim>32</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+bessel_cosine_stochastic_groundstate_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/stochastic/double_precision_noise_tests.xmds b/testsuite/stochastic/double_precision_noise_tests.xmds
new file mode 100644
index 0000000..e2603fb
--- /dev/null
+++ b/testsuite/stochastic/double_precision_noise_tests.xmds
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  
+  <testing>
+    <xsil_file name="double_precision_noise_tests.xsil" expected="double_precision_noise_tests_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+  </testing>
+  
+  <name>dsfmt_single_precision</name>
+  <author>Mattias Johnsson</author>
+  <description>
+    Tests double precision uniform, gaussian, poissonian, wiener and 
+    jump noises, using DSFMT, solirte and posix generators. It does this by
+    choosing rates and coefficients such that each type of noise has roughly the 
+    same impact on the evolution.
+
+    Note: Solirte currently can't do uniform, jump or poissonian noises, so 
+    those aren't tested.
+
+    This is not a physically realistic simulation; rather it is just supposed to test
+    that double-precision noises behave the same way in the future.
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <!-- Uniform noise is comparable in magnitude to the others if the
+           inverse volume element is unity
+      -->
+      <dimension name="x" lattice="128"  domain="(-64, 64)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <features>
+    <precision> double </precision> 
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+  </features>
+  
+  <noise_vector name="uniform_noise_dsfmt" dimensions="x" kind="uniform" type="real" method="dsfmt" seed="31 41 59">
+    <components>nu_dsfmt</components>
+  </noise_vector>
+  <noise_vector name="gaussian_noise_dsfmt" dimensions="x" kind="gaussian" type="real" method="dsfmt" seed="26 53 58">
+    <components>ng_dsfmt</components>
+  </noise_vector>
+  <noise_vector name="wiener_noise_dsfmt" dimensions="x" kind="wiener" type="real" method="dsfmt" seed="97 93 23">
+    <components>nw_dsfmt</components>
+  </noise_vector>
+  <noise_vector name="poissonian_noise_dsfmt" dimensions="x" kind="poissonian" type="real" mean="2.0" method="dsfmt" seed="84 62 64 ">
+    <components>np_dsfmt</components>
+  </noise_vector>
+  <noise_vector name="jump_noise_dsfmt" dimensions="x" kind="jump" type="real" mean-rate="2.0" method="dsfmt" seed="33 83 27">
+    <components>nj_dsfmt</components>
+  </noise_vector>
+<!--
+  <noise_vector name="uniform_noise_solirte" dimensions="x" kind="uniform" type="real" method="solirte" seed="31 41 59">
+    <components>nu_solirte</components>
+  </noise_vector>
+-->
+  <noise_vector name="gaussian_noise_solirte" dimensions="x" kind="gaussian" type="real" method="solirte" seed="26 53 58">
+    <components>ng_solirte</components>
+  </noise_vector>
+  <noise_vector name="wiener_noise_solirte" dimensions="x" kind="wiener" type="real" method="solirte" seed="97 93 23">
+    <components>nw_solirte</components>
+  </noise_vector>
+
+  <noise_vector name="uniform_noise_posix" dimensions="x" kind="uniform" type="real" method="posix" seed="31 41 59">
+    <components>nu_posix</components>
+  </noise_vector>
+  <noise_vector name="gaussian_noise_posix" dimensions="x" kind="gaussian" type="real" method="posix" seed="26 53 58">
+    <components>ng_posix</components>
+  </noise_vector>
+  <noise_vector name="wiener_noise_posix" dimensions="x" kind="wiener" type="real" method="posix" seed="97 93 23">
+    <components>nw_posix</components>
+  </noise_vector>
+  <noise_vector name="poissonian_noise_posix" dimensions="x" kind="poissonian" type="real" mean="2.0" method="posix" seed="84 62 64 ">
+    <components>np_posix</components>
+  </noise_vector>
+  <noise_vector name="jump_noise_posix" dimensions="x" kind="jump" type="real" mean-rate="2.0" method="posix" seed="33 83 27">
+    <components>nj_posix</components>
+  </noise_vector>
+
+  <vector name="main" initial_basis="x" type="real">
+    <components> phi1 phi2 phi3 </components>
+    <initialisation>
+      <dependencies>
+         uniform_noise_dsfmt   gaussian_noise_dsfmt   poissonian_noise_dsfmt 
+                               gaussian_noise_solirte 
+         uniform_noise_posix   gaussian_noise_posix   poissonian_noise_posix
+      </dependencies>
+      <![CDATA[
+        phi1 = nu_dsfmt   + ng_dsfmt + np_dsfmt; 
+        phi2 =              ng_solirte; 
+        phi3 = nu_posix   + ng_posix + np_posix; 
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <integrate algorithm="SI" iterations="3" interval="1.0" steps="1000">
+      <samples>25</samples>
+      <operators>
+        <dependencies>
+          jump_noise_dsfmt wiener_noise_dsfmt
+                           wiener_noise_solirte
+          jump_noise_posix wiener_noise_posix
+ </dependencies>
+        <integration_vectors> main </integration_vectors>
+        <![CDATA[
+         dphi1_dt = 1.5 * (nw_dsfmt   + nj_dsfmt  ) * phi1;
+         dphi2_dt = 1.5 * (nw_solirte             ) * phi2;
+         dphi3_dt = 1.5 * (nw_posix   + nj_posix  ) * phi3;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output filename="double_precision_noise_tests.xsil" format="hdf5">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>Phi1 Phi2 Phi3</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          Phi1 = phi1;
+          Phi2 = phi2;
+          Phi3 = phi3;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/stochastic/double_precision_noise_tests_expected.h5 b/testsuite/stochastic/double_precision_noise_tests_expected.h5
new file mode 100644
index 0000000..120453d
Binary files /dev/null and b/testsuite/stochastic/double_precision_noise_tests_expected.h5 differ
diff --git a/testsuite/stochastic/double_precision_noise_tests_expected.xsil b/testsuite/stochastic/double_precision_noise_tests_expected.xsil
new file mode 100644
index 0000000..1c66523
--- /dev/null
+++ b/testsuite/stochastic/double_precision_noise_tests_expected.xsil
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  
+  <testing>
+    <xsil_file name="double_precision_noise_tests.xsil" expected="double_precision_noise_tests_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+  </testing>
+  
+  <name>dsfmt_single_precision</name>
+  <author>Mattias Johnsson</author>
+  <description>
+    Tests double precision uniform, gaussian, poissonian, wiener and 
+    jump noises, using DSFMT, solirte and posix generators. It does this by
+    choosing rates and coefficients such that each type of noise has roughly the 
+    same impact on the evolution.
+
+    Note: Solirte currently can't do uniform, jump or poissonian noises, so 
+    those aren't tested.
+
+    This is not a physically realistic simulation; rather it is just supposed to test
+    that double-precision noises behave the same way in the future.
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <!-- Uniform noise is comparable in magnitude to the others if the
+           inverse volume element is unity
+      -->
+      <dimension name="x" lattice="128"  domain="(-64, 64)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <features>
+    <precision> double </precision> 
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+  </features>
+  
+  <noise_vector name="uniform_noise_dsfmt" dimensions="x" kind="uniform" type="real" method="dsfmt" seed="31 41 59">
+    <components>nu_dsfmt</components>
+  </noise_vector>
+  <noise_vector name="gaussian_noise_dsfmt" dimensions="x" kind="gaussian" type="real" method="dsfmt" seed="26 53 58">
+    <components>ng_dsfmt</components>
+  </noise_vector>
+  <noise_vector name="wiener_noise_dsfmt" dimensions="x" kind="wiener" type="real" method="dsfmt" seed="97 93 23">
+    <components>nw_dsfmt</components>
+  </noise_vector>
+  <noise_vector name="poissonian_noise_dsfmt" dimensions="x" kind="poissonian" type="real" mean="2.0" method="dsfmt" seed="84 62 64 ">
+    <components>np_dsfmt</components>
+  </noise_vector>
+  <noise_vector name="jump_noise_dsfmt" dimensions="x" kind="jump" type="real" mean-rate="2.0" method="dsfmt" seed="33 83 27">
+    <components>nj_dsfmt</components>
+  </noise_vector>
+<!--
+  <noise_vector name="uniform_noise_solirte" dimensions="x" kind="uniform" type="real" method="solirte" seed="31 41 59">
+    <components>nu_solirte</components>
+  </noise_vector>
+-->
+  <noise_vector name="gaussian_noise_solirte" dimensions="x" kind="gaussian" type="real" method="solirte" seed="26 53 58">
+    <components>ng_solirte</components>
+  </noise_vector>
+  <noise_vector name="wiener_noise_solirte" dimensions="x" kind="wiener" type="real" method="solirte" seed="97 93 23">
+    <components>nw_solirte</components>
+  </noise_vector>
+
+  <noise_vector name="uniform_noise_posix" dimensions="x" kind="uniform" type="real" method="posix" seed="31 41 59">
+    <components>nu_posix</components>
+  </noise_vector>
+  <noise_vector name="gaussian_noise_posix" dimensions="x" kind="gaussian" type="real" method="posix" seed="26 53 58">
+    <components>ng_posix</components>
+  </noise_vector>
+  <noise_vector name="wiener_noise_posix" dimensions="x" kind="wiener" type="real" method="posix" seed="97 93 23">
+    <components>nw_posix</components>
+  </noise_vector>
+  <noise_vector name="poissonian_noise_posix" dimensions="x" kind="poissonian" type="real" mean="2.0" method="posix" seed="84 62 64 ">
+    <components>np_posix</components>
+  </noise_vector>
+  <noise_vector name="jump_noise_posix" dimensions="x" kind="jump" type="real" mean-rate="2.0" method="posix" seed="33 83 27">
+    <components>nj_posix</components>
+  </noise_vector>
+
+  <vector name="main" initial_basis="x" type="real">
+    <components> phi1 phi2 phi3 </components>
+    <initialisation>
+      <dependencies>
+         uniform_noise_dsfmt   gaussian_noise_dsfmt   poissonian_noise_dsfmt 
+                               gaussian_noise_solirte 
+         uniform_noise_posix   gaussian_noise_posix   poissonian_noise_posix
+      </dependencies>
+      <![CDATA[
+        phi1 = nu_dsfmt   + ng_dsfmt + np_dsfmt; 
+        phi2 =              ng_solirte; 
+        phi3 = nu_posix   + ng_posix + np_posix; 
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <integrate algorithm="SI" iterations="3" interval="1.0" steps="1000">
+      <samples>25</samples>
+      <operators>
+        <dependencies>
+          jump_noise_dsfmt wiener_noise_dsfmt
+                           wiener_noise_solirte
+          jump_noise_posix wiener_noise_posix
+ </dependencies>
+        <integration_vectors> main </integration_vectors>
+        <![CDATA[
+         dphi1_dt = 1.5 * (nw_dsfmt   + nj_dsfmt  ) * phi1;
+         dphi2_dt = 1.5 * (nw_solirte             ) * phi2;
+         dphi3_dt = 1.5 * (nw_posix   + nj_posix  ) * phi3;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output filename="double_precision_noise_tests.xsil" format="hdf5">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>Phi1 Phi2 Phi3</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          Phi1 = phi1;
+          Phi2 = phi2;
+          Phi3 = phi3;
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t x Phi1 Phi2 Phi3 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>26</Dim>
+    <Dim>128</Dim>
+    <Dim>5</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+double_precision_noise_tests_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/stochastic/dsfmt_single_precision.xmds b/testsuite/stochastic/dsfmt_single_precision.xmds
new file mode 100644
index 0000000..2fc885b
--- /dev/null
+++ b/testsuite/stochastic/dsfmt_single_precision.xmds
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  
+  <testing>
+    <xsil_file name="dsfmt_single_precision.xsil" expected="dsfmt_single_precision_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+  </testing>
+  
+  <name>dsfmt_single_precision</name>
+  <author>Mattias Johnsson</author>
+  <description>
+    Tests single precision, DSFMT-generated, uniform, gaussian, poissonian, wiener and 
+    jump noises in a single script. It does this by choosing rates and coefficients 
+    such that each type of noise has roughly the same impact on the evolution.
+
+    This is not a physically realistic simulation; rather it is just supposed to test
+    that single-precision DSFMT noises behave the same way in the future.
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <!-- Uniform noise is comparable in magnitude to the others if the
+           inverse volume element is unity
+      -->
+      <dimension name="x" lattice="128"  domain="(-64, 64)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <features>
+    <precision> single </precision> 
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+  </features>
+  
+  <noise_vector name="uniform_noise" dimensions="x" kind="uniform" type="real" method="dsfmt" seed="31 41 59">
+    <components>nu</components>
+  </noise_vector>
+
+  <noise_vector name="gaussian_noise" dimensions="x" kind="gaussian" type="real" method="dsfmt" seed="26 53 58">
+    <components>ng</components>
+  </noise_vector>
+
+  <noise_vector name="wiener_noise" dimensions="x" kind="wiener" type="real" method="dsfmt" seed="97 93 23">
+    <components>nw</components>
+  </noise_vector>
+
+  <noise_vector name="poissonian_noise" dimensions="x" kind="poissonian" type="real" mean="2.0" method="dsfmt" seed="84 62 64 ">
+    <components>np</components>
+  </noise_vector>
+
+  <noise_vector name="jump_noise" dimensions="x" kind="jump" type="real" mean-rate="2.0" method="dsfmt" seed="33 83 27">
+    <components>nj</components>
+  </noise_vector>
+
+  <vector name="main" initial_basis="x" type="real">
+    <components> phi </components>
+    <initialisation>
+      <dependencies> uniform_noise gaussian_noise poissonian_noise </dependencies>
+      <![CDATA[
+        phi = nu + ng + np; 
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <integrate algorithm="SI" iterations="3" interval="1.0" steps="1000">
+      <samples>25</samples>
+      <operators>
+        <dependencies> jump_noise wiener_noise </dependencies>
+        <integration_vectors> main </integration_vectors>
+        <![CDATA[
+         dphi_dt = 1.5*(nw + nj)*phi;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output filename="dsfmt_single_precision.xsil" format="hdf5">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>Phi</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          Phi = phi;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/stochastic/dsfmt_single_precision_expected.h5 b/testsuite/stochastic/dsfmt_single_precision_expected.h5
new file mode 100644
index 0000000..efa360a
Binary files /dev/null and b/testsuite/stochastic/dsfmt_single_precision_expected.h5 differ
diff --git a/testsuite/stochastic/dsfmt_single_precision_expected.xsil b/testsuite/stochastic/dsfmt_single_precision_expected.xsil
new file mode 100644
index 0000000..217ba94
--- /dev/null
+++ b/testsuite/stochastic/dsfmt_single_precision_expected.xsil
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  
+  <testing>
+    <xsil_file name="dsfmt_single_precision.xsil" expected="dsfmt_single_precision_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+  </testing>
+  
+  <name>dsfmt_single_precision</name>
+  <author>Mattias Johnsson</author>
+  <description>
+    Tests single precision, DSFMT-generated, uniform, gaussian, poissonian, wiener and 
+    jump noises in a single script. It does this by choosing rates and coefficients 
+    such that each type of noise has roughly the same impact on the evolution.
+
+    This is not a physically realistic simulation; rather it is just supposed to test
+    that single-precision DSFMT noises behave the same way in the future.
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <!-- Uniform noise is comparable in magnitude to the others if the
+           inverse volume element is unity
+      -->
+      <dimension name="x" lattice="128"  domain="(-64, 64)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <features>
+    <precision> single </precision> 
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+  </features>
+  
+  <noise_vector name="uniform_noise" dimensions="x" kind="uniform" type="real" method="dsfmt" seed="31 41 59">
+    <components>nu</components>
+  </noise_vector>
+
+  <noise_vector name="gaussian_noise" dimensions="x" kind="gaussian" type="real" method="dsfmt" seed="26 53 58">
+    <components>ng</components>
+  </noise_vector>
+
+  <noise_vector name="wiener_noise" dimensions="x" kind="wiener" type="real" method="dsfmt" seed="97 93 23">
+    <components>nw</components>
+  </noise_vector>
+
+  <noise_vector name="poissonian_noise" dimensions="x" kind="poissonian" type="real" mean="2.0" method="dsfmt" seed="84 62 64 ">
+    <components>np</components>
+  </noise_vector>
+
+  <noise_vector name="jump_noise" dimensions="x" kind="jump" type="real" mean-rate="2.0" method="dsfmt" seed="33 83 27">
+    <components>nj</components>
+  </noise_vector>
+
+  <vector name="main" initial_basis="x" type="real">
+    <components> phi </components>
+    <initialisation>
+      <dependencies> uniform_noise gaussian_noise poissonian_noise </dependencies>
+      <![CDATA[
+        phi = nu + ng + np; 
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <integrate algorithm="SI" iterations="3" interval="1.0" steps="1000">
+      <samples>25</samples>
+      <operators>
+        <dependencies> jump_noise wiener_noise </dependencies>
+        <integration_vectors> main </integration_vectors>
+        <![CDATA[
+         dphi_dt = 1.5*(nw + nj)*phi;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output filename="dsfmt_single_precision.xsil" format="hdf5">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>Phi</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          Phi = phi;
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t x Phi 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="single">
+    <Dim>26</Dim>
+    <Dim>128</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+dsfmt_single_precision_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/stochastic/fibre.xmds b/testsuite/stochastic/fibre.xmds
new file mode 100644
index 0000000..aca1729
--- /dev/null
+++ b/testsuite/stochastic/fibre.xmds
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="fibre.xsil" expected="fibre_expected.xsil" absolute_tolerance="5e-5" relative_tolerance="1e-3" />
+  </testing>
+  <name>fibre</name>
+  <author>Unknown author</author>
+  <description>
+    Example fibre noise simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="64"  domain="(-5, 5)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <globals>
+      <![CDATA[
+      const real ggamma = 1.0;
+      const real beta = sqrt(4.0*M_PI*ggamma/10.0);
+      ]]>
+    </globals>
+  </features>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>phi</components>
+    <initialisation>
+      <![CDATA[
+        phi = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <noise_vector name="noise" kind="wiener" type="complex" seed="293485">
+    <components>n_1</components>
+  </noise_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="2.5" steps="200000">
+      <samples>50</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*kx*kx;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>noise</dependencies>
+        <![CDATA[
+          dphi_dt = L[phi] - ggamma*phi + beta*n_1;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="kx" initial_sample="yes">
+        <moments>pow_dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          pow_dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/stochastic/fibre_expected.xsil b/testsuite/stochastic/fibre_expected.xsil
new file mode 100644
index 0000000..8ba15e6
--- /dev/null
+++ b/testsuite/stochastic/fibre_expected.xsil
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="fibre.xsil" expected="fibre_expected.xsil" absolute_tolerance="5e-5" relative_tolerance="1e-3" />
+  </testing>
+  <name>fibre</name>
+  <author>Unknown author</author>
+  <description>
+    Example fibre noise simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="64"  domain="(-5, 5)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <!-- <openmp /> -->
+    <stochastic>
+      <noise kind="gaussian" prefix="n" num="2" seed="293485"/>
+      <!-- If there is no seed attribute then seeds will be chosen randomly at run-time -->
+    </stochastic>
+    <globals>
+      <![CDATA[
+      const real ggamma = 1.0;
+      const real beta = sqrt(2.0*M_PI*ggamma/10.0);
+      ]]>
+    </globals>
+  </features>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>phi</components>
+    <initialisation no_noises="true">
+      <![CDATA[
+        phi = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" iterations="3" interval="2.5" steps="200000" tolerance="1e-6">
+      <samples>50</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*kx*kx;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi] - ggamma*phi + beta*complex(n_1, n_2);
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="kx" initial_sample="yes">
+        <moments>pow_dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          pow_dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t kx pow_dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>51</Dim>
+    <Dim>64</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+fibre_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/stochastic/fibre_expected_mg0.dat b/testsuite/stochastic/fibre_expected_mg0.dat
new file mode 100644
index 0000000..67916c7
Binary files /dev/null and b/testsuite/stochastic/fibre_expected_mg0.dat differ
diff --git a/testsuite/stochastic/fibre_with_correlation_function_expected.xsil b/testsuite/stochastic/fibre_with_correlation_function_expected.xsil
new file mode 100644
index 0000000..029047c
--- /dev/null
+++ b/testsuite/stochastic/fibre_with_correlation_function_expected.xsil
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="fibre_with_correlation_function.xsil" expected="fibre_with_correlation_function_expected.xsil" absolute_tolerance="5e-5" relative_tolerance="1e-3" />
+  </testing>
+  <name>fibre_with_correlation_function</name>
+  <author>Unknown author</author>
+  <description>
+    Example fibre noise simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="64"  domain="(-5, 5)" aliases="xp" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <stochastic>
+      <noise kind="gaussian-solirte" prefix="n" num="2" seed="293485"/>
+      <!-- If there is no seed attribute then seeds will be chosen randomly at run-time -->
+    </stochastic>
+    <globals>
+      <![CDATA[
+      const real ggamma = 1.0;
+      const real beta = sqrt(2.0*M_PI*ggamma/10.0);
+      ]]>
+    </globals>
+  </features>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>phi</components>
+    <initialisation no_noises="true">
+      <![CDATA[
+        phi = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="SI" interval="2.5" steps="200000" tolerance="1e-6">
+      <samples>50 1 1</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*kx*kx;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi] - ggamma*phi + beta*complex(n_1, n_2);
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="kx" initial_sample="yes">
+        <moments>pow_dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          pow_dens = mod2(phi);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x xp" initial_sample="no">
+        <moments>g1 g2</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          g1 = abs(conj(phi) * phi(x => xp));
+          g2 = mod2(phi) * mod2(phi(x => xp));
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx kxp" initial_sample="no">
+        <moments>g1 g2 g2minus</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          g1 = abs(conj(phi) * phi(kx => kxp));
+          g2 = mod2(phi) * mod2(phi(kx => kxp));
+          g2minus = mod2(phi) * mod2(phi(kx => -kxp));
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t kx pow_dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>51</Dim>
+    <Dim>64</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+fibre_with_correlation_function_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x xp g1 g2 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>64</Dim>
+    <Dim>64</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+fibre_with_correlation_function_expected_mg1.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_3">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+kx kxp g1 g2 g2minus 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>64</Dim>
+    <Dim>64</Dim>
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+fibre_with_correlation_function_expected_mg2.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/stochastic/fibre_with_correlation_function_expected_mg0.dat b/testsuite/stochastic/fibre_with_correlation_function_expected_mg0.dat
new file mode 100644
index 0000000..ab54c80
Binary files /dev/null and b/testsuite/stochastic/fibre_with_correlation_function_expected_mg0.dat differ
diff --git a/testsuite/stochastic/fibre_with_correlation_function_expected_mg1.dat b/testsuite/stochastic/fibre_with_correlation_function_expected_mg1.dat
new file mode 100644
index 0000000..fc5ac81
Binary files /dev/null and b/testsuite/stochastic/fibre_with_correlation_function_expected_mg1.dat differ
diff --git a/testsuite/stochastic/fibre_with_correlation_function_expected_mg2.dat b/testsuite/stochastic/fibre_with_correlation_function_expected_mg2.dat
new file mode 100644
index 0000000..2c9137d
Binary files /dev/null and b/testsuite/stochastic/fibre_with_correlation_function_expected_mg2.dat differ
diff --git a/testsuite/stochastic/fibre_with_correlation_functions.xmds b/testsuite/stochastic/fibre_with_correlation_functions.xmds
new file mode 100644
index 0000000..cac557f
--- /dev/null
+++ b/testsuite/stochastic/fibre_with_correlation_functions.xmds
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="fibre_with_correlation_function.xsil" expected="fibre_with_correlation_function_expected.xsil" absolute_tolerance="5e-5" relative_tolerance="1e-3" />
+  </testing>
+  <name>fibre_with_correlation_function</name>
+  <author>Unknown author</author>
+  <description>
+    Example fibre noise simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="64"  domain="(-5, 5)" aliases="xp" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <globals>
+      <![CDATA[
+      const real ggamma = 1.0;
+      const real beta = sqrt(4.0*M_PI*ggamma/10.0);
+      ]]>
+    </globals>
+  </features>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>phi</components>
+    <initialisation>
+      <![CDATA[
+        phi = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <noise_vector name="noise" kind="wiener" type="complex" method="solirte" seed="293485">
+    <components>n_1</components>
+  </noise_vector>
+  
+  <sequence>
+    <integrate algorithm="SI" interval="2.5" steps="200000" tolerance="1e-6">
+      <samples>50 1 1</samples>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*kx*kx;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>noise</dependencies>
+        <![CDATA[
+          dphi_dt = L[phi] - ggamma*phi + beta*n_1;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="kx" initial_sample="yes">
+        <moments>pow_dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          pow_dens = mod2(phi);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x xp" initial_sample="no">
+        <moments>g1 g2</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          g1 = abs(conj(phi) * phi(x => xp));
+          g2 = mod2(phi) * mod2(phi(x => xp));
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx kxp" initial_sample="no">
+        <moments>g1 g2 g2minus</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          g1 = abs(conj(phi) * phi(kx => kxp));
+          g2 = mod2(phi) * mod2(phi(kx => kxp));
+          g2minus = mod2(phi) * mod2(phi(kx => -kxp));
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/stochastic/kubo.xmds b/testsuite/stochastic/kubo.xmds
new file mode 100644
index 0000000..fde59cb
--- /dev/null
+++ b/testsuite/stochastic/kubo.xmds
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="kubo.xsil" expected="kubo_expected.xsil" absolute_tolerance="4e-2" relative_tolerance="4e-2" />
+  </testing>
+  
+  <name>kubo</name>
+  <author>Graham Dennis / Michael Hush</author>
+  <description>
+    Example Kubo oscillator simulation 
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <driver name="multi-path" paths="10000" />
+  
+  <vector name="main" type="complex">
+    <components>
+      z
+    </components>
+    <initialisation>
+      <![CDATA[
+        z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <noise_vector name="noise" kind="wiener" type="real" method="solirte">
+    <components>n_1</components>
+  </noise_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="3" steps="1000" tolerance="1e-6">
+      <samples>50 </samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>noise</dependencies>
+        <![CDATA[
+          dz_dt = i*z*n_1;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(z);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/stochastic/kubo_expected.xsil b/testsuite/stochastic/kubo_expected.xsil
new file mode 100644
index 0000000..83f395f
--- /dev/null
+++ b/testsuite/stochastic/kubo_expected.xsil
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="kubo.xsil" expected="kubo_expected.xsil" absolute_tolerance="2e-2" relative_tolerance="2e-2" />
+  </testing>
+  
+  <name>kubo</name>
+  <author>Graham Dennis / Michael Hush</author>
+  <description>
+    Example Kubo oscillator simulation 
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <driver name="multi-path" paths="10000" />
+  
+  <features>
+    <stochastic>
+      <noise kind="gaussian" prefix="n" num="1" seed="1348 234"/>
+      <!-- If there is no seed attribute then seeds will be chosen randomly at run-time -->
+    </stochastic>
+  </features>
+  
+  <vector name="main" type="complex">
+    <components>
+      z
+    </components>
+    <initialisation noises="">
+      <![CDATA[
+        z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="3" steps="1000" tolerance="1e-6">
+      <samples>50 </samples>
+      <operators noises="n">
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dz_dt = i*z*n_1;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(z);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t mean_zR mean_zI stderr_zR stderr_zI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>51</Dim>
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+kubo_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/stochastic/kubo_expected_mg0.dat b/testsuite/stochastic/kubo_expected_mg0.dat
new file mode 100644
index 0000000..c002b34
Binary files /dev/null and b/testsuite/stochastic/kubo_expected_mg0.dat differ
diff --git a/testsuite/stochastic/kubo_fixedstep.xmds b/testsuite/stochastic/kubo_fixedstep.xmds
new file mode 100644
index 0000000..d0b85d1
--- /dev/null
+++ b/testsuite/stochastic/kubo_fixedstep.xmds
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="kubo_fixedstep.xsil" expected="kubo_fixedstep_expected.xsil" absolute_tolerance="5e-2" relative_tolerance="1e-1" />
+  </testing>
+  
+  <name>kubo_fixedstep</name>
+  <author>Graham Dennis / Michael Hush</author>
+  <description>
+    Example Kubo oscillator simulation 
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <driver name="multi-path" paths="1000" />
+  
+  <vector name="main" type="complex">
+    <components>
+      z
+    </components>
+    <initialisation>
+      <![CDATA[
+        z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <noise_vector name="noise" kind="wiener" type="real" seed="157 9348 234">
+    <components>n_1</components>
+  </noise_vector>
+  
+  <sequence>
+    <integrate algorithm="RK9" interval="10" steps="10000">
+      <samples>500 </samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>noise</dependencies>
+        <![CDATA[
+          dz_dt = i*z*n_1;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(z);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/stochastic/kubo_fixedstep_expected.xsil b/testsuite/stochastic/kubo_fixedstep_expected.xsil
new file mode 100644
index 0000000..59e58f2
--- /dev/null
+++ b/testsuite/stochastic/kubo_fixedstep_expected.xsil
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="kubo_fixedstep.xsil" expected="kubo_fixedstep_expected.xsil" absolute_tolerance="5e-2" relative_tolerance="1e-1" />
+  </testing>
+  
+  <name>kubo_fixedstep</name>
+  <author>Graham Dennis / Michael Hush</author>
+  <description>
+    Example Kubo oscillator simulation 
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+  
+  <driver name="multi-path" paths="1000" />
+  
+  <features>
+    <benchmark />
+    <bing />
+    <stochastic>
+      <noise kind="gaussian" prefix="n" num="1" seed="157 9348 234"/>
+      <!-- If there is no seed attribute then seeds will be chosen randomly at run-time -->
+    </stochastic>
+  </features>
+  
+  <vector name="main" type="complex">
+    <components>
+      z
+    </components>
+    <initialisation noises="">
+      <![CDATA[
+        z = 1.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK9" interval="10" steps="10000">
+      <samples>500 </samples>
+      <operators noises="n">
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dz_dt = i*z*n_1;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <moments>zR zI</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          _SAMPLE_COMPLEX(z);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t mean_zR mean_zI stderr_zR stderr_zI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>501</Dim>
+    <Dim>5</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+kubo_fixedstep_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/stochastic/kubo_fixedstep_expected_mg0.dat b/testsuite/stochastic/kubo_fixedstep_expected_mg0.dat
new file mode 100644
index 0000000..10c0f7d
Binary files /dev/null and b/testsuite/stochastic/kubo_fixedstep_expected_mg0.dat differ
diff --git a/testsuite/stochastic/photodetector.xmds b/testsuite/stochastic/photodetector.xmds
new file mode 100644
index 0000000..eac5b97
--- /dev/null
+++ b/testsuite/stochastic/photodetector.xmds
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="photodetector.xsil" expected="photodetector_expected.xsil" absolute_tolerance="4e-5" relative_tolerance="4e-5" />
+  </testing>
+
+  <name>photodetector</name>
+  <author>Graham Dennis</author>
+  <description>
+    Example poissonian noise simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+
+  <noise_vector name="noises" kind="jump" mean-rate="5.0" type="real" method="posix" seed="314 159 276">
+        <components>nn</components>
+  </noise_vector>
+  
+  <vector name="main" type="real">
+    <components> N </components>
+    <initialisation>
+      <![CDATA[
+        N = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="10" steps="1000">
+      <samples>1000</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>noises</dependencies>
+        <![CDATA[
+          dN_dt = nn;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="hdf5" filename="photodetector.xsil">
+      <sampling_group initial_sample="yes">
+        <moments>Ndet</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          Ndet = N;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/stochastic/photodetector_bessel.xmds b/testsuite/stochastic/photodetector_bessel.xmds
new file mode 100644
index 0000000..21a5dad
--- /dev/null
+++ b/testsuite/stochastic/photodetector_bessel.xmds
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="photodetector_bessel.xsil" expected="photodetector_bessel_expected.xsil" absolute_tolerance="4e-5" relative_tolerance="4e-5" />
+  </testing>
+
+  <name>photodetector_bessel</name>
+  <author>Graham Dennis</author>
+  <description>
+    Example poissonian noise simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+        <dimension name="x" domain="(0, 1)" lattice="100" transform="bessel" volume_prefactor="2.0*M_PI" />
+    </transverse_dimensions>
+  </geometry>
+
+  <noise_vector name="noises" kind="jump" mean-rate="10.0" type="real" method="posix" seed="314 159 276">
+      <!-- A mean rate of 10 per volume. This means that over 10 time units and an area of pi * 1^2, we expect 314.15... 
+           total events on average -->
+        <components>nn</components>
+  </noise_vector>
+  
+  <vector name="main" type="real">
+    <components> rho </components>
+    <initialisation>
+      <![CDATA[
+        rho = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="10" steps="1000">
+      <samples>1000 100</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>noises</dependencies>
+        <![CDATA[
+          drho_dt = nn;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="hdf5" filename="photodetector_bessel.xsil">
+      <sampling_group basis="x(0)" initial_sample="yes">
+        <moments>Ndet</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          Ndet = rho;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = rho;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/stochastic/photodetector_bessel_expected.h5 b/testsuite/stochastic/photodetector_bessel_expected.h5
new file mode 100644
index 0000000..dba9dbd
Binary files /dev/null and b/testsuite/stochastic/photodetector_bessel_expected.h5 differ
diff --git a/testsuite/stochastic/photodetector_bessel_expected.xsil b/testsuite/stochastic/photodetector_bessel_expected.xsil
new file mode 100644
index 0000000..a8baa7b
--- /dev/null
+++ b/testsuite/stochastic/photodetector_bessel_expected.xsil
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="photodetector_bessel.xsil" expected="photodetector_bessel_expected.xsil" absolute_tolerance="4e-5" relative_tolerance="4e-5" />
+  </testing>
+
+  <name>photodetector_bessel</name>
+  <author>Graham Dennis</author>
+  <description>
+    Example poissonian noise simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+        <dimension name="x" domain="(0, 1)" lattice="100" transform="bessel" volume_prefactor="2.0*M_PI" />
+    </transverse_dimensions>
+  </geometry>
+
+  <noise_vector name="noises" kind="jump" mean-rate="10.0" type="real" method="posix" seed="314 159 276">
+      <!-- A mean rate of 10 per volume. This means that over 10 time units and an area of pi * 1^2, we expect 314.15... 
+           total events on average -->
+        <components>nn</components>
+  </noise_vector>
+  
+  <vector name="main" type="real">
+    <components> rho </components>
+    <initialisation>
+      <![CDATA[
+        rho = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="10" steps="1000">
+      <samples>1000 100</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>noises</dependencies>
+        <![CDATA[
+          drho_dt = nn;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="hdf5" filename="photodetector_bessel.xsil">
+      <sampling_group basis="x(0)" initial_sample="yes">
+        <moments>Ndet</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          Ndet = rho;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = rho;
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t Ndet 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>1001</Dim>
+    <Dim>2</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+photodetector_bessel_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t x dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>101</Dim>
+    <Dim>100</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/2"/>
+photodetector_bessel_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/stochastic/photodetector_expected.h5 b/testsuite/stochastic/photodetector_expected.h5
new file mode 100644
index 0000000..d677880
Binary files /dev/null and b/testsuite/stochastic/photodetector_expected.h5 differ
diff --git a/testsuite/stochastic/photodetector_expected.xsil b/testsuite/stochastic/photodetector_expected.xsil
new file mode 100644
index 0000000..4117aa3
--- /dev/null
+++ b/testsuite/stochastic/photodetector_expected.xsil
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="photodetector.xsil" expected="photodetector_expected.xsil" absolute_tolerance="4e-5" relative_tolerance="4e-5" />
+  </testing>
+
+  <name>photodetector</name>
+  <author>Graham Dennis</author>
+  <description>
+    Example poissonian noise simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+  </geometry>
+
+  <noise_vector name="noises" kind="jump" mean-rate="5.0" type="real" method="posix" seed="314 159 276">
+        <components>nn</components>
+  </noise_vector>
+  
+  <vector name="main" type="real">
+    <components> N </components>
+    <initialisation>
+      <![CDATA[
+        N = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="10" steps="1000">
+      <samples>1000</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>noises</dependencies>
+        <![CDATA[
+          dN_dt = nn;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="hdf5" filename="photodetector.xsil">
+      <sampling_group initial_sample="yes">
+        <moments>Ndet</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          Ndet = N;
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t Ndet 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>1001</Dim>
+    <Dim>2</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+photodetector_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/stochastic/photodetector_linear.xmds b/testsuite/stochastic/photodetector_linear.xmds
new file mode 100644
index 0000000..250780b
--- /dev/null
+++ b/testsuite/stochastic/photodetector_linear.xmds
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="photodetector_linear.xsil" expected="photodetector_linear_expected.xsil" absolute_tolerance="4e-5" relative_tolerance="4e-5" />
+  </testing>
+
+  <name>photodetector_linear</name>
+  <author>Graham Dennis</author>
+  <description>
+    Example poissonian noise simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+        <dimension name="x" domain="(-1, 1)" lattice="100" />
+    </transverse_dimensions>
+  </geometry>
+
+  <noise_vector name="noises" kind="jump" mean-rate="5.0" type="real" method="posix" seed="314 159 276">
+        <components>nn</components>
+  </noise_vector>
+  
+  <vector name="main" type="real">
+    <components> rho </components>
+    <initialisation>
+      <![CDATA[
+        rho = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="10" steps="1000">
+      <samples>1000 100</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>noises</dependencies>
+        <![CDATA[
+          drho_dt = nn;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="hdf5" filename="photodetector_linear.xsil">
+      <sampling_group basis="x(0)" initial_sample="yes">
+        <moments>Ndet</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          Ndet = rho;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = rho;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/stochastic/photodetector_linear_expected.h5 b/testsuite/stochastic/photodetector_linear_expected.h5
new file mode 100644
index 0000000..2e532cf
Binary files /dev/null and b/testsuite/stochastic/photodetector_linear_expected.h5 differ
diff --git a/testsuite/stochastic/photodetector_linear_expected.xsil b/testsuite/stochastic/photodetector_linear_expected.xsil
new file mode 100644
index 0000000..b1acb19
--- /dev/null
+++ b/testsuite/stochastic/photodetector_linear_expected.xsil
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="photodetector_linear.xsil" expected="photodetector_linear_expected.xsil" absolute_tolerance="4e-5" relative_tolerance="4e-5" />
+  </testing>
+
+  <name>photodetector_linear</name>
+  <author>Graham Dennis</author>
+  <description>
+    Example poissonian noise simulation
+  </description>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+        <dimension name="x" domain="(-1, 1)" lattice="100" />
+    </transverse_dimensions>
+  </geometry>
+
+  <noise_vector name="noises" kind="jump" mean-rate="5.0" type="real" method="posix" seed="314 159 276">
+        <components>nn</components>
+  </noise_vector>
+  
+  <vector name="main" type="real">
+    <components> rho </components>
+    <initialisation>
+      <![CDATA[
+        rho = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="10" steps="1000">
+      <samples>1000 100</samples>
+      <operators>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>noises</dependencies>
+        <![CDATA[
+          drho_dt = nn;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="hdf5" filename="photodetector_linear.xsil">
+      <sampling_group basis="x(0)" initial_sample="yes">
+        <moments>Ndet</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          Ndet = rho;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = rho;
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t Ndet 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>1001</Dim>
+    <Dim>2</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+photodetector_linear_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t x dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>101</Dim>
+    <Dim>100</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/2"/>
+photodetector_linear_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/stochastic/wigner_cool_HO.xmds b/testsuite/stochastic/wigner_cool_HO.xmds
new file mode 100644
index 0000000..d08aca4
--- /dev/null
+++ b/testsuite/stochastic/wigner_cool_HO.xmds
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="wigner_cool_HO.xsil" expected="wigner_cool_HO_expected.xsil" absolute_tolerance="5e-2" relative_tolerance="1e-1" />
+  </testing>
+  <name>wigner_cool_HO</name>
+  <author>Michael Hush</author>
+  <description>
+    Single particle in a harmonic oscillator under God control (no realistic measurement has been taken into account), such that energy is reduced. Simulated using a stochastic unravelling from the wigner representation.  
+  </description>
+  
+  <features>
+    <fftw plan="patient"/>
+    <globals>
+      <![CDATA[
+      
+        const real feedp = -1.35;
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" type="integer" domain="(1, 10000)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <noise_vector name="noise" kind="gaussian" type="complex" seed="157 9348 234">
+    <components>n_1</components>
+  </noise_vector>
+  
+  <vector type="real" name="variables" dimensions="j">
+    <components> x p </components>
+    <initialisation>
+      <dependencies>noise</dependencies>
+      <![CDATA[
+      
+        //Coherent state initialisation
+        
+        real x0 = sqrt(10.0);
+        real p0 = sqrt(10.0);
+      
+        x = x0 + Re(n_1);
+        p = p0 + Im(n_1);
+         
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector type="real" name="observables_evo" dimensions="">
+    <components>avg_x_evo avg_p_evo avg_pp_evo</components>
+    <evaluation>
+    <dependencies>variables</dependencies>
+    <![CDATA[
+      avg_p_evo = p/_lattice_j;  
+    ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <computed_vector type="real" name="observables" dimensions="">
+    <components>avg_x avg_p avg_E avg_EE avg_exx avg_epp avg_eEE avg_eEEEE</components>
+    <evaluation>
+    <dependencies>variables</dependencies>
+    <![CDATA[
+      
+      avg_x = x/_lattice_j;
+      avg_p = p/_lattice_j;
+      avg_E = 0.5*(x*x+p*p)/_lattice_j;
+      avg_EE = pow(0.5*(x*x+p*p),2)/_lattice_j;
+      
+      //Error calculation
+      avg_exx = avg_x*avg_x*_lattice_j;
+      avg_epp = avg_p*avg_p*_lattice_j;
+      avg_eEE = avg_E*avg_E*_lattice_j;
+      avg_eEEEE = avg_EE*avg_EE*_lattice_j;
+       
+    ]]>
+    </evaluation>
+  </computed_vector>
+  
+  
+  <sequence>
+  
+    <integrate algorithm="SI" tolerance="1e-8" interval="10" steps="1000">
+      <samples>50</samples>
+      
+      <operators>
+        <integration_vectors>variables</integration_vectors>
+        <dependencies>observables_evo</dependencies>
+        <![CDATA[
+        
+          dx_dt = p; 
+          dp_dt = -x + feedp*avg_p_evo;
+          
+        ]]>
+      </operators>
+    </integrate>
+    
+  </sequence>
+  <output format="binary">
+  
+      <sampling_group initial_sample="yes">
+        <moments>P X E EE P_err X_err E_err EE_err</moments>
+        <dependencies>observables</dependencies>
+        <![CDATA[
+          
+          P = avg_p;
+          X = avg_x;
+          E = avg_E;
+          EE = avg_EE;
+          
+          //errors
+          X_err = sqrt(avg_exx - avg_x*avg_x)/sqrt(_lattice_j);
+          P_err = sqrt(avg_epp - avg_p*avg_p)/sqrt(_lattice_j);
+          E_err = sqrt(avg_eEE - avg_E*avg_E)/sqrt(_lattice_j);
+          EE_err = sqrt(avg_eEEEE - avg_EE*avg_EE)/sqrt(_lattice_j);
+          
+        ]]>
+      </sampling_group>
+    
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/stochastic/wigner_cool_HO_expected.xsil b/testsuite/stochastic/wigner_cool_HO_expected.xsil
new file mode 100644
index 0000000..5f36a92
--- /dev/null
+++ b/testsuite/stochastic/wigner_cool_HO_expected.xsil
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="wigner_cool_HO.xsil" expected="wigner_cool_HO_expected.xsil" absolute_tolerance="5e-2" relative_tolerance="1e-1" />
+  </testing>
+  <name>wigner_cool_HO</name>
+  <author>Michael Hush</author>
+  <description>
+    Single particle in a harmonic oscillator under God control (no realistic measurement has been taken into account), such that energy is reduced. Simulated using a stochastic unravelling from the wigner representation.  
+  </description>
+  
+  <features>
+    <benchmark />
+    <fftw plan="patient"/>
+    <stochastic>
+      <noise kind="gaussian" prefix="n" num="2" seed="157 9348 234"/>
+    </stochastic>
+    <globals>
+      <![CDATA[
+      
+        const real feedp = -1.35;
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="j" type="integer" domain="(1, 10000)" />
+    </transverse_dimensions>
+  </geometry>
+    
+  <vector type="real" name="variables" dimensions="j">
+    <components> x p </components>
+    <initialisation>
+      <![CDATA[
+      
+        //Coherent state initialisation
+        
+        real x0 = sqrt(10.0);
+        real p0 = sqrt(10.0);
+        real sigma0 = sqrt(0.5);
+      
+        x = x0 + n_1*sigma0;
+        p = p0 + n_2*sigma0;
+         
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector type="real" name="observables_evo" dimensions="">
+    <components>avg_x_evo avg_p_evo avg_pp_evo</components>
+    <evaluation noises="">
+    <dependencies>variables</dependencies>
+    <![CDATA[
+      avg_p_evo = p/_lattice_j;  
+    ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <computed_vector type="real" name="observables" dimensions="">
+    <components>avg_x avg_p avg_E avg_EE avg_exx avg_epp avg_eEE avg_eEEEE</components>
+    <evaluation noises="">
+    <dependencies>variables</dependencies>
+    <![CDATA[
+      
+      avg_x = x/_lattice_j;
+      avg_p = p/_lattice_j;
+      avg_E = 0.5*(x*x+p*p)/_lattice_j;
+      avg_EE = pow(0.5*(x*x+p*p),2)/_lattice_j;
+      
+      //Error calculation
+      avg_exx = avg_x*avg_x*_lattice_j;
+      avg_epp = avg_p*avg_p*_lattice_j;
+      avg_eEE = avg_E*avg_E*_lattice_j;
+      avg_eEEEE = avg_EE*avg_EE*_lattice_j;
+       
+    ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+  
+    <integrate algorithm="SI" tolerance="1e-8" interval="10" steps="1000">
+      <samples>50</samples>
+      
+      <operators>
+        <integration_vectors>variables</integration_vectors>
+        <dependencies>observables_evo</dependencies>
+        <![CDATA[
+        
+          dx_dt = p; 
+          dp_dt = -x + feedp*avg_p_evo;
+          
+        ]]>
+      </operators>
+    </integrate>
+    
+  </sequence>
+  <output format="binary">
+  
+      <sampling_group initial_sample="yes">
+        <moments>P X E EE P_err X_err E_err EE_err</moments>
+        <dependencies>observables</dependencies>
+        <![CDATA[
+          
+          P = avg_p;
+          X = avg_x;
+          E = avg_E;
+          EE = avg_EE;
+          
+          //errors
+          X_err = sqrt(avg_exx - avg_x*avg_x)/sqrt(_lattice_j);
+          P_err = sqrt(avg_epp - avg_p*avg_p)/sqrt(_lattice_j);
+          E_err = sqrt(avg_eEE - avg_E*avg_E)/sqrt(_lattice_j);
+          EE_err = sqrt(avg_eEEEE - avg_EE*avg_EE)/sqrt(_lattice_j);
+          
+        ]]>
+      </sampling_group>
+    
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>9</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t P X E EE P_err X_err E_err EE_err 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>51</Dim>
+    <Dim>9</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+wigner_cool_HO_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/stochastic/wigner_cool_HO_expected_mg0.dat b/testsuite/stochastic/wigner_cool_HO_expected_mg0.dat
new file mode 100644
index 0000000..0028c2a
Binary files /dev/null and b/testsuite/stochastic/wigner_cool_HO_expected_mg0.dat differ
diff --git a/testsuite/transforms/bessel_transform.xmds b/testsuite/transforms/bessel_transform.xmds
new file mode 100644
index 0000000..615bfa3
--- /dev/null
+++ b/testsuite/transforms/bessel_transform.xmds
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="bessel_transform.xsil" expected="bessel_transform_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>bessel_transform</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the wave equation on a disk of radius 1 utilising cylindrical symmetry
+    by using the Bessel function transform. The Bessel function transform implicitly
+    assumes Dirichlet boundary conditions at the edge of the disk.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" transform="bessel" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.25)*(x-0.25));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-6" interval="8e-3" steps="400">
+      <samples>100 100</samples>
+      <operators>
+        <operator kind="ex" constant="yes" basis="kx">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx" initial_sample="no">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/transforms/bessel_transform_expected.xsil b/testsuite/transforms/bessel_transform_expected.xsil
new file mode 100644
index 0000000..cf9a981
--- /dev/null
+++ b/testsuite/transforms/bessel_transform_expected.xsil
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="bessel_transform.xsil" expected="bessel_transform_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>bessel_transform</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the wave equation on a disk of radius 1 utilising cylindrical symmetry
+    by using the Bessel function transform. The Bessel function transform implicitly
+    assumes Dirichlet boundary conditions at the edge of the disk.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <mmt />
+    <globals>
+      <![CDATA[
+      const double T = 10.0;
+      const double mass = 1e-3;
+      const double length = 1.0;
+      const double mu = mass/length;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100"  domain="(0, 1)" transform="bessel" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.25)*(x-0.25));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-6" interval="8e-3" steps="400">
+      <samples>100 100</samples>
+      <operators>
+        <operator kind="ex" constant="yes" fourier_space="kx">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <dimension name="x" fourier_space="no" />
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u;
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="no">
+        <dimension name="x" fourier_space="yes" />
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.re;
+        
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t x amp 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>101</Dim>
+    <Dim>100</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="BigEndian"/>
+bessel_transform_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t kx amp 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>100</Dim>
+    <Dim>100</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="BigEndian"/>
+bessel_transform_expected_mg1.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/transforms/bessel_transform_expected_mg0.dat b/testsuite/transforms/bessel_transform_expected_mg0.dat
new file mode 100644
index 0000000..f7d4173
Binary files /dev/null and b/testsuite/transforms/bessel_transform_expected_mg0.dat differ
diff --git a/testsuite/transforms/bessel_transform_expected_mg1.dat b/testsuite/transforms/bessel_transform_expected_mg1.dat
new file mode 100644
index 0000000..d9cd4d9
Binary files /dev/null and b/testsuite/transforms/bessel_transform_expected_mg1.dat differ
diff --git a/testsuite/transforms/bessel_transform_rectangular.xmds b/testsuite/transforms/bessel_transform_rectangular.xmds
new file mode 100644
index 0000000..a00f37c
--- /dev/null
+++ b/testsuite/transforms/bessel_transform_rectangular.xmds
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="bessel_transform_rectangular.xsil" expected="bessel_transform_rectangular_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>bessel_transform_rectangular</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the wave equation on a disk of radius 1 utilising cylindrical symmetry
+    by using the Bessel function transform. The Bessel function transform implicitly
+    assumes Dirichlet boundary conditions at the edge of the disk.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100" spectral_lattice="50" domain="(0, 1)" transform="bessel" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.25)*(x-0.25));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-6" interval="8e-3">
+      <samples>100 73</samples>
+      <operators>
+        <operator kind="ex" constant="yes" basis="kx">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx" initial_sample="no">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/transforms/bessel_transform_rectangular_expected.xsil b/testsuite/transforms/bessel_transform_rectangular_expected.xsil
new file mode 100644
index 0000000..a9e7672
--- /dev/null
+++ b/testsuite/transforms/bessel_transform_rectangular_expected.xsil
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="bessel_transform_rectangular.xsil" expected="bessel_transform_rectangular_expected.xsil" absolute_tolerance="1e-6" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>bessel_transform_rectangular</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the wave equation on a disk of radius 1 utilising cylindrical symmetry
+    by using the Bessel function transform. The Bessel function transform implicitly
+    assumes Dirichlet boundary conditions at the edge of the disk.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="100" spectral_lattice="50" domain="(0, 1)" transform="bessel" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.25)*(x-0.25));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-6" interval="8e-3">
+      <samples>100 73</samples>
+      <operators>
+        <operator kind="ex" constant="yes" fourier_space="kx">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <dimension name="x" fourier_space="no" />
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="no">
+        <dimension name="x" fourier_space="yes" />
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u.Re();
+        
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t x amp 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>101</Dim>
+    <Dim>100</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+bessel_transform_rectangular_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t kx amp 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>73</Dim>
+    <Dim>50</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+bessel_transform_rectangular_expected_mg1.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/transforms/bessel_transform_rectangular_expected_mg0.dat b/testsuite/transforms/bessel_transform_rectangular_expected_mg0.dat
new file mode 100644
index 0000000..56304a0
Binary files /dev/null and b/testsuite/transforms/bessel_transform_rectangular_expected_mg0.dat differ
diff --git a/testsuite/transforms/bessel_transform_rectangular_expected_mg1.dat b/testsuite/transforms/bessel_transform_rectangular_expected_mg1.dat
new file mode 100644
index 0000000..832b729
Binary files /dev/null and b/testsuite/transforms/bessel_transform_rectangular_expected_mg1.dat differ
diff --git a/testsuite/transforms/diffusion_bessel.xmds b/testsuite/transforms/diffusion_bessel.xmds
new file mode 100644
index 0000000..05d11f6
--- /dev/null
+++ b/testsuite/transforms/diffusion_bessel.xmds
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="diffusion_bessel.xsil" expected="diffusion_bessel_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>diffusion_bessel</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion solved using a Discrete Sine Transform (odd boundary conditions at both ends)
+    Odd boundary conditions essentially mimics zero dirichlet boundary conditions for linear problems.
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw plan="exhaustive" />
+    <validation kind="run-time"/>
+    <arguments>
+      <argument name="latticesize" type="integer" default_value="70"/>
+    </arguments>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(0.0, 1.0)" transform="bessel" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="y" type="real">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-3*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="20.0" steps="2400" tolerance="1e-5">
+      <samples>48</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="ky">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="y(32)" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/transforms/diffusion_bessel_expected.xsil b/testsuite/transforms/diffusion_bessel_expected.xsil
new file mode 100644
index 0000000..72bfd37
--- /dev/null
+++ b/testsuite/transforms/diffusion_bessel_expected.xsil
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="diffusion_bessel.xsil" expected="diffusion_bessel_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>diffusion_bessel</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion solved using a Discrete Sine Transform (odd boundary conditions at both ends)
+    Odd boundary conditions essentially mimics zero dirichlet boundary conditions for linear problems.
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw plan="exhaustive" />
+    <openmp />
+    <validation kind="run-time"/>
+    <arguments>
+      <argument name="latticesize" type="integer" default_value="70"/>
+    </arguments>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(0.0, 1.0)" transform="bessel" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="y" type="real">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-3*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="20.0" steps="2400" tolerance="1e-5">
+      <samples>48</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="ky">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="y(32)" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+
+Variables that can be specified on the command line:
+  Command line argument latticesize = 70
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t y dens error_dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>49</Dim>
+    <Dim>32</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint64" precision="double" Type="Remote" Encoding="LittleEndian"/>
+diffusion_bessel_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/transforms/diffusion_bessel_expected_mg0.dat b/testsuite/transforms/diffusion_bessel_expected_mg0.dat
new file mode 100644
index 0000000..c207818
Binary files /dev/null and b/testsuite/transforms/diffusion_bessel_expected_mg0.dat differ
diff --git a/testsuite/transforms/diffusion_dst.xmds b/testsuite/transforms/diffusion_dst.xmds
new file mode 100644
index 0000000..970659e
--- /dev/null
+++ b/testsuite/transforms/diffusion_dst.xmds
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="diffusion_dst.xsil" expected="diffusion_dst_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>diffusion_dst</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion solved using a Discrete Sine Transform (odd boundary conditions at both ends)
+    Odd boundary conditions essentially mimics zero dirichlet boundary conditions for linear problems.
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw plan="exhaustive" />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" transform="dst" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="y" type="real">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-3*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="20.0" steps="2400" tolerance="1e-5">
+      <samples>48</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="ky">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group basis="y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/transforms/diffusion_dst_expected.xsil b/testsuite/transforms/diffusion_dst_expected.xsil
new file mode 100644
index 0000000..f276899
--- /dev/null
+++ b/testsuite/transforms/diffusion_dst_expected.xsil
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="diffusion_dst.xsil" expected="diffusion_dst_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>diffusion_dst</name>
+  <author>Graham Dennis</author>
+  <description>
+    Simple one-dimensional diffusion solved using a Discrete Sine Transform (odd boundary conditions at both ends)
+    Odd boundary conditions essentially mimics zero dirichlet boundary conditions for linear problems.
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw plan="exhaustive" />
+    <openmp />
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="y" lattice="128" domain="(-1.0, 1.0)" transform="dst" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="y" type="double">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+        phi = exp(-3*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" interval="20.0" steps="2400" tolerance="1e-5">
+      <samples>48</samples>
+      <operators>
+        <operator kind="ip" constant="yes" fourier_space="ky">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -0.02*ky*ky;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dphi_dt = L[phi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <!-- Any dimension not mentioned is assumed to be in real space and its middle element will be sampled -->
+        <!-- Note that dimensions can be in any order. Not that I can think of a reason why you would want to do that -->
+        <dimension name="y" lattice="128" fourier_space="y" />
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(phi);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t y dens error_dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>49</Dim>
+    <Dim>128</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+diffusion_dst_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/transforms/diffusion_dst_expected_mg0.dat b/testsuite/transforms/diffusion_dst_expected_mg0.dat
new file mode 100644
index 0000000..8f4fdac
Binary files /dev/null and b/testsuite/transforms/diffusion_dst_expected_mg0.dat differ
diff --git a/testsuite/transforms/disc.xmds b/testsuite/transforms/disc.xmds
new file mode 100644
index 0000000..6b4a9c6
--- /dev/null
+++ b/testsuite/transforms/disc.xmds
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="disc.xsil" expected="disc_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+    <xsil_file name="disc_coordinate_space1.xsil" expected="disc_coordinate_space1_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+    <xsil_file name="disc_spectral_space.xsil" expected="disc_spectral_space_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+    <xsil_file name="disc_coordinate_space2.xsil" expected="disc_coordinate_space_expected.xsil" absolute_tolerance="1e-3" relative_tolerance="1e-3" />
+  </testing>
+  
+  <name>disc</name>
+
+  <author>Mattias Johnsson</author>
+  <description>
+    Calculate the volume of unit ball using spherical bessel transform
+  </description>
+
+  <geometry>
+      <propagation_dimension> t </propagation_dimension>
+      <transverse_dimensions>
+        <dimension name="r" lattice="256"  domain="(0, 1.5)" transform="bessel" volume_prefactor="2.0*M_PI"/>
+      </transverse_dimensions>
+   </geometry>
+
+  <vector name="densityvector" type="real" dimensions="r">
+    <components> rho </components>
+    <initialisation>
+      <![CDATA[
+        if (r<=1.0)
+          rho = 1.0;
+        else
+          rho = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <breakpoint filename="disc_coordinate_space1.xsil">
+      <dependencies>densityvector</dependencies>
+    </breakpoint>
+    <breakpoint filename="disc_spectral_space.xsil">
+      <dependencies basis="kr">densityvector</dependencies>
+    </breakpoint>
+    <breakpoint filename="disc_coordinate_space2.xsil">
+      <dependencies>densityvector</dependencies>
+    </breakpoint>
+  </sequence>
+
+  <output>
+    <sampling_group basis="r(0)" initial_sample="yes">
+      <moments> volume </moments>
+      <dependencies>densityvector</dependencies>
+      <![CDATA[
+        volume = rho / (M_PI) ;// This should be close to 1.
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
+
diff --git a/testsuite/transforms/disc_coordinate_space1_expected.h5 b/testsuite/transforms/disc_coordinate_space1_expected.h5
new file mode 100644
index 0000000..9adb832
Binary files /dev/null and b/testsuite/transforms/disc_coordinate_space1_expected.h5 differ
diff --git a/testsuite/transforms/disc_coordinate_space1_expected.xsil b/testsuite/transforms/disc_coordinate_space1_expected.xsil
new file mode 100644
index 0000000..eb90108
--- /dev/null
+++ b/testsuite/transforms/disc_coordinate_space1_expected.xsil
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="disc.xsil" expected="disc_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+    <xsil_file name="disc_coordinate_space1.xsil" expected="disc_coordinate_space1_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+    <xsil_file name="disc_spectral_space.xsil" expected="disc_spectral_space_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+    <xsil_file name="disc_coordinate_space2.xsil" expected="disc_coordinate_space_expected.xsil" absolute_tolerance="1e-3" relative_tolerance="1e-3" />
+  </testing>
+  
+  <name>disc</name>
+
+  <author>Mattias Johnsson</author>
+  <description>
+    Calculate the volume of unit ball using spherical bessel transform
+  </description>
+
+  <geometry>
+      <propagation_dimension> t </propagation_dimension>
+      <transverse_dimensions>
+        <dimension name="r" lattice="256"  domain="(0, 1.5)" transform="bessel" volume_prefactor="4.0*M_PI"/>
+      </transverse_dimensions>
+   </geometry>
+
+  <vector name="densityvector" type="real" dimensions="r">
+    <components> rho </components>
+    <initialisation>
+      <![CDATA[
+        if (r<=1.0)
+          rho = 1.0;
+        else
+          rho = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <breakpoint filename="disc_coordinate_space1.xsil">
+      <dependencies>densityvector</dependencies>
+    </breakpoint>
+    <breakpoint filename="disc_spectral_space.xsil">
+      <dependencies basis="kr">densityvector</dependencies>
+    </breakpoint>
+    <breakpoint filename="disc_coordinate_space2.xsil">
+      <dependencies>densityvector</dependencies>
+    </breakpoint>
+  </sequence>
+
+  <output>
+    <sampling_group basis="r(0)" initial_sample="yes">
+      <moments> volume </moments>
+      <dependencies>densityvector</dependencies>
+      <![CDATA[
+        volume = rho / (M_PI) ;// This should be close to 1.
+      ]]>
+    </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+r rho 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>256</Dim>
+    <Dim>2</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+disc_coordinate_space1_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/transforms/disc_coordinate_space_expected.h5 b/testsuite/transforms/disc_coordinate_space_expected.h5
new file mode 100644
index 0000000..a42205b
Binary files /dev/null and b/testsuite/transforms/disc_coordinate_space_expected.h5 differ
diff --git a/testsuite/transforms/disc_coordinate_space_expected.xsil b/testsuite/transforms/disc_coordinate_space_expected.xsil
new file mode 100644
index 0000000..2642b05
--- /dev/null
+++ b/testsuite/transforms/disc_coordinate_space_expected.xsil
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="disc.xsil" expected="disc_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+    <xsil_file name="disc_coordinate_space1.xsil" expected="disc_coordinate_space1_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+    <xsil_file name="disc_spectral_space.xsil" expected="disc_spectral_space_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+    <xsil_file name="disc_coordinate_space2.xsil" expected="disc_coordinate_space_expected.xsil" absolute_tolerance="1e-3" relative_tolerance="1e-3" />
+  </testing>
+  
+  <name>disc</name>
+
+  <author>Mattias Johnsson</author>
+  <description>
+    Calculate the volume of unit ball using spherical bessel transform
+  </description>
+
+  <geometry>
+      <propagation_dimension> t </propagation_dimension>
+      <transverse_dimensions>
+        <dimension name="r" lattice="256"  domain="(0, 1.5)" transform="bessel" volume_prefactor="4.0*M_PI"/>
+      </transverse_dimensions>
+   </geometry>
+
+  <vector name="densityvector" type="real" dimensions="r">
+    <components> rho </components>
+    <initialisation>
+      <![CDATA[
+        if (r<=1.0)
+          rho = 1.0;
+        else
+          rho = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <breakpoint filename="disc_coordinate_space1.xsil">
+      <dependencies>densityvector</dependencies>
+    </breakpoint>
+    <breakpoint filename="disc_spectral_space.xsil">
+      <dependencies basis="kr">densityvector</dependencies>
+    </breakpoint>
+    <breakpoint filename="disc_coordinate_space2.xsil">
+      <dependencies>densityvector</dependencies>
+    </breakpoint>
+  </sequence>
+
+  <output>
+    <sampling_group basis="r(0)" initial_sample="yes">
+      <moments> volume </moments>
+      <dependencies>densityvector</dependencies>
+      <![CDATA[
+        volume = rho / (M_PI) ;// This should be close to 1.
+      ]]>
+    </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+r rho 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>256</Dim>
+    <Dim>2</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+disc_coordinate_space_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/transforms/disc_expected.h5 b/testsuite/transforms/disc_expected.h5
new file mode 100644
index 0000000..dc9b8c2
Binary files /dev/null and b/testsuite/transforms/disc_expected.h5 differ
diff --git a/testsuite/transforms/disc_expected.xsil b/testsuite/transforms/disc_expected.xsil
new file mode 100644
index 0000000..c089384
--- /dev/null
+++ b/testsuite/transforms/disc_expected.xsil
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="disc.xsil" expected="disc_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+    <xsil_file name="disc_coordinate_space1.xsil" expected="disc_coordinate_space1_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+    <xsil_file name="disc_spectral_space.xsil" expected="disc_spectral_space_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+    <xsil_file name="disc_coordinate_space2.xsil" expected="disc_coordinate_space_expected.xsil" absolute_tolerance="1e-3" relative_tolerance="1e-3" />
+  </testing>
+  
+  <name>disc</name>
+
+  <author>Mattias Johnsson</author>
+  <description>
+    Calculate the volume of unit ball using spherical bessel transform
+  </description>
+
+  <geometry>
+      <propagation_dimension> t </propagation_dimension>
+      <transverse_dimensions>
+        <dimension name="r" lattice="256"  domain="(0, 1.5)" transform="bessel" volume_prefactor="2.0*M_PI"/>
+      </transverse_dimensions>
+   </geometry>
+
+  <vector name="densityvector" type="real" dimensions="r">
+    <components> rho </components>
+    <initialisation>
+      <![CDATA[
+        if (r<=1.0)
+          rho = 1.0;
+        else
+          rho = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <breakpoint filename="disc_coordinate_space1.xsil">
+      <dependencies>densityvector</dependencies>
+    </breakpoint>
+    <breakpoint filename="disc_spectral_space.xsil">
+      <dependencies basis="kr">densityvector</dependencies>
+    </breakpoint>
+    <breakpoint filename="disc_coordinate_space2.xsil">
+      <dependencies>densityvector</dependencies>
+    </breakpoint>
+  </sequence>
+
+  <output>
+    <sampling_group basis="r(0)" initial_sample="yes">
+      <moments> volume </moments>
+      <dependencies>densityvector</dependencies>
+      <![CDATA[
+        volume = rho / (M_PI) ;// This should be close to 1.
+      ]]>
+    </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">0</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>1</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+volume 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>1</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+disc_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/transforms/disc_spectral_space_expected.h5 b/testsuite/transforms/disc_spectral_space_expected.h5
new file mode 100644
index 0000000..1ccec45
Binary files /dev/null and b/testsuite/transforms/disc_spectral_space_expected.h5 differ
diff --git a/testsuite/transforms/disc_spectral_space_expected.xsil b/testsuite/transforms/disc_spectral_space_expected.xsil
new file mode 100644
index 0000000..cdb48d3
--- /dev/null
+++ b/testsuite/transforms/disc_spectral_space_expected.xsil
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="disc.xsil" expected="disc_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+    <xsil_file name="disc_coordinate_space1.xsil" expected="disc_coordinate_space1_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+    <xsil_file name="disc_spectral_space.xsil" expected="disc_spectral_space_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+    <xsil_file name="disc_coordinate_space2.xsil" expected="disc_coordinate_space_expected.xsil" absolute_tolerance="1e-3" relative_tolerance="1e-3" />
+  </testing>
+  
+  <name>disc</name>
+
+  <author>Mattias Johnsson</author>
+  <description>
+    Calculate the volume of unit ball using spherical bessel transform
+  </description>
+
+  <geometry>
+      <propagation_dimension> t </propagation_dimension>
+      <transverse_dimensions>
+        <dimension name="r" lattice="256"  domain="(0, 1.5)" transform="bessel" volume_prefactor="4.0*M_PI"/>
+      </transverse_dimensions>
+   </geometry>
+
+  <vector name="densityvector" type="real" dimensions="r">
+    <components> rho </components>
+    <initialisation>
+      <![CDATA[
+        if (r<=1.0)
+          rho = 1.0;
+        else
+          rho = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <breakpoint filename="disc_coordinate_space1.xsil">
+      <dependencies>densityvector</dependencies>
+    </breakpoint>
+    <breakpoint filename="disc_spectral_space.xsil">
+      <dependencies basis="kr">densityvector</dependencies>
+    </breakpoint>
+    <breakpoint filename="disc_coordinate_space2.xsil">
+      <dependencies>densityvector</dependencies>
+    </breakpoint>
+  </sequence>
+
+  <output>
+    <sampling_group basis="r(0)" initial_sample="yes">
+      <moments> volume </moments>
+      <dependencies>densityvector</dependencies>
+      <![CDATA[
+        volume = rho / (M_PI) ;// This should be close to 1.
+      ]]>
+    </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+kr rho 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>256</Dim>
+    <Dim>2</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+disc_spectral_space_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/transforms/hermitegauss_fourier.xmds b/testsuite/transforms/hermitegauss_fourier.xmds
new file mode 100644
index 0000000..ebc5acd
--- /dev/null
+++ b/testsuite/transforms/hermitegauss_fourier.xmds
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="hermitegauss_fourier_1.xsil" expected="hermitegauss_fourier_1_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+    <xsil_file name="hermitegauss_fourier_2.xsil" expected="hermitegauss_fourier_2_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+    <xsil_file name="hermitegauss_fourier_3.xsil" expected="hermitegauss_fourier_3_expected.xsil" absolute_tolerance="1e-11" relative_tolerance="1e-5" />
+    <xsil_file name="hermitegauss_fourier_4.xsil" expected="hermitegauss_fourier_1_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+  </testing>
+
+  <name>hermitegauss_fourier</name>
+  <author>Graham Dennis</author>
+  <description>
+    Transform between the various Hermite-Gauss bases (position, spectral, momentum)
+  </description>
+  
+  <features>
+    <validation kind="run-time" />
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="80" spectral_lattice="50" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+        // initial state is the groundstate in the x axis, but shifted by offset and expanded
+      psi = pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.25*(M*omega/hbar)*(x - offset)*(x - offset));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="hermitegauss_fourier_1.xsil" format="hdf5">
+      <dependencies basis="x">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="hermitegauss_fourier_2.xsil" format="hdf5">
+      <dependencies basis="nx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="hermitegauss_fourier_3.xsil" format="hdf5">
+      <dependencies basis="kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="hermitegauss_fourier_4.xsil" format="hdf5">
+      <dependencies basis="x">main</dependencies>
+    </breakpoint>
+  </sequence>
+  <output />
+</simulation>
diff --git a/testsuite/transforms/hermitegauss_fourier_1_expected.h5 b/testsuite/transforms/hermitegauss_fourier_1_expected.h5
new file mode 100644
index 0000000..3a2bbdb
Binary files /dev/null and b/testsuite/transforms/hermitegauss_fourier_1_expected.h5 differ
diff --git a/testsuite/transforms/hermitegauss_fourier_1_expected.xsil b/testsuite/transforms/hermitegauss_fourier_1_expected.xsil
new file mode 100644
index 0000000..c6c16cc
--- /dev/null
+++ b/testsuite/transforms/hermitegauss_fourier_1_expected.xsil
@@ -0,0 +1,84 @@
+<?xml version="1.0" ?><simulation xmds-version="2">
+  <testing>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_fourier_1_expected.xsil" name="hermitegauss_fourier_1.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_fourier_2_expected.xsil" name="hermitegauss_fourier_2.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-11" expected="hermitegauss_fourier_3_expected.xsil" name="hermitegauss_fourier_3.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_fourier_1_expected.xsil" name="hermitegauss_fourier_4.xsil" relative_tolerance="1e-5"/>
+  </testing>
+
+  <name>hermitegauss_fourier</name>
+  <author>Graham Dennis</author>
+  <description>
+    Transform between the various Hermite-Gauss bases (position, spectral, momentum)
+  </description>
+  
+  <features>
+    <validation kind="run-time"/>
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension lattice="80" length_scale="sqrt(hbar/(M*omega))" name="x" spectral_lattice="50" transform="hermite-gauss"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector initial_basis="x" name="main" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+        // initial state is the groundstate in the x axis, but shifted by offset and expanded
+      psi = pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.25*(M*omega/hbar)*(x - offset)*(x - offset));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="hermitegauss_fourier_1.xsil" format="hdf5">
+      <dependencies basis="x">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="hermitegauss_fourier_2.xsil" format="hdf5">
+      <dependencies basis="nx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="hermitegauss_fourier_3.xsil" format="hdf5">
+      <dependencies basis="kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="hermitegauss_fourier_4.xsil" format="hdf5">
+      <dependencies basis="x">main</dependencies>
+    </breakpoint>
+  </sequence>
+  <output/>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x psiR psiI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>80</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+hermitegauss_fourier_1_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/transforms/hermitegauss_fourier_2_expected.h5 b/testsuite/transforms/hermitegauss_fourier_2_expected.h5
new file mode 100644
index 0000000..510b9c6
Binary files /dev/null and b/testsuite/transforms/hermitegauss_fourier_2_expected.h5 differ
diff --git a/testsuite/transforms/hermitegauss_fourier_2_expected.xsil b/testsuite/transforms/hermitegauss_fourier_2_expected.xsil
new file mode 100644
index 0000000..50ac70e
--- /dev/null
+++ b/testsuite/transforms/hermitegauss_fourier_2_expected.xsil
@@ -0,0 +1,84 @@
+<?xml version="1.0" ?><simulation xmds-version="2">
+  <testing>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_fourier_1_expected.xsil" name="hermitegauss_fourier_1.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_fourier_2_expected.xsil" name="hermitegauss_fourier_2.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-11" expected="hermitegauss_fourier_3_expected.xsil" name="hermitegauss_fourier_3.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_fourier_1_expected.xsil" name="hermitegauss_fourier_4.xsil" relative_tolerance="1e-5"/>
+  </testing>
+
+  <name>hermitegauss_fourier</name>
+  <author>Graham Dennis</author>
+  <description>
+    Transform between the various Hermite-Gauss bases (position, spectral, momentum)
+  </description>
+  
+  <features>
+    <validation kind="run-time"/>
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension lattice="80" length_scale="sqrt(hbar/(M*omega))" name="x" spectral_lattice="50" transform="hermite-gauss"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector initial_basis="x" name="main" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+        // initial state is the groundstate in the x axis, but shifted by offset and expanded
+      psi = pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.25*(M*omega/hbar)*(x - offset)*(x - offset));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="hermitegauss_fourier_1.xsil" format="hdf5">
+      <dependencies basis="x">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="hermitegauss_fourier_2.xsil" format="hdf5">
+      <dependencies basis="nx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="hermitegauss_fourier_3.xsil" format="hdf5">
+      <dependencies basis="kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="hermitegauss_fourier_4.xsil" format="hdf5">
+      <dependencies basis="x">main</dependencies>
+    </breakpoint>
+  </sequence>
+  <output/>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+nx psiR psiI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>50</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+hermitegauss_fourier_2_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/transforms/hermitegauss_fourier_3_expected.h5 b/testsuite/transforms/hermitegauss_fourier_3_expected.h5
new file mode 100644
index 0000000..f95e1a9
Binary files /dev/null and b/testsuite/transforms/hermitegauss_fourier_3_expected.h5 differ
diff --git a/testsuite/transforms/hermitegauss_fourier_3_expected.xsil b/testsuite/transforms/hermitegauss_fourier_3_expected.xsil
new file mode 100644
index 0000000..1542788
--- /dev/null
+++ b/testsuite/transforms/hermitegauss_fourier_3_expected.xsil
@@ -0,0 +1,84 @@
+<?xml version="1.0" ?><simulation xmds-version="2">
+  <testing>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_fourier_1_expected.xsil" name="hermitegauss_fourier_1.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_fourier_2_expected.xsil" name="hermitegauss_fourier_2.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-11" expected="hermitegauss_fourier_3_expected.xsil" name="hermitegauss_fourier_3.xsil" relative_tolerance="1e-5"/>
+    <xsil_file absolute_tolerance="1e-8" expected="hermitegauss_fourier_1_expected.xsil" name="hermitegauss_fourier_4.xsil" relative_tolerance="1e-5"/>
+  </testing>
+
+  <name>hermitegauss_fourier</name>
+  <author>Graham Dennis</author>
+  <description>
+    Transform between the various Hermite-Gauss bases (position, spectral, momentum)
+  </description>
+  
+  <features>
+    <validation kind="run-time"/>
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension lattice="80" length_scale="sqrt(hbar/(M*omega))" name="x" spectral_lattice="50" transform="hermite-gauss"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector initial_basis="x" name="main" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+        // initial state is the groundstate in the x axis, but shifted by offset and expanded
+      psi = pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.25*(M*omega/hbar)*(x - offset)*(x - offset));
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="hermitegauss_fourier_1.xsil" format="hdf5">
+      <dependencies basis="x">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="hermitegauss_fourier_2.xsil" format="hdf5">
+      <dependencies basis="nx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="hermitegauss_fourier_3.xsil" format="hdf5">
+      <dependencies basis="kx">main</dependencies>
+    </breakpoint>
+    <breakpoint filename="hermitegauss_fourier_4.xsil" format="hdf5">
+      <dependencies basis="x">main</dependencies>
+    </breakpoint>
+  </sequence>
+  <output/>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+kx psiR psiI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>80</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+hermitegauss_fourier_3_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/transforms/hermitegauss_fourier_loading.xmds b/testsuite/transforms/hermitegauss_fourier_loading.xmds
new file mode 100644
index 0000000..492a8d9
--- /dev/null
+++ b/testsuite/transforms/hermitegauss_fourier_loading.xmds
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <input_xsil_file name="hermitegauss_fourier_2_expected.xsil" />
+    <xsil_file name="hermitegauss_fourier_loading_break.xsil" expected="hermitegauss_fourier_loading_break_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+  </testing>
+
+  <name>hermitegauss_fourier_loading</name>
+  <author>Graham Dennis</author>
+  <description>
+    Loose loading from the Hermite-Gauss bases (checking that it works for integer-valued dimensions)
+  </description>
+  
+  <features>
+    <validation kind="run-time" />
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="200" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_space="nx" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation kind="hdf5" geometry_matching_mode="loose">
+        <filename>hermitegauss_fourier_2_expected.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="hermitegauss_fourier_loading_break.xsil" format="hdf5">
+      <dependencies basis="x">main</dependencies>
+    </breakpoint>
+  </sequence>
+  <output />
+</simulation>
diff --git a/testsuite/transforms/hermitegauss_fourier_loading_break_expected.h5 b/testsuite/transforms/hermitegauss_fourier_loading_break_expected.h5
new file mode 100644
index 0000000..216d421
Binary files /dev/null and b/testsuite/transforms/hermitegauss_fourier_loading_break_expected.h5 differ
diff --git a/testsuite/transforms/hermitegauss_fourier_loading_break_expected.xsil b/testsuite/transforms/hermitegauss_fourier_loading_break_expected.xsil
new file mode 100644
index 0000000..49995dc
--- /dev/null
+++ b/testsuite/transforms/hermitegauss_fourier_loading_break_expected.xsil
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <input_xsil_file name="hermitegauss_fourier_2_expected.xsil" />
+    <xsil_file name="hermitegauss_fourier_loading_break.xsil" expected="hermitegauss_fourier_loading_break_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+  </testing>
+
+  <name>hermitegauss_fourier_loading</name>
+  <author>Graham Dennis</author>
+  <description>
+    Loose loading from the Hermite-Gauss bases (checking that it works for integer-valued dimensions)
+  </description>
+  
+  <features>
+    <validation kind="run-time" />
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="200" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="nx" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation kind="hdf5" geometry_matching_mode="loose">
+        <filename>hermitegauss_fourier_2_expected.h5</filename>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <breakpoint filename="hermitegauss_fourier_loading_break.xsil" format="hdf5">
+      <dependencies basis="x">main</dependencies>
+    </breakpoint>
+  </sequence>
+  <output />
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+x psiR psiI 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>200</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+hermitegauss_fourier_loading_break_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/transforms/hermitegauss_transform_2d.xmds b/testsuite/transforms/hermitegauss_transform_2d.xmds
new file mode 100644
index 0000000..d78646e
--- /dev/null
+++ b/testsuite/transforms/hermitegauss_transform_2d.xmds
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="hermitegauss_transform_2d.xsil" expected="hermitegauss_transform_2d_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+  </testing>
+
+  <name>hermitegauss_transform_2d</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the Schroedinger equation in 2D using the hermite-Gauss basis.
+  </description>
+  
+  <features>
+    <benchmark />
+    <bing />
+    <validation kind="run-time" />
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="20" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+      <dimension name="y" lattice="20" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+        // initial state is the groundstate in the x axis, but shifted by offset
+      psi = pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.5*(M*omega/hbar)*(x - offset)*(x - offset));
+        // and an expanded gaussian in the y axis
+      psi *= pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.25*(M*omega/hbar)*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>N integral_y2</components>
+    <evaluation>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        N = mod2(psi);
+        integral_y2 = mod2(psi)*y*y;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-6" interval="1e-3" steps="400">
+      <samples>10 1 100</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="nx ny">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*(nx + ny + 1.0)*omega;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dpsi_dt = L[psi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="nx ny" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(0)" initial_sample="yes">
+        <moments>mean_x mean_sigmay</moments>
+        <dependencies>main normalisation</dependencies>
+        <![CDATA[
+          mean_x = mod2(psi)*x/N;
+          mean_sigmay = sqrt(integral_y2/N);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/transforms/hermitegauss_transform_2d_chunked.xmds b/testsuite/transforms/hermitegauss_transform_2d_chunked.xmds
new file mode 100644
index 0000000..ac2cee5
--- /dev/null
+++ b/testsuite/transforms/hermitegauss_transform_2d_chunked.xmds
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="hermitegauss_transform_2d_chunked.xsil" expected="hermitegauss_transform_2d_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+  </testing>
+
+  <name>hermitegauss_transform_2d_chunked</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the Schroedinger equation in 2D using the hermite-Gauss basis.
+  </description>
+  
+  <features>
+    <chunked_output size="10KB" />
+    <validation kind="run-time" />
+    <globals>
+      <![CDATA[
+        const real M = 9.1e-31; // Mass of an electron
+        const real hbar = 1.05e-34;
+        const real omega = 2*M_PI*1e3;
+        const real offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="20" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+      <dimension name="y" lattice="20" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+        // initial state is the groundstate in the x axis, but shifted by offset
+      psi = pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.5*(M*omega/hbar)*(x - offset)*(x - offset));
+        // and an expanded gaussian in the y axis
+      psi *= pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.25*(M*omega/hbar)*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>N integral_y2</components>
+    <evaluation>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        N = mod2(psi);
+        integral_y2 = mod2(psi)*y*y;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-6" interval="1e-3" steps="400">
+      <samples>10 1 100</samples>
+      <operators>
+        <operator kind="ip" constant="yes" basis="nx ny">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*(nx + ny + 1.0)*omega;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dpsi_dt = L[psi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="x y" initial_sample="yes">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="nx ny" initial_sample="no">
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group basis="x(0) y(0)" initial_sample="yes">
+        <moments>mean_x mean_sigmay</moments>
+        <dependencies>main normalisation</dependencies>
+        <![CDATA[
+          mean_x = mod2(psi)*x/N;
+          mean_sigmay = sqrt(integral_y2/N);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/transforms/hermitegauss_transform_2d_expected.xsil b/testsuite/transforms/hermitegauss_transform_2d_expected.xsil
new file mode 100644
index 0000000..76e7f20
--- /dev/null
+++ b/testsuite/transforms/hermitegauss_transform_2d_expected.xsil
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="hermitegauss_transform_2d.xsil" expected="hermitegauss_transform_2d_expected.xsil" absolute_tolerance="1e-8" relative_tolerance="1e-5" />
+  </testing>
+
+  <name>hermitegauss_transform_2d</name>
+  <author>Graham Dennis</author>
+  <description>
+    Solve the Schroedinger equation in 2D using the hermite-Gauss basis.
+  </description>
+  
+  <features>
+    <benchmark />
+    <!-- <error_check /> -->
+    <bing />
+    <!-- <fftw plan="estimate" /> -->
+    <mmt />
+    <validation kind="run-time" />
+    <globals>
+      <![CDATA[
+        const double M = 9.1e-31; // Mass of an electron
+        const double hbar = 1.05e-34;
+        const double omega = 2*M_PI*1e3;
+        const double offset = 1.0 * sqrt(hbar/(M*omega));
+        
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="20" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+      <dimension name="y" lattice="20" length_scale="sqrt(hbar/(M*omega))" transform="hermite-gauss" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x y" type="complex">
+    <components>
+      psi
+    </components>
+    <initialisation>
+      <![CDATA[
+        // initial state is the groundstate in the x axis, but shifted by offset
+      psi = pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.5*(M*omega/hbar)*(x - offset)*(x - offset));
+        // and an expanded gaussian in the y axis
+      psi *= pow(M*omega/(hbar*M_PI), 0.25) * exp(-0.25*(M*omega/hbar)*y*y);
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="double">
+    <components>N integral_y2</components>
+    <evaluation>
+      <dependencies>main</dependencies>
+      <![CDATA[
+        N = mod2(psi);
+        integral_y2 = mod2(psi)*y*y;
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="ARK45" tolerance="1e-6" interval="1e-3" steps="400">
+      <samples>10 1 100</samples>
+      <operators>
+        <operator kind="ip" constant="yes" fourier_space="nx ny">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -i*(nx + ny + 1.0)*omega;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <![CDATA[
+          dpsi_dt = L[psi];
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary">
+      <sampling_group initial_sample="yes">
+        <dimension name="x" fourier_space="no" />
+        <dimension name="y" fourier_space="no" />
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="no">
+        <dimension name="x" fourier_space="yes" />
+        <dimension name="y" fourier_space="yes" />
+        <moments>dens</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          dens = mod2(psi);
+        
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes">
+        <dimension name="x" lattice="0" />
+        <dimension name="y" lattice="0" />
+        <moments>mean_x mean_sigmay</moments>
+        <dependencies>main normalisation</dependencies>
+        <![CDATA[
+          mean_x = mod2(psi)*x/N;
+          mean_sigmay = sqrt(integral_y2/N);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">3</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t x y dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>11</Dim>
+    <Dim>20</Dim>
+    <Dim>20</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="BigEndian"/>
+hermitegauss_transform_2d_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+nx ny dens 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>20</Dim>
+    <Dim>20</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="BigEndian"/>
+hermitegauss_transform_2d_expected_mg1.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_3">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t mean_x mean_sigmay 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>101</Dim>
+    <Dim>3</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="BigEndian"/>
+hermitegauss_transform_2d_expected_mg2.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/transforms/hermitegauss_transform_2d_expected_mg0.dat b/testsuite/transforms/hermitegauss_transform_2d_expected_mg0.dat
new file mode 100644
index 0000000..36a0dcd
Binary files /dev/null and b/testsuite/transforms/hermitegauss_transform_2d_expected_mg0.dat differ
diff --git a/testsuite/transforms/hermitegauss_transform_2d_expected_mg1.dat b/testsuite/transforms/hermitegauss_transform_2d_expected_mg1.dat
new file mode 100644
index 0000000..2fd3f63
Binary files /dev/null and b/testsuite/transforms/hermitegauss_transform_2d_expected_mg1.dat differ
diff --git a/testsuite/transforms/hermitegauss_transform_2d_expected_mg2.dat b/testsuite/transforms/hermitegauss_transform_2d_expected_mg2.dat
new file mode 100644
index 0000000..3535186
Binary files /dev/null and b/testsuite/transforms/hermitegauss_transform_2d_expected_mg2.dat differ
diff --git a/testsuite/transforms/spherical_ball.xmds b/testsuite/transforms/spherical_ball.xmds
new file mode 100644
index 0000000..2756eb1
--- /dev/null
+++ b/testsuite/transforms/spherical_ball.xmds
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="spherical_ball.xsil" expected="spherical_ball_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+    <xsil_file name="spherical_ball_coordinate_space1.xsil" expected="spherical_ball_coordinate_space1_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+    <xsil_file name="spherical_ball_spectral_space.xsil" expected="spherical_ball_spectral_space_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+    <xsil_file name="spherical_ball_coordinate_space2.xsil" expected="spherical_ball_coordinate_space_expected.xsil" absolute_tolerance="1e-3" relative_tolerance="1e-3" />
+  </testing>
+  
+  <name>spherical_ball</name>
+
+  <author>Mattias Johnsson</author>
+  <description>
+    Calculate the volume of unit ball using spherical bessel transform
+  </description>
+
+  <geometry>
+      <propagation_dimension> t </propagation_dimension>
+      <transverse_dimensions>
+        <dimension name="r" lattice="256"  domain="(0, 1.5)" transform="spherical-bessel" volume_prefactor="4.0*M_PI"/>
+      </transverse_dimensions>
+   </geometry>
+
+  <vector name="densityvector" type="real" dimensions="r">
+    <components> rho </components>
+    <initialisation>
+      <![CDATA[
+        if (r<=1.0)
+          rho = 1.0;
+        else
+          rho = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <breakpoint filename="spherical_ball_coordinate_space1.xsil">
+      <dependencies>densityvector</dependencies>
+    </breakpoint>
+    <breakpoint filename="spherical_ball_spectral_space.xsil">
+      <dependencies basis="kr">densityvector</dependencies>
+    </breakpoint>
+    <breakpoint filename="spherical_ball_coordinate_space2.xsil">
+      <dependencies>densityvector</dependencies>
+    </breakpoint>
+  </sequence>
+
+  <output>
+    <sampling_group basis="r(0)" initial_sample="yes">
+      <moments> volume </moments>
+      <dependencies>densityvector</dependencies>
+      <![CDATA[
+        volume = rho / (M_PI*4.0/3.0) ;// This should be close to 1.
+      ]]>
+    </sampling_group>
+  </output>
+</simulation>
+
diff --git a/testsuite/transforms/spherical_ball_coordinate_space1_expected.h5 b/testsuite/transforms/spherical_ball_coordinate_space1_expected.h5
new file mode 100644
index 0000000..7fb163d
Binary files /dev/null and b/testsuite/transforms/spherical_ball_coordinate_space1_expected.h5 differ
diff --git a/testsuite/transforms/spherical_ball_coordinate_space1_expected.xsil b/testsuite/transforms/spherical_ball_coordinate_space1_expected.xsil
new file mode 100644
index 0000000..360ce90
--- /dev/null
+++ b/testsuite/transforms/spherical_ball_coordinate_space1_expected.xsil
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="spherical_ball.xsil" expected="spherical_ball_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+    <xsil_file name="spherical_ball_coordinate_space1.xsil" expected="spherical_ball_coordinate_space1_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+    <xsil_file name="spherical_ball_spectral_space.xsil" expected="spherical_ball_spectral_space_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+    <xsil_file name="spherical_ball_coordinate_space2.xsil" expected="spherical_ball_coordinate_space_expected.xsil" absolute_tolerance="1e-3" relative_tolerance="1e-3" />
+  </testing>
+  
+  <name>spherical_ball</name>
+
+  <author>Mattias Johnsson</author>
+  <description>
+    Calculate the volume of unit ball using spherical bessel transform
+  </description>
+
+  <geometry>
+      <propagation_dimension> t </propagation_dimension>
+      <transverse_dimensions>
+        <dimension name="r" lattice="256"  domain="(0, 1.5)" transform="spherical-bessel" volume_prefactor="4.0*M_PI"/>
+      </transverse_dimensions>
+   </geometry>
+
+  <vector name="densityvector" type="real" dimensions="r">
+    <components> rho </components>
+    <initialisation>
+      <![CDATA[
+        if (r<=1.0)
+          rho = 1.0;
+        else
+          rho = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <breakpoint filename="spherical_ball_coordinate_space1.xsil">
+      <dependencies>densityvector</dependencies>
+    </breakpoint>
+    <breakpoint filename="spherical_ball_spectral_space.xsil">
+      <dependencies basis="kr">densityvector</dependencies>
+    </breakpoint>
+    <breakpoint filename="spherical_ball_coordinate_space2.xsil">
+      <dependencies>densityvector</dependencies>
+    </breakpoint>
+  </sequence>
+
+  <output>
+    <sampling_group basis="r(0)" initial_sample="yes">
+      <moments> volume </moments>
+      <dependencies>densityvector</dependencies>
+      <![CDATA[
+        volume = rho / (M_PI*4.0/3.0) ;// This should be close to 1.
+      ]]>
+    </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+r rho 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>256</Dim>
+    <Dim>2</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+spherical_ball_coordinate_space1_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/transforms/spherical_ball_coordinate_space_expected.h5 b/testsuite/transforms/spherical_ball_coordinate_space_expected.h5
new file mode 100644
index 0000000..b52463f
Binary files /dev/null and b/testsuite/transforms/spherical_ball_coordinate_space_expected.h5 differ
diff --git a/testsuite/transforms/spherical_ball_coordinate_space_expected.xsil b/testsuite/transforms/spherical_ball_coordinate_space_expected.xsil
new file mode 100644
index 0000000..ba49f61
--- /dev/null
+++ b/testsuite/transforms/spherical_ball_coordinate_space_expected.xsil
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="spherical_ball.xsil" expected="spherical_ball_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+    <xsil_file name="spherical_ball_coordinate_space1.xsil" expected="spherical_ball_coordinate_space1_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+    <xsil_file name="spherical_ball_spectral_space.xsil" expected="spherical_ball_spectral_space_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+    <xsil_file name="spherical_ball_coordinate_space2.xsil" expected="spherical_ball_coordinate_space_expected.xsil" absolute_tolerance="1e-3" relative_tolerance="1e-3" />
+  </testing>
+  
+  <name>spherical_ball</name>
+
+  <author>Mattias Johnsson</author>
+  <description>
+    Calculate the volume of unit ball using spherical bessel transform
+  </description>
+
+  <geometry>
+      <propagation_dimension> t </propagation_dimension>
+      <transverse_dimensions>
+        <dimension name="r" lattice="256"  domain="(0, 1.5)" transform="spherical-bessel" volume_prefactor="4.0*M_PI"/>
+      </transverse_dimensions>
+   </geometry>
+
+  <vector name="densityvector" type="real" dimensions="r">
+    <components> rho </components>
+    <initialisation>
+      <![CDATA[
+        if (r<=1.0)
+          rho = 1.0;
+        else
+          rho = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <breakpoint filename="spherical_ball_coordinate_space1.xsil">
+      <dependencies>densityvector</dependencies>
+    </breakpoint>
+    <breakpoint filename="spherical_ball_spectral_space.xsil">
+      <dependencies basis="kr">densityvector</dependencies>
+    </breakpoint>
+    <breakpoint filename="spherical_ball_coordinate_space2.xsil">
+      <dependencies>densityvector</dependencies>
+    </breakpoint>
+  </sequence>
+
+  <output>
+    <sampling_group basis="r(0)" initial_sample="yes">
+      <moments> volume </moments>
+      <dependencies>densityvector</dependencies>
+      <![CDATA[
+        volume = rho / (M_PI*4.0/3.0) ;// This should be close to 1.
+      ]]>
+    </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+r rho 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>256</Dim>
+    <Dim>2</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+spherical_ball_coordinate_space_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/transforms/spherical_ball_expected.h5 b/testsuite/transforms/spherical_ball_expected.h5
new file mode 100644
index 0000000..fc130ff
Binary files /dev/null and b/testsuite/transforms/spherical_ball_expected.h5 differ
diff --git a/testsuite/transforms/spherical_ball_expected.xsil b/testsuite/transforms/spherical_ball_expected.xsil
new file mode 100644
index 0000000..1505367
--- /dev/null
+++ b/testsuite/transforms/spherical_ball_expected.xsil
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="spherical_ball.xsil" expected="spherical_ball_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+    <xsil_file name="spherical_ball_coordinate_space1.xsil" expected="spherical_ball_coordinate_space1_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+    <xsil_file name="spherical_ball_spectral_space.xsil" expected="spherical_ball_spectral_space_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+    <xsil_file name="spherical_ball_coordinate_space2.xsil" expected="spherical_ball_coordinate_space_expected.xsil" absolute_tolerance="1e-3" relative_tolerance="1e-3" />
+  </testing>
+  
+  <name>spherical_ball</name>
+
+  <author>Mattias Johnsson</author>
+  <description>
+    Calculate the volume of unit ball using spherical bessel transform
+  </description>
+
+  <geometry>
+      <propagation_dimension> t </propagation_dimension>
+      <transverse_dimensions>
+        <dimension name="r" lattice="256"  domain="(0, 1.5)" transform="spherical-bessel" volume_prefactor="4.0*M_PI"/>
+      </transverse_dimensions>
+   </geometry>
+
+  <vector name="densityvector" type="real" dimensions="r">
+    <components> rho </components>
+    <initialisation>
+      <![CDATA[
+        if (r<=1.0)
+          rho = 1.0;
+        else
+          rho = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <breakpoint filename="spherical_ball_coordinate_space1.xsil">
+      <dependencies>densityvector</dependencies>
+    </breakpoint>
+    <breakpoint filename="spherical_ball_spectral_space.xsil">
+      <dependencies basis="kr">densityvector</dependencies>
+    </breakpoint>
+    <breakpoint filename="spherical_ball_coordinate_space2.xsil">
+      <dependencies>densityvector</dependencies>
+    </breakpoint>
+  </sequence>
+
+  <output>
+    <sampling_group basis="r(0)" initial_sample="yes">
+      <moments> volume </moments>
+      <dependencies>densityvector</dependencies>
+      <![CDATA[
+        volume = rho / (M_PI*4.0/3.0) ;// This should be close to 1.
+      ]]>
+    </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">0</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>1</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+volume 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>1</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+spherical_ball_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/transforms/spherical_ball_spectral_space_expected.h5 b/testsuite/transforms/spherical_ball_spectral_space_expected.h5
new file mode 100644
index 0000000..4789cc8
Binary files /dev/null and b/testsuite/transforms/spherical_ball_spectral_space_expected.h5 differ
diff --git a/testsuite/transforms/spherical_ball_spectral_space_expected.xsil b/testsuite/transforms/spherical_ball_spectral_space_expected.xsil
new file mode 100644
index 0000000..8e93c57
--- /dev/null
+++ b/testsuite/transforms/spherical_ball_spectral_space_expected.xsil
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="spherical_ball.xsil" expected="spherical_ball_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+    <xsil_file name="spherical_ball_coordinate_space1.xsil" expected="spherical_ball_coordinate_space1_expected.xsil" absolute_tolerance="1e-5" relative_tolerance="1e-5" />
+    <xsil_file name="spherical_ball_spectral_space.xsil" expected="spherical_ball_spectral_space_expected.xsil" absolute_tolerance="1e-4" relative_tolerance="1e-4" />
+    <xsil_file name="spherical_ball_coordinate_space2.xsil" expected="spherical_ball_coordinate_space_expected.xsil" absolute_tolerance="1e-3" relative_tolerance="1e-3" />
+  </testing>
+  
+  <name>spherical_ball</name>
+
+  <author>Mattias Johnsson</author>
+  <description>
+    Calculate the volume of unit ball using spherical bessel transform
+  </description>
+
+  <geometry>
+      <propagation_dimension> t </propagation_dimension>
+      <transverse_dimensions>
+        <dimension name="r" lattice="256"  domain="(0, 1.5)" transform="spherical-bessel" volume_prefactor="4.0*M_PI"/>
+      </transverse_dimensions>
+   </geometry>
+
+  <vector name="densityvector" type="real" dimensions="r">
+    <components> rho </components>
+    <initialisation>
+      <![CDATA[
+        if (r<=1.0)
+          rho = 1.0;
+        else
+          rho = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+
+  <sequence>
+    <breakpoint filename="spherical_ball_coordinate_space1.xsil">
+      <dependencies>densityvector</dependencies>
+    </breakpoint>
+    <breakpoint filename="spherical_ball_spectral_space.xsil">
+      <dependencies basis="kr">densityvector</dependencies>
+    </breakpoint>
+    <breakpoint filename="spherical_ball_coordinate_space2.xsil">
+      <dependencies>densityvector</dependencies>
+    </breakpoint>
+  </sequence>
+
+  <output>
+    <sampling_group basis="r(0)" initial_sample="yes">
+      <moments> volume </moments>
+      <dependencies>densityvector</dependencies>
+      <![CDATA[
+        volume = rho / (M_PI*4.0/3.0) ;// This should be close to 1.
+      ]]>
+    </sampling_group>
+  </output>
+
+<info>
+Script compiled with XMDS2 version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="breakpoint">
+  <Param Name="n_independent">1</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>2</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+kr rho 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>256</Dim>
+    <Dim>2</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+spherical_ball_spectral_space_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/transforms/vibstring_dct.xmds b/testsuite/transforms/vibstring_dct.xmds
new file mode 100644
index 0000000..18a4bed
--- /dev/null
+++ b/testsuite/transforms/vibstring_dct.xmds
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="vibstring_dct.xsil" expected="vibstring_dct_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>vibstring_dct</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string using a Discrete Cosine transform (i.e. even boundary conditions on both sides)
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw plan="estimate" />
+    <globals>
+      <![CDATA[
+      const real T = 10.0;
+      const real mass = 1e-3;
+      const real length = 1.0;
+      const real mu = mass/length;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="50"  domain="(0.5, 1.0)" transform="dct"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="real">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="2e-3" steps="100">
+      <samples>50 50</samples>
+      <computed_vector name="moment_creator" dimensions="" type="real">
+        <components>moment</components>
+        <evaluation>
+          <dependencies basis="kx"> main </dependencies>
+          <![CDATA[
+            moment = mod2(u);
+          ]]>
+        </evaluation>
+      </computed_vector>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>moment_creator</dependencies>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+          moment;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary" filename="vibstring_dct.xsil">
+      <sampling_group basis="x" initial_sample="yes">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u;
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kx" initial_sample="no">
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u;
+        
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
diff --git a/testsuite/transforms/vibstring_dct_expected.xsil b/testsuite/transforms/vibstring_dct_expected.xsil
new file mode 100644
index 0000000..57ba13b
--- /dev/null
+++ b/testsuite/transforms/vibstring_dct_expected.xsil
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="vibstring_dct.xsil" expected="vibstring_dct_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>vibstring_dct</name>
+  <author>Graham Dennis</author>
+  <description>
+    Vibrating string using a Discrete Cosine transform (i.e. even boundary conditions on both sides)
+  </description>
+  
+  <features>
+    <benchmark />
+    <error_check />
+    <bing />
+    <fftw plan="estimate" />
+    <openmp />
+    <globals>
+      <![CDATA[
+      const double T = 10.0;
+      const double mass = 1e-3;
+      const double length = 1.0;
+      const double mu = mass/length;
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="x" lattice="50"  domain="(0.5, 1.0)" transform="dct"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="main" initial_basis="x" type="double">
+    <components>
+      u uDot
+    </components>
+    <initialisation>
+      <![CDATA[
+        u = exp(-100.0*(x-0.5)*(x-0.5));
+        uDot = 0.0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="2e-3" steps="100">
+      <samples>50 50</samples>
+      <computed_vector name="moment_creator" dimensions="" type="double">
+        <components>moment</components>
+        <evaluation>
+          <dependencies fourier_space="kx"> main </dependencies>
+          <![CDATA[
+            moment = mod2(u);
+          ]]>
+        </evaluation>
+      </computed_vector>
+      <operators>
+        <operator kind="ex" constant="yes">
+          <operator_names>L</operator_names>
+          <![CDATA[
+            L = -T*kx*kx/mu;
+          ]]>
+        </operator>
+        <integration_vectors>main</integration_vectors>
+        <dependencies>moment_creator</dependencies>
+        <![CDATA[
+          du_dt = uDot;
+          duDot_dt = L[u];
+          moment;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="binary" filename="vibstring_dct.xsil">
+      <sampling_group initial_sample="yes">
+        <!-- Any dimension not mentioned is assumed to be in real space and its middle element will be sampled -->
+        <!-- Note that this is different default behaviour to the filter operator. To integrate, put in a dimension -->
+        <!-- with zero lattice points. -->
+        <!-- Note that dimensions can be in any order. Not that I can think of a reason why you would want to do that -->
+        <dimension name="x" lattice="50" fourier_space="no" />
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u;
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="no">
+        <dimension name="x" lattice="50" fourier_space="yes" />
+        <moments>amp</moments>
+        <dependencies>main</dependencies>
+        <![CDATA[
+          amp = u;
+        
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t x amp error_amp 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>51</Dim>
+    <Dim>50</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+vibstring_dct_expected_mg0.dat
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t kx amp error_amp 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>50</Dim>
+    <Dim>50</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Binary" UnsignedLong="uint32" precision="double" Type="Remote" Encoding="LittleEndian"/>
+vibstring_dct_expected_mg1.dat
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/transforms/vibstring_dct_expected_mg0.dat b/testsuite/transforms/vibstring_dct_expected_mg0.dat
new file mode 100644
index 0000000..e7773bc
Binary files /dev/null and b/testsuite/transforms/vibstring_dct_expected_mg0.dat differ
diff --git a/testsuite/transforms/vibstring_dct_expected_mg1.dat b/testsuite/transforms/vibstring_dct_expected_mg1.dat
new file mode 100644
index 0000000..934b36d
Binary files /dev/null and b/testsuite/transforms/vibstring_dct_expected_mg1.dat differ
diff --git a/testsuite/vectors/initialisation_order.xmds b/testsuite/vectors/initialisation_order.xmds
new file mode 100644
index 0000000..ae91d2f
--- /dev/null
+++ b/testsuite/vectors/initialisation_order.xmds
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="initialisation_order.xsil" expected="initialisation_order_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>initialisation_order</name>
+  <author>Graham Dennis</author>
+  <description>
+    1D TW model of the uniform Peaks system. Groundstate finder.
+    Demonstrates a phase-separated BEC groundstate.
+    Note that the initialisation of the 'wavefunction' vector
+    depends on the 'potential' vector having already been evaluated.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <fftw plan="exhaustive" />
+    <globals>
+      <![CDATA[
+      /* physical constants  */
+       const real omegaz = 2*M_PI*55.0;
+       const real omegarho = 2*M_PI*1020.0;
+       const real hbar = 1.05457148e-34;
+       const real M = 4.0026032*1.66053886e-27;
+       const real scatteringLength = 7.51e-9;
+       const real Uint3 = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+       const real Nparticles = 2.0e6;
+       const real mu = pow(15*Nparticles*Uint3*omegarho*omegarho*omegaz/(8.0*M_PI)*pow(M/2,3.0/2.0),2.0/5.0);
+       const real Uint = Uint3*5.0*omegarho*omegarho*M/(4.0*M_PI*mu);
+       const real Uint_hbar = Uint/hbar;
+       const complex miUint_hbar = -i*Uint_hbar;
+       const real otherScatteringLength = 5.56e-9;
+       const real kappa = otherScatteringLength/scatteringLength;
+       const real eta = 0.5;
+       real Delta;
+       const real hbar_M = hbar/M;
+       
+       /* absorbing boundary constants */
+        const real absorbleft = 5.0e4;
+        const real absorbright = 5.0e4;
+        const real widthPerp = 5.0e-6;
+       
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="z" lattice="256"  domain="(-36e-5, 36e-5)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" initial_basis="z" type="complex">
+    <components>V</components>
+    <initialisation>
+      <![CDATA[
+        V = 0.5*M*omegaz*omegaz*z*z;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" initial_basis="z" type="complex">
+    <components>
+      phi1 phi0
+    </components>
+    <initialisation>
+      <dependencies>potential</dependencies>
+      <![CDATA[
+        phi1 = phi0 = 0.0;
+        if (eta*mu - V.Re() > 0.0) {
+          phi1 = sqrt((eta*mu - V.Re())/Uint);
+        }
+        if ((1.0-eta)*mu - V.Re() > 0.0) {
+          phi0 = sqrt(((1.0-eta)*mu - V.Re())/Uint);
+        }
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>N1 N0</components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        N1 = mod2(phi1);
+        N0 = mod2(phi0);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <vector name="normalisation_copy" dimensions="" type="real">
+    <components>N1_copy N0_copy</components>
+    <initialisation>
+      <dependencies>normalisation</dependencies>
+      <![CDATA[
+        N1_copy = N1;
+        N0_copy = N0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <filter>
+      <dependencies>wavefunction normalisation_copy</dependencies>
+      <![CDATA[
+        phi1 *= sqrt(eta*Nparticles/N1_copy);
+        phi0 *= sqrt((1.0-eta)*Nparticles/N0_copy);
+      ]]>
+    </filter>
+    <integrate algorithm="RK4" interval="5.0e-4" steps="500">
+      <samples>50 50</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            phi1 *= sqrt(eta*Nparticles/N1);
+            phi0 *= sqrt((1.0-eta)*Nparticles/N0);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*hbar/M*kz*kz;
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi1_dt = T[phi1] - 1.0/hbar*(V + Uint*(mod2(phi1) + mod2(phi0)) - eta*mu)*phi1;
+          dphi0_dt = T[phi0] - 1.0/hbar*(V + Uint*(mod2(phi1) + kappa*mod2(phi0)) - (1.0-eta)*mu)*phi0;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="hdf5">
+      <sampling_group basis="z" initial_sample="yes">
+        <moments>dens1 dens0</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens1 = mod2(phi1);
+          dens0 = mod2(phi0);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kz" initial_sample="yes">
+        <moments>dens1 dens0</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens1 = mod2(phi1);
+          dens0 = mod2(phi0);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/vectors/initialisation_order_chunked.xmds b/testsuite/vectors/initialisation_order_chunked.xmds
new file mode 100644
index 0000000..81de869
--- /dev/null
+++ b/testsuite/vectors/initialisation_order_chunked.xmds
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="initialisation_order_chunked.xsil" expected="initialisation_order_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>initialisation_order_chunked</name>
+  <author>Graham Dennis</author>
+  <description>
+    1D TW model of the uniform Peaks system. Groundstate finder.
+    Demonstrates a phase-separated BEC groundstate.
+    Note that the initialisation of the 'wavefunction' vector
+    depends on the 'potential' vector having already been evaluated.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <chunked_output size="100KB" />
+    <fftw plan="exhaustive" />
+    <globals>
+      <![CDATA[
+      /* physical constants  */
+       const real omegaz = 2*M_PI*55.0;
+       const real omegarho = 2*M_PI*1020.0;
+       const real hbar = 1.05457148e-34;
+       const real M = 4.0026032*1.66053886e-27;
+       const real scatteringLength = 7.51e-9;
+       const real Uint3 = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+       const real Nparticles = 2.0e6;
+       const real mu = pow(15*Nparticles*Uint3*omegarho*omegarho*omegaz/(8.0*M_PI)*pow(M/2,3.0/2.0),2.0/5.0);
+       const real Uint = Uint3*5.0*omegarho*omegarho*M/(4.0*M_PI*mu);
+       const real Uint_hbar = Uint/hbar;
+       const complex miUint_hbar = -i*Uint_hbar;
+       const real otherScatteringLength = 5.56e-9;
+       const real kappa = otherScatteringLength/scatteringLength;
+       const real eta = 0.5;
+       real Delta;
+       const real hbar_M = hbar/M;
+       
+       /* absorbing boundary constants */
+        const real absorbleft = 5.0e4;
+        const real absorbright = 5.0e4;
+        const real widthPerp = 5.0e-6;
+       
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="z" lattice="256"  domain="(-36e-5, 36e-5)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" initial_basis="z" type="complex">
+    <components>V</components>
+    <initialisation>
+      <![CDATA[
+        V = 0.5*M*omegaz*omegaz*z*z;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" initial_basis="z" type="complex">
+    <components>
+      phi1 phi0
+    </components>
+    <initialisation>
+      <dependencies>potential</dependencies>
+      <![CDATA[
+        phi1 = phi0 = 0.0;
+        if (eta*mu - V.Re() > 0.0) {
+          phi1 = sqrt((eta*mu - V.Re())/Uint);
+        }
+        if ((1.0-eta)*mu - V.Re() > 0.0) {
+          phi0 = sqrt(((1.0-eta)*mu - V.Re())/Uint);
+        }
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>N1 N0</components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        N1 = mod2(phi1);
+        N0 = mod2(phi0);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <vector name="normalisation_copy" dimensions="" type="real">
+    <components>N1_copy N0_copy</components>
+    <initialisation>
+      <dependencies>normalisation</dependencies>
+      <![CDATA[
+        N1_copy = N1;
+        N0_copy = N0;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <sequence>
+    <filter>
+      <dependencies>wavefunction normalisation_copy</dependencies>
+      <![CDATA[
+        phi1 *= sqrt(eta*Nparticles/N1_copy);
+        phi0 *= sqrt((1.0-eta)*Nparticles/N0_copy);
+      ]]>
+    </filter>
+    <integrate algorithm="RK4" interval="5.0e-4" steps="500">
+      <samples>50 50</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            phi1 *= sqrt(eta*Nparticles/N1);
+            phi0 *= sqrt((1.0-eta)*Nparticles/N0);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*hbar/M*kz*kz;
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi1_dt = T[phi1] - 1.0/hbar*(V + Uint*(mod2(phi1) + mod2(phi0)) - eta*mu)*phi1;
+          dphi0_dt = T[phi0] - 1.0/hbar*(V + Uint*(mod2(phi1) + kappa*mod2(phi0)) - (1.0-eta)*mu)*phi0;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="hdf5">
+      <sampling_group basis="z" initial_sample="yes">
+        <moments>dens1 dens0</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens1 = mod2(phi1);
+          dens0 = mod2(phi0);
+        ]]>
+      </sampling_group>
+      <sampling_group basis="kz" initial_sample="yes">
+        <moments>dens1 dens0</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens1 = mod2(phi1);
+          dens0 = mod2(phi0);
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/testsuite/vectors/initialisation_order_expected.h5 b/testsuite/vectors/initialisation_order_expected.h5
new file mode 100644
index 0000000..b131dd0
Binary files /dev/null and b/testsuite/vectors/initialisation_order_expected.h5 differ
diff --git a/testsuite/vectors/initialisation_order_expected.xsil b/testsuite/vectors/initialisation_order_expected.xsil
new file mode 100644
index 0000000..95ed302
--- /dev/null
+++ b/testsuite/vectors/initialisation_order_expected.xsil
@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="initialisation_order.xsil" expected="initialisation_order_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>initialisation_order</name>
+  <author>Graham Dennis</author>
+  <description>
+    1D TW model of the uniform Peaks system. Groundstate finder.
+    Demonstrates a phase-separated BEC groundstate.
+    Note that the initialisation of the 'wavefunction' vector
+    depends on the 'potential' vector having already been evaluated.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <fftw plan="exhaustive" />
+    <globals>
+      <![CDATA[
+      /* physical constants  */
+       const double omegaz = 2*M_PI*55.0;
+       const double omegarho = 2*M_PI*1020.0;
+       const double hbar = 1.05457148e-34;
+       const double M = 4.0026032*1.66053886e-27;
+       const double scatteringLength = 7.51e-9;
+       const double Uint3 = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+       const double Nparticles = 2.0e6;
+       const double mu = pow(15*Nparticles*Uint3*omegarho*omegarho*omegaz/(8.0*M_PI)*pow(M/2,3.0/2.0),2.0/5.0);
+       const double Uint = Uint3*5.0*omegarho*omegarho*M/(4.0*M_PI*mu);
+       const double Uint_hbar = Uint/hbar;
+       const complex miUint_hbar = -i*Uint_hbar;
+       const double otherScatteringLength = 5.56e-9;
+       const double kappa = otherScatteringLength/scatteringLength;
+       const double eta = 0.5;
+       double Delta;
+       const double hbar_M = hbar/M;
+       
+       /* absorbing boundary constants */
+        const double absorbleft = 5.0e4;
+        const double absorbright = 5.0e4;
+        const double widthPerp = 5.0e-6;
+       
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="z" lattice="256"  domain="(-36e-5, 36e-5)" />
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" initial_basis="z" type="complex">
+    <components>V</components>
+    <initialisation>
+      <![CDATA[
+        V = 0.5*M*omegaz*omegaz*z*z;
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" initial_basis="z" type="complex">
+    <components>
+      phi1 phi0
+    </components>
+    <initialisation>
+      <dependencies>potential</dependencies>
+      <![CDATA[
+        phi1 = phi0 = 0.0;
+        if (eta*mu - V.re > 0.0) {
+          phi1 = sqrt((eta*mu - V.re)/Uint);
+        }
+        if ((1.0-eta)*mu - V.re > 0.0) {
+          phi0 = sqrt(((1.0-eta)*mu - V.re)/Uint);
+        }
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="double">
+    <components>N1 N0</components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        N1 = mod2(phi1);
+        N0 = mod2(phi0);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <filter>
+      <dependencies>wavefunction normalisation</dependencies>
+      <![CDATA[
+        phi1 *= sqrt(eta*Nparticles/N1);
+        phi0 *= sqrt((1.0-eta)*Nparticles/N0);
+      ]]>
+    </filter>
+    <integrate algorithm="RK4" interval="5.0e-4" steps="500">
+      <samples>50 50</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation</dependencies>
+          <![CDATA[
+            phi1 *= sqrt(eta*Nparticles/N1);
+            phi0 *= sqrt((1.0-eta)*Nparticles/N0);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*hbar/M*kz*kz;
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi1_dt = T[phi1] - 1.0/hbar*(V + Uint*(mod2(phi1) + mod2(phi0)) - eta*mu)*phi1;
+          dphi0_dt = T[phi0] - 1.0/hbar*(V + Uint*(mod2(phi1) + kappa*mod2(phi0)) - (1.0-eta)*mu)*phi0;
+        ]]>
+      </operators>
+    </integrate>
+  </sequence>
+  <output format="hdf5">
+      <sampling_group initial_sample="yes">
+        <dimension name="z" />
+        <moments>dens1 dens0</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens1 = mod2(phi1);
+          dens0 = mod2(phi0);
+        ]]>
+      </sampling_group>
+      <sampling_group initial_sample="yes">
+        <dimension name="z" fourier_space="yes" />
+        <moments>dens1 dens0</moments>
+        <dependencies>wavefunction</dependencies>
+        <![CDATA[
+          dens1 = mod2(phi1);
+          dens0 = mod2(phi0);
+        ]]>
+      </sampling_group>
+  </output>
+
+<info>
+Script compiled with xpdeint version VERSION_PLACEHOLDER (SUBVERSION_REVISION_PLACEHOLDER)
+See http://www.xmds.org for more information.
+</info>
+
+<XSIL Name="moment_group_1">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t z dens1 dens0 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>51</Dim>
+    <Dim>256</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/1"/>
+initialisation_order_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+
+<XSIL Name="moment_group_2">
+  <Param Name="n_independent">2</Param>
+  <Array Name="variables" Type="Text">
+    <Dim>4</Dim>
+    <Stream><Metalink Format="Text" Delimiter=" \n"/>
+t kz dens1 dens0 
+    </Stream>
+  </Array>
+  <Array Name="data" Type="double">
+    <Dim>51</Dim>
+    <Dim>256</Dim>
+    <Dim>4</Dim>
+    <Stream><Metalink Format="HDF5" Type="Remote" Group="/2"/>
+initialisation_order_expected.h5
+    </Stream>
+  </Array>
+</XSIL>
+</simulation>
diff --git a/testsuite/vectors/partial_integration_computed_vector.xmds b/testsuite/vectors/partial_integration_computed_vector.xmds
new file mode 100644
index 0000000..0561cbe
--- /dev/null
+++ b/testsuite/vectors/partial_integration_computed_vector.xmds
@@ -0,0 +1,176 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<simulation xmds-version="2">
+  <testing>
+    <xsil_file name="partial_integration_computed_vector.xsil" expected="../fast/bessel_cosine_groundstate_expected.xsil" absolute_tolerance="1e-7" relative_tolerance="1e-5" />
+    <xsil_file name="partial_integration_computed_vector_breakpoint.xsil" expected="../fast/bessel_cosine_groundstate_breakpoint_expected.xsil" absolute_tolerance="1e0" relative_tolerance="1e-5" />
+  </testing>
+  
+  <name>partial_integration_computed_vector</name>
+  <author>Graham Dennis</author>
+  <description>
+    Calculate the 3D ground state of a Rubidium BEC in a harmonic magnetic trap assuming
+    cylindrical symmetry about the z axis and reflection symmetry about z=0.
+    This permits us to use the cylindrical bessel functions to expand the solution transverse
+    to z and a cosine series to expand the solution along z.
+    
+    This testcase tests using both Fourier transforms and Matrix transforms in a single simulation.
+  </description>
+  
+  <features>
+    <auto_vectorise />
+    <benchmark />
+    <bing />
+    <globals>
+      <![CDATA[
+        const real omegaz = 2*M_PI*20;
+        const real omegarho = 2*M_PI*200;
+        const real hbar = 1.05457148e-34;
+        const real M = 1.409539200000000e-25;
+        const real g = 9.8;
+        const real scatteringLength = 5.57e-9;
+        const real Uint = 4.0*M_PI*hbar*hbar*scatteringLength/M;
+        const real Nparticles = 5.0e5;
+
+        /* offset constants */
+        const real EnergyOffset = pow(15.0*Nparticles*Uint*omegaz*omegarho*omegarho/(8*M_PI), 2.0/5.0)
+                                    * pow(M/2.0, 3.0/5.0);
+
+      ]]>
+    </globals>
+  </features>
+  
+  <geometry>
+    <propagation_dimension> t </propagation_dimension>
+    <transverse_dimensions>
+      <dimension name="z" lattice="32"  domain="(0.0, 1.0e-4)" transform="dct" volume_prefactor="2.0" />
+      <dimension name="r" lattice="32"  domain="(0.0, 1.0e-5)" transform="bessel" volume_prefactor="2.0*M_PI"/>
+    </transverse_dimensions>
+  </geometry>
+  
+  <vector name="potential" type="complex">
+    <components>
+      V1
+    </components>
+    <initialisation>
+      <![CDATA[
+        real Vtrap = 0.5*M*(omegarho*omegarho*r*r + omegaz*omegaz*z*z);
+      
+        V1  = -i/hbar*(Vtrap - EnergyOffset);
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <vector name="wavefunction" type="complex">
+    <components>
+      phi
+    </components>
+    <initialisation>
+      <![CDATA[
+      
+        if ((abs(r) < 0.9e-5) && abs(z) < 0.9e-4) {
+          phi = 1.0; //sqrt(Nparticles/2.0e-5);
+          // This will be automatically normalised later
+        } else {
+          phi = 0.0;
+        }
+      
+      ]]>
+    </initialisation>
+  </vector>
+  
+  <computed_vector name="partial_r" dimensions="r" type="real">
+      <components>Nr</components>
+      <evaluation>
+          <dependencies>wavefunction</dependencies>
+          <![CDATA[
+                  Nr = mod2(phi);
+          ]]>
+      </evaluation>
+  </computed_vector>
+
+  <computed_vector name="partial_z" dimensions="z" type="real">
+      <components>Nz</components>
+      <evaluation>
+          <dependencies>wavefunction</dependencies>
+          <![CDATA[
+                  Nz = mod2(phi);
+          ]]>
+      </evaluation>
+  </computed_vector>
+  
+  <computed_vector name="norm_r" dimensions="" type="real">
+      <components>NcalcR</components>
+      <evaluation>
+          <dependencies>partial_r</dependencies>
+          <![CDATA[
+                      NcalcR = Nr;
+          ]]>
+      </evaluation>
+  </computed_vector>
+  
+  <computed_vector name="norm_z" dimensions="" type="real">
+      <components>NcalcZ</components>
+      <evaluation>
+          <dependencies>partial_z</dependencies>
+          <![CDATA[
+                      NcalcZ = Nz;
+        ]]>
+      </evaluation>
+  </computed_vector>
+  
+  <computed_vector name="normalisation" dimensions="" type="real">
+    <components>
+      Ncalc
+    </components>
+    <evaluation>
+      <dependencies>wavefunction</dependencies>
+      <![CDATA[
+        // Calculate the current normalisation of the wave function.
+        Ncalc = mod2(phi);
+      ]]>
+    </evaluation>
+  </computed_vector>
+  
+  <sequence>
+    <integrate algorithm="RK4" interval="1e-4" steps="1000">
+      <samples>100</samples>
+      <filters>
+        <filter>
+          <dependencies>wavefunction normalisation norm_r norm_z</dependencies>
+          <![CDATA[
+            // Correct normalisation of the wavefunction
+                  real mean_number = (Ncalc + NcalcR + NcalcZ)/3.0;
+            phi *= sqrt(Nparticles/mean_number);
+          ]]>
+        </filter>
+      </filters>
+      <operators>
+        <operator kind="ip" constant="yes">
+          <operator_names>T</operator_names>
+          <![CDATA[
+            T = -0.5*hbar/M*(kr*kr + kz*kz);
+          ]]>
+        </operator>
+        <integration_vectors>wavefunction</integration_vectors>
+        <dependencies>potential</dependencies>
+        <![CDATA[
+          dphi_dt = T[phi] - (i*V1 + Uint/hbar*mod2(phi))*phi;
+        ]]>
+      </operators>
+    </integrate>
+    <breakpoint filename="partial_integration_computed_vector_breakpoint.xsil" format="hdf5">
+      <dependencies>wavefunction</dependencies>
+    </breakpoint>
+  </sequence>
+  <output format="binary">
+      <sampling_group basis="r z" initial_sample="no">
+        <moments>norm_dens</moments>
+        <dependencies>wavefunction normalisation norm_r norm_z</dependencies>
+        <![CDATA[
+                    real mean_number = (Ncalc + NcalcR + NcalcZ)/3.0;
+          norm_dens = mod2(phi)/mean_number;
+        ]]>
+      </sampling_group>
+  </output>
+</simulation>
\ No newline at end of file
diff --git a/xpdeint/CallOnceGuards.py b/xpdeint/CallOnceGuards.py
new file mode 100644
index 0000000..7a12e68
--- /dev/null
+++ b/xpdeint/CallOnceGuards.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+CallOnceGuards.py
+
+Created by Graham Dennis on 2007-12-14.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+These function decorators are used to ensure that certain functions are only called
+once during the generation of the simulation script. One example where these are used
+is segment (e.g. an integrator) initialisation. If a segment is called multiple times
+in a simulation, then it would be a good idea to perform all initialisation of the 
+segment that doesn't change between invocations only once. A segment might be called
+multiple times when we are performing a multi-path simulation, or if the segment
+exists inside of a sequence that is looping.
+
+One easy way to implement this optimisation is for anything that might be doing the looping
+(which must be further up the call tree than the segment that is being looped over) to call
+the initialisation code for the segment before the loop. To prevent the segment writing its
+own initialisation code in the normal segment routine, there needs to be a way to prevent the
+segment including this code. We could add flags for each of these functions, but it could be
+quite easy to forget. Using function decorators, we can wrap the function that we only want
+to execute once to check the value of a flag to see if it has executed before and return an
+empty string if it has, but to execute and change the value of the flag if it hasn't. This way
+the checking of the flag is built into the execution of the function itself.
+
+As our 'preflight' stage of the simulation now includes a 'dry-run' stage that does a preliminary
+conversion of the simulation classes to a C++ source file, we will need to be able to reset these
+flags after the execution of the dry-run so that functions that were called during the dry-run do
+not prevent those same functions being called during the actual conversion of the simulation
+classes to the C++ source file. To achieve this, `_ScriptElement` has a `resetGuards` method that
+resets all of the CallOnceGuards.
+
+To use a CallOnceGuard, import this file into the Cheetah template or Python source file and then
+use the decorator syntax (in Python)::
+
+  @callOnceGuard
+  def someFunction(self):
+    doSomeStuff
+    
+    return "thingy"
+  
+Or in a Cheetah template::
+
+  @@callOnceGuard
+  @def someOtherFunction($someArgument)
+    @# Put stuff here
+  @end def
+
+There are two function decorators provided by this module, `callOnceGuard` and `callOncePerInstanceGuard`.
+The first, `callOnceGuard` prevents a function being called more than once, even if the call is made
+on a different instance. This is useful for example for ensuring that a header has been ``#include``'ed
+that might be required by multiple instances of a given class (e.g. the MKL noises). The second decorator,
+`callOncePerInstanceGuard` is useful when you want a function to only be called once for a given instance.
+This is useful in the example given above where a segment should only be initialised once.
+"""
+
+from functools import wraps
+from xpdeint._ScriptElement import _ScriptElement
+
+
+def callOnceGuard(f):
+  """Function decorator to prevent a function being called more than once."""
+  @wraps(f)
+  def wrapper(*args, **KWs):
+    # If the function object isn't in the guard set, then add it and run the function
+    if not f in _ScriptElement._callOnceGuards:
+      _ScriptElement._callOnceGuards.add(f)
+      return f(*args, **KWs)
+    else:
+      return ''
+  
+  return wrapper
+
+
+def callOncePerInstanceGuard(f):
+  """Function decorator to prevent a function being called more than once for each instance."""
+  @wraps(f)
+  def wrapper(self, *args, **KWs):
+    # If the guard name isn't in the guard set for this instance, then add it and run the function
+    if not f in _ScriptElement._callOncePerInstanceGuards[self]:
+      _ScriptElement._callOncePerInstanceGuards[self].add(f)
+      return f(self, *args, **KWs)
+    else:
+      return ''
+  
+  return wrapper
+
diff --git a/xpdeint/CheetahTemplateOptions.mk b/xpdeint/CheetahTemplateOptions.mk
new file mode 100644
index 0000000..403a42c
--- /dev/null
+++ b/xpdeint/CheetahTemplateOptions.mk
@@ -0,0 +1 @@
+cheetah_settings = directiveStartToken="@",commentStartToken="@\#",multiLineCommentStartToken="@*",multiLineCommentEndToken="*@"
diff --git a/xpdeint/CodeParser.py b/xpdeint/CodeParser.py
new file mode 100755
index 0000000..b358fcc
--- /dev/null
+++ b/xpdeint/CodeParser.py
@@ -0,0 +1,648 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+CodeParser.py
+
+Created by Graham Dennis on 2009-06-27.
+
+Copyright (c) 2009-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+The purpose of this module is to facilitate better understanding of user
+code blocks by breaking the code up into Tokens (strings of text with an
+associated meaning) and using this as the basis for all code modification.
+We need to modify user code in a number of situations, the most obvious being
+IP and EX operators where an expression like 'L[u]' in 'du_dt = L[u];' must be 
+found and replaced with some other string. The trouble with using regular
+expressions is that they would also match inside comments, string constants,
+and so giving the user different results to what they were expecting.
+"""
+
+from pyparsing import \
+        Word, alphas, alphanums, Regex, cppStyleComment, quotedString, Forward, \
+        nestedExpr, OneOrMore, Suppress, oneOf, Keyword, Dict, Group, ZeroOrMore, \
+        delimitedList, originalTextFor, Empty, opAssoc, \
+        ParserElement, Optional, lineno, col, MatchFirst, Literal
+
+ParserElement.enablePackrat()
+
+import unittest
+
+from xpdeint.ParserException import ParserException, parserWarning
+
+class CodeParserException(ParserException):
+    """
+    A class for exceptions thrown by the C++ code parser.
+    This class determines the line in the original script that
+    corresponds to the part of the code block that triggered the
+    exception.
+    """
+    def __init__(self, codeBlock, codeIndex, msg):
+        ParserException.__init__(self, codeBlock.xmlElement, msg)
+        
+        self.columnNumber = col(codeIndex, codeBlock.codeString)
+        self.lineNumber = codeBlock.scriptLineNumber + lineno(codeIndex, codeBlock.codeString)-1
+    
+
+
+identifier = Word(alphas + '_', alphanums + '_')
+numericConstant = Regex(r'\b((0(x|X)[0-9a-fA-F]*)|(([0-9]+\.?[0-9]*)|(\.[0-9]+))((e|E)(\+|-)?[0-9]+)?)(L|l|UL|ul|u|U|F|f|ll|LL|ull|ULL)?\b')
+
+ignoreExpr = cppStyleComment.copy() | quotedString.copy()
+
+baseExpr = Forward()
+
+arrayAccess = originalTextFor(nestedExpr('[', ']', baseExpr, ignoreExpr))
+parenthisedExpression = originalTextFor(nestedExpr('(', ')', baseExpr, ignoreExpr))
+functionCall = nestedExpr('(', ')', delimitedList(baseExpr), ignoreExpr)
+alphaNumPlusSafePunctuation = alphanums + '!#$%&\\*+-./:;<=>@^_`{|}~'
+
+baseExpr << OneOrMore(originalTextFor(identifier + functionCall) | quotedString.copy() \
+                | identifier | numericConstant | arrayAccess | parenthisedExpression \
+                | Word(alphaNumPlusSafePunctuation))
+baseExpr.ignore(cppStyleComment.copy())
+
+
+def targetComponentsForOperatorsInString(operatorNames, codeBlock):
+    """
+    Return a list of pairs of operator names and their targets that are in `codeString`.
+    The valid operator names searched for are `operatorNames`. For example, if 'L' is in `operatorNames`,
+    then in the code ``L[phi]`` the return value would be ``('L', 'phi', slice(firstCharacterIndex, lastCharacterIndex))``.
+    """
+    parser = MatchFirst(Keyword(operatorName) for operatorName in operatorNames).setResultsName('name') \
+                + Optional(nestedExpr('[', ']', baseExpr, ignoreExpr).setResultsName('target'))
+    parser.ignore(cppStyleComment.copy())
+    parser.ignore(quotedString.copy())
+    results = []
+    for tokens, start, end in parser.scanString(codeBlock.codeString):
+        if 'target' in tokens:
+            results.append((tokens.name, ''.join(tokens.target.asList()[0]), slice(start, end)))
+        else:
+            raise CodeParserException(codeBlock, start, "Invalid use of '%s' operator in code block." % tokens.name)
+    return results
+
+def sliceFor(expr):
+    """
+    Helper to add a slice object to the ParseResults with name 'slice' which is the
+    slice of the original string that these results correspond to.
+    """
+    locMarker = Empty().setParseAction(lambda s, loc, t: loc)
+    matchExpr = locMarker("_original_start") + expr + locMarker("_original_end")
+    def makeSlice(s, l, t):
+        t["slice"] = slice(t["_original_start"], t["_original_end"])
+        # Clean up the loc markers added above
+        del t[0]
+        del t[-1]
+        del t["_original_start"]
+        del t["_original_end"]
+    matchExpr.setParseAction(makeSlice)
+    return matchExpr
+
+def nonlocalDimensionAccessForVectors(vectors, codeBlock):
+    """
+    Find all places in the `codeBlock` where any components of any of the `vectors`
+    are accessed non-locally (usually by integer-valued dimensions) and return a ``(componentName, vector, resultDict, codeSlice)``
+    tuple for each such occurrence. ``codeSlice`` is the character range over which this expression occurs,
+    and ``resultDict`` is a dictionary describing how each dimension is accessed. See `nonlocalDimensionAccessForField`
+    for more information about ``resultDict``.
+    """
+    componentNameToVectorMap = {}
+    for v in vectors:
+        componentNameToVectorMap.update(dict.fromkeys(v.components, v))
+    result = nonlocalDimensionAccessForComponents(componentNameToVectorMap.keys(), codeBlock)
+    return [(componentName, componentNameToVectorMap[componentName], resultDict, codeSlice) \
+                for componentName, resultDict, codeSlice in result]
+
+def nonlocalDimensionAccessForComponents(components, codeBlock):
+    """
+    Find all places in the `codeBlock` where any of `components` are accessed with
+    non-locally (usually integer-valued dimensions) and return a ``(componentName, resultDict, codeSlice)``
+    tuple for each such occurrence. The companion of `nonlocalDimensionAccessForVectors` and
+    to be used when `components` are components of vectors.
+    """
+    
+    # Optimise for the common case: if the code doesn't contain the string "=>", then we know it doesn't have any nonlocal access
+    if "=>" not in codeBlock.codeString:
+        return []
+    
+    dictionaryElement = identifier + Suppress('=>') + sliceFor(Group(baseExpr))
+    nonlocalAccessDictParser = Dict(
+        ZeroOrMore(Group(dictionaryElement + Suppress(','))) + Group(dictionaryElement)
+    )
+    parser = identifier.setResultsName('name') \
+                + nestedExpr('(', ')', nonlocalAccessDictParser, ignoreExpr).setResultsName('access')
+    parser.ignore(cppStyleComment.copy())
+    parser.ignore(quotedString.copy())
+    results = []
+    
+    for tokens, start, end in parser.scanString(codeBlock.codeString):
+        if tokens.name not in components: continue
+        accessDict = {}
+        tokenDict = tokens.access[0].asDict()
+        for key, value in tokenDict.items():
+            accessDict[key] = (' '.join(value[0].asList()), value.slice.start)
+        results.append((tokens.name, accessDict, slice(start, end)))
+    return results
+
+def checkForIntegerDivision(codeBlock):
+    """
+    Raise a CodeParserException if the code contains what looks like an integer division.
+    i.e. ``9/2`` or the like. This is because the user is likely to get unexpected results.
+    The most notorious example of this is ``1/2`` which evaluates to zero.
+    """
+    parser = numericConstant.setResultsName('numerator') + '/' + numericConstant.setResultsName('denominator')
+    parser.ignore(cppStyleComment.copy())
+    parser.ignore(quotedString.copy())
+    for tokens, start, end in parser.scanString(codeBlock.codeString):
+        if tokens.numerator.isdigit() and tokens.denominator.isdigit():
+            raise CodeParserException(
+                codeBlock, start,
+                "It looks like you are trying to divide two integers.\n"
+                "One of the oddities of the C language is that the result of such an expression\n"
+                "is the floor of that division instead of the real value.\n"
+                "For example '1/2' would give '0' instead of '0.5'.\n"
+                "The way to fix this is to turn one or both of the integers into real numbers\n"
+                "by adding a decimal point. For example, '1/2' should be written as '1.0/2.0'.\n\n"
+                "If you feel this warning is given in error, send an email to xmds-devel at lists.sourceforge.net"
+            )
+    
+
+# The following code is stolen from pyparsing with optimisations made for our case.
+def operatorPrecedence( baseExpr, opList ):
+    """Helper method for constructing grammars of expressions made up of
+       operators working in a precedence hierarchy.  Operators may be unary or
+       binary, left- or right-associative.  Parse actions can also be attached
+       to operator expressions.
+       
+       Parameters:
+        - baseExpr - expression representing the most basic element for the nested
+        - opList - list of tuples, one for each operator precedence level in the
+          expression grammar; each tuple is of the form
+          (opExpr, numTerms, rightLeftAssoc, parseAction), where:
+           - opExpr is the pyparsing expression for the operator;
+              may also be a string, which will be converted to a Literal;
+              if numTerms is 3, opExpr is a tuple of two expressions, for the
+              two operators separating the 3 terms
+           - numTerms is the number of terms for this operator (must
+              be 1, 2, or 3)
+           - rightLeftAssoc is the indicator whether the operator is
+              right or left associative, using the pyparsing-defined
+              constants opAssoc.RIGHT and opAssoc.LEFT.
+           - parseAction is the parse action to be associated with
+              expressions matching this operator expression (the
+              parse action tuple member may be omitted)
+    """
+    ret = Forward()
+    lastExpr = baseExpr | ( Suppress('(') + ret + Suppress(')') )
+    for i,operDef in enumerate(opList):
+        opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4]
+        if arity == 3:
+            if opExpr is None or len(opExpr) != 2:
+                raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions")
+            opExpr1, opExpr2 = opExpr
+        thisExpr = Forward()#.setName("expr%d" % i)
+        if rightLeftAssoc == opAssoc.LEFT:
+            if arity == 1:
+                matchExpr = Group( lastExpr + OneOrMore( opExpr ) )
+            elif arity == 2:
+                if opExpr is not None:
+                    matchExpr = Group( lastExpr + OneOrMore( opExpr + lastExpr ) )
+                else:
+                    matchExpr = Group( lastExpr + OneOrMore(lastExpr) )
+            elif arity == 3:
+                matchExpr = Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr )
+            else:
+                raise ValueError("operator must be unary (1), binary (2), or ternary (3)")
+        elif rightLeftAssoc == opAssoc.RIGHT:
+            if arity == 1:
+                matchExpr = Group( OneOrMore(opExpr) + thisExpr )
+            elif arity == 2:
+                if opExpr is not None:
+                    matchExpr = Group( lastExpr + OneOrMore( opExpr + thisExpr ) )
+                else:
+                    matchExpr = Group( lastExpr + OneOrMore( thisExpr ) )
+            elif arity == 3:
+                matchExpr = Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr )
+            else:
+                raise ValueError("operator must be unary (1), binary (2), or ternary (3)")
+        else:
+            raise ValueError("operator must indicate right or left associativity")
+        if pa:
+            matchExpr.setParseAction( pa )
+        thisExpr << ( matchExpr | lastExpr )
+        lastExpr = thisExpr
+    ret << lastExpr
+    return ret
+
+def performIPOperatorSanityCheck(componentName, propagationDimension, operatorCodeSlice, codeBlock):
+    """
+    Check that the user hasn't tried to use an IP operator where an IP operator cannot be used.
+    
+    IP operators must be diagonal, so one cannot have expressions of the form ``dy_dt = L[x];`` for IP operators.
+    This is valid for EX operators, but not for IP. This is a common mistake for users to make, and so we should
+    do our best to spot it and report the error. Another mistake users make is trying to multiply the operator,
+    for example ``dy_dt = i*L[y];``. This code does a sophisticated validation by constructing a parse tree for
+    each statement in the code taking into account operator precedence. This sanity checking is even able to pick
+    up problems such as ``dphi_dt = i*(V*phi + U*mod2(phi)*phi + T[phi]);``.
+    If the user's code passes this test, then it is a reasonable assumption that they are using IP operators safely.
+    """
+    
+    operatorString = codeBlock.codeString[operatorCodeSlice]
+    
+    expr = Forward()
+    
+    operatorKeyword = Keyword(operatorString).setResultsName('targetOperator')
+    
+    operand = operatorKeyword \
+                | (identifier + Group('(' + delimitedList(expr) + ')')) \
+                | (identifier + Group(OneOrMore('[' + expr + ']'))) \
+                | quotedString.copy() \
+                | identifier \
+                | numericConstant
+    operand.ignore(cppStyleComment.copy())
+    
+    expr << operatorPrecedence(
+        operand,
+        [
+            (oneOf('++ --'), 1, opAssoc.LEFT),
+            (oneOf('. ->'), 2, opAssoc.LEFT),
+            (~oneOf('-> -= += *= &= |=') + oneOf('+ - ! ~ * & ++ --'), 1, opAssoc.RIGHT),
+            (~oneOf('*= /= %=') + oneOf('* / %'), 2, opAssoc.LEFT),
+            (~oneOf('++ -- -> -= +=') + oneOf('+ -'), 2, opAssoc.LEFT),
+# Although the operators below don't all have the same precedence, as we don't actually
+# care about them as they are all invalid uses of the IP operator, we can cheat and lump
+# them together
+            (~oneOf('<<= >>= &= |=') + oneOf('<< >> < <= > >= == != & ^ | && ||'), 2, opAssoc.LEFT),
+# Correct ordering
+            # (~oneOf('<<= >>=') + oneOf('<< >>'), 2, opAssoc.LEFT),
+            # (~oneOf('<< >> <<= >>=') + oneOf('< <= > >='), 2, opAssoc.LEFT),
+            # (oneOf('== !='), 2, opAssoc.LEFT),
+            # (~oneOf('&& &=') + '&', 2, opAssoc.LEFT),
+            # ('^', 2, opAssoc.LEFT),
+            # (~oneOf('|| |=') + '|', 2, opAssoc.LEFT),
+            # ('&&', 2, opAssoc.LEFT),
+            # ('||', 2, opAssoc.LEFT),
+            (('?',':'), 3, opAssoc.RIGHT),
+            (~Literal('==') + oneOf('= += -= *= /= %= <<= >>= &= ^= |= =>'), 2, opAssoc.RIGHT),
+            (',', 2, opAssoc.LEFT),
+        ]
+    )
+    expr.ignore(cppStyleComment.copy())
+    
+    statement = expr + Suppress(';')
+    
+    stack = []
+    expectedAssignmentVariable = 'd%(componentName)s_d%(propagationDimension)s' % locals()
+    
+    def validateStack():
+        """
+        It is the job of this function to validate the operations that the located operator is involved in.
+        The stack describes the part of the parse tree in which the operator was found. The first element in the stack
+        is the outermost operation, and the last the innermost. The last element is guaranteed to be the operator itself.
+        """
+        # Reverse the stack as we want to search the parse tree from inner-most expression to outer-most.
+        stack.reverse()
+        assignmentHit = False
+        errorMessageCommon = "Due to the way IP operators work, they can only contribute to the derivative of the variable " \
+            "they act on, i.e. dx_dt = L[x]; not dy_dt = L[x];\n\n"
+        
+        # We don't need to check the first element of the stack
+        # as we are guaranteed that it is the operator itself. This will be useful for determining
+        # which part of the parse tree we should be looking at.
+        for idx, node in enumerate(stack[1:]):
+            if len(node) == 1: continue
+            # idx is the index in the stack of the next element *deeper* in the parse tree.
+            previousStackEntry = stack[idx]
+            if not isinstance(stack[idx], basestring):
+                previousStackEntry = previousStackEntry.asList()
+            binaryOpIdx = node.asList().index(previousStackEntry) - 1
+            if binaryOpIdx < 0: binaryOpIdx = 1
+            # Unary '+' is safe.
+            if node[0] == '+': continue
+            # Binary '+' is safe.
+            if node[binaryOpIdx] == '+': continue
+            # Binary '-' is safe if the operator is the first argument.
+            if node[binaryOpIdx] == '-' and node.asList().index(previousStackEntry) == 0: continue
+            # Assignment is safe if it there is only one, and if it's to the right variable
+            if node[binaryOpIdx] in ['=', '+=']:
+                if node[0] == expectedAssignmentVariable:
+                    assignmentHit = True
+                    continue
+                else:
+                    return errorMessageCommon + "In this case, you should probably use an EX operator instead of an "\
+                            "IP operator."
+            else:
+                return errorMessageCommon + "You appear to be using the IP operator in an unsafe operation. " \
+                        "The most likely cause is trying to multiply it by something, e.g. dphi_dt = 0.5*L[phi]; "\
+                        "If this is the cause and you are multiplying by a constant, just move the constant into the "\
+                        "definition of the operator itself. i.e. L = -0.5*kx*kx; If you are multiplying by something "\
+                        "that isn't constant e.g. dphi_dt = x*L[phi]; where x is a dimension, you must use an EX operator "\
+                        "instead."
+        if not assignmentHit:
+            return errorMessageCommon + "You appear to be missing the assignment for this particular operator."
+        return True
+    
+    class FoundTargetException(Exception): pass
+    
+    def findOperatorInParseTree(results):
+        stack.append(results)
+        if 'targetOperator' in results:
+            stack.append(results.targetOperator)
+            raise FoundTargetException()
+        for item in results:
+            if isinstance(item, basestring): continue
+            findOperatorInParseTree(item)
+        del stack[-1]
+    
+    try:
+        foundOperator = False
+        for tokens, start, end in statement.scanString(codeBlock.codeString):
+            if start > operatorCodeSlice.stop or end < operatorCodeSlice.start: continue
+            try:
+                findOperatorInParseTree(tokens)
+            except FoundTargetException:
+                foundOperator = True
+                result = validateStack()
+                if result is not True:
+                    raise CodeParserException(
+                        codeBlock,
+                        operatorCodeSlice.start,
+                        result + ("\n\nThe conflict was caused by the operator '%s'." \
+                        % operatorString)
+                    )
+        if not foundOperator:
+            parserWarning(
+                codeBlock.xmlElement,
+                "Unable to check the safety of your IP operator '%s' because the containing expression could not be found. "
+                "Please send a copy of your script to xmds-devel at lists.sourceforge.net so this problem can be investigated." \
+                % operatorString
+            )
+    except RuntimeError:
+        parserWarning(
+            codeBlock.xmlElement,
+            "Unable to check the safety of your IP operator because your code is too deeply nested."
+        )
+    
+
+# Below are a bunch of unit tests for the pyparsing-based code parser. These tests can be executed by
+# directly executing this file, or by running the xpdeint test suite from 'run_tests.py'
+
+class AbstractCodeParserTests(unittest.TestCase):
+    @staticmethod
+    def _block(codeString):
+        class _Mock(object): pass
+        block = _Mock()
+        block.xmlElement = None
+        block.scriptLineNumber = 1
+        block.codeString = codeString
+        return block
+    
+
+class TargetComponentsForOperatorsInStringTests(AbstractCodeParserTests):
+    def test_combined(self):
+        self.assertEqual(
+            targetComponentsForOperatorsInString(
+                ['L', 'T'],
+                self._block('/* L[phi] */ K[S] T[mu /* */] L[ j[0] + k] " T[ foo ]"')
+            ),
+            [('T', 'mu', slice(18, 29)), ('L', 'j[0]+k', slice(30, 42))]
+        )
+    def test_ignoreChildComment(self):
+        self.assertEqual(
+            targetComponentsForOperatorsInString(['T'], self._block('T[mu /* */ ]')),
+            [('T', 'mu', slice(0, 12))]
+        )
+    def test_ignoreSiblingComment(self):
+        self.assertEqual(
+            targetComponentsForOperatorsInString(['Ky'], self._block('/* stuff */ Ky[ target]')),
+            [('Ky', 'target', slice(12, 23))]
+        )
+    def test_ignoreSiblingQuotedString(self):
+        self.assertEqual(
+            targetComponentsForOperatorsInString(['F'], self._block('printf("F[psi * 0.98]"); F[phi];')),
+            [('F', 'phi', slice(25, 31))]
+        )
+    def test_nestedOperators(self):
+        self.assertEqual(
+            targetComponentsForOperatorsInString(['Q'], self._block('Q[ Q[ phi]]')),
+            [('Q', 'Q[ phi]', slice(0, 11))]
+        )
+    def test_unbalancedString(self):
+        self.assertRaises(
+            CodeParserException,
+            targetComponentsForOperatorsInString, ['Txx'], self._block('Txx [ ( ]')
+        )
+    def test_withPrintf(self):
+        self.assertEqual(
+            targetComponentsForOperatorsInString(['L'],
+                self._block('printf("L[psi]: %e\\n", L[psi]);')
+            ),
+            [('L', 'psi', slice(23, 29))]
+        )
+    def test_notGreedy(self):
+        self.assertEqual(
+            targetComponentsForOperatorsInString(['L'], self._block('notL[phi];')),
+            []
+        )
+    def test_invalidSyntax(self):
+        self.assertRaises(
+            CodeParserException,
+            targetComponentsForOperatorsInString, ['L'], self._block('L * 5')
+        )
+    
+
+class NonlocalDimensionAccessForComponentsTests(AbstractCodeParserTests):
+    def test_combined(self):
+        self.assertEqual(
+            nonlocalDimensionAccessForComponents(
+                ['phi'],
+                self._block("phi(j => 0 - 9 /* ignore me */, kz => -kz)")
+            ),
+            [('phi', {'j': ('0 - 9', 9), 'kz': ('-kz', 38)}, slice(0, 42))]
+        )
+    def test_multipleAccess(self):
+        self.assertEqual(
+            nonlocalDimensionAccessForComponents(
+                ['velocity'], 
+                self._block("stuff whatever velocity(time => 0.3e-6, idx => -9 * (1 + 2))")
+            ),
+            [('velocity', {'time': ('0.3e-6', 32), 'idx': ('-9 * (1 + 2)', 47)}, slice(15, 60))]
+        )
+    def test_basic(self):
+        self.assertEqual(
+            nonlocalDimensionAccessForComponents(['u'], self._block("u(p => q)")),
+            [('u', {'p': ('q', 7)}, slice(0, 9))]
+        )
+    def test_accessMultipleTimes(self):
+        self.assertEqual(
+            nonlocalDimensionAccessForComponents(
+                ['foo'],
+                self._block("foo(uv => uk * 2) + foo(mb => uv)")
+            ),
+            [('foo', {'uv': ('uk * 2', 10)}, slice(0, 17)),
+             ('foo', {'mb': ('uv', 30)}, slice(20, 33))]
+        )
+    def test_accessDifferentVariables(self):
+        self.assertEqual(
+            nonlocalDimensionAccessForComponents(
+                ['foo', 'bar'],
+                self._block("bar(bang => bam) / foo( someDim => 7 + exp(-2.0))")
+            ),
+            [('bar', {'bang': ('bam', 12)}, slice(0, 16)),
+             ('foo', {'someDim': ('7 + exp(-2.0)', 35)}, slice(19, 49))]
+        )
+    def test_withPrintf(self):
+        self.assertEqual(
+            nonlocalDimensionAccessForComponents(
+                ['psi'],
+                self._block('printf("psi(j => 8): %e\\n", psi(j => 8));')
+            ),
+            [('psi', {'j': ('8', 37)}, slice(28, 39))]
+        )
+    def test_notGreedy(self):
+        self.assertEqual(
+            nonlocalDimensionAccessForComponents(['psi'], self._block('notpsi(dim => value)')),
+            []
+        )
+
+class IntegerDivisionTests(AbstractCodeParserTests):
+    def test_floatDivision(self):
+        self.assertEqual(
+            checkForIntegerDivision(self._block('1.0 / 5.0')),
+            None
+        )
+    def test_symbolDivision(self):
+        self.assertEqual(
+            checkForIntegerDivision(self._block(' M_PI / a')),
+            None
+        )
+    def test_integerDivisionByDouble(self):
+        self.assertEqual(
+            checkForIntegerDivision(self._block(' 1 / 2.0')),
+            None
+        )
+    def test_doubleDivisionByInteger(self):
+        self.assertEqual(
+            checkForIntegerDivision(self._block(' 1.0 / 9')),
+            None
+        )
+    def test_integerDivision(self):
+        self.assertRaises(
+            CodeParserException,
+            checkForIntegerDivision, self._block(' 135 / 9')
+        )
+    def test_ignoreComments(self):
+        self.assertEqual(
+            checkForIntegerDivision(self._block(' /* 1 / 56 */')),
+            None
+        )
+    def test_ignoreStrings(self):
+        self.assertEqual(
+            checkForIntegerDivision(self._block('printf("567 / 962")')),
+            None
+        )
+
+class IPOperatorSanityCheckTests(AbstractCodeParserTests):
+    def test_combined(self):
+        self.assertRaises(
+            CodeParserException,
+            performIPOperatorSanityCheck,
+            'phi', 't', slice(12, 18),
+            self._block("dphi_dt = 1-L[phi]; a = b;")
+        )
+    def test_basic(self):
+        self.assertEqual(
+            performIPOperatorSanityCheck(
+                'psi', 'z', slice(10, 16),
+                self._block('dpsi_dz = T[psi];')
+            ),
+            None
+        )
+    def test_assignmentToIncorrectVariable(self):
+        self.assertRaises(
+            CodeParserException,
+            performIPOperatorSanityCheck,
+            'y', 't', slice(8, 13),
+            self._block("dx_dt = Kt[y];")
+        )
+    def test_unsafeUnaryOperation(self):
+        self.assertRaises(
+            CodeParserException,
+            performIPOperatorSanityCheck,
+            'y', 't', slice(9, 13),
+            self._block("dy_dt = -K[y];")
+        )
+    def test_unsafeBinaryOperation(self):
+        self.assertRaises(
+            CodeParserException,
+            performIPOperatorSanityCheck,
+            'y', 'x', slice(8, 13),
+            self._block("dy_dx = Z[y] / 9.0;")
+        )
+    def test_safeBinaryOperation(self):
+        self.assertEqual(
+            performIPOperatorSanityCheck('x', 'z', slice(14, 18),
+                self._block("dx_dz = 6.0 + W[x];")
+            ),
+            None
+        )
+    def test_safeSubtraction(self):
+        self.assertEqual(
+            performIPOperatorSanityCheck('x', 'z', slice(8, 13),
+                self._block("dx_dz = W[x] - phi;")
+            ),
+            None
+        )
+    def test_unsafeSubtraction(self):
+        self.assertRaises(
+            CodeParserException,
+            performIPOperatorSanityCheck,
+            'var', 'time', slice(19, 27),
+            self._block("dvar_dtime = 1.0 - Foo[var];")
+        )
+    def test_hiddenUnsafeOperation(self):
+        self.assertRaises(
+            CodeParserException,
+            performIPOperatorSanityCheck,
+            'foo', 't', slice(30, 36),
+            self._block("dfoo_dt = i * (fine + dandy + K[foo] );")
+        )
+    def test_complicatedSafeOperation(self):
+        self.assertEqual(
+            performIPOperatorSanityCheck('bar', 'baz', slice(43, 50),
+                self._block("dbar_dbaz = 9.0 * 7 + (something - other + GH[bar]);")
+            ),
+            None
+        )
+    def test_missingAssignment(self):
+        self.assertRaises(
+            CodeParserException,
+            performIPOperatorSanityCheck,
+            'foo', 't', slice(0, 6),
+            self._block("T[foo];")
+        )
+    def test_realExample(self):
+        self.assertEqual(
+            performIPOperatorSanityCheck('phi1', 't', slice(11, 18),
+                self._block('dphi1_dt = T[phi1] - 1.0/hbar*(V + Uint*((phi1) + (phi0)) - eta*mu)*phi1;')
+            ),
+            None
+        )
+
+
+if __name__ == '__main__':
+    unittest.main()
+
diff --git a/xpdeint/Configuration.py b/xpdeint/Configuration.py
new file mode 100755
index 0000000..2692cfb
--- /dev/null
+++ b/xpdeint/Configuration.py
@@ -0,0 +1,223 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+Configuration.py
+
+Created by Graham Dennis on 2009-03-01.
+
+Copyright (c) 2009-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+import os, sys, shutil
+
+from pkg_resources import resource_filename
+from xpdeint.Preferences import xpdeintUserDataPath
+from xpdeint.Utilities import unique
+
+import cPickle, tempfile, shutil, logging
+
+config_arg_cache_filename = os.path.join(xpdeintUserDataPath, 'xpdeint_config_arg_cache')
+
+wafdir = os.path.normpath(resource_filename(__name__, 'waf'))
+sys.path.insert(0, wafdir)
+
+from waflib import Context, Options, Configure, Utils, Logs, Errors
+
+waf_initialised = False
+
+def initialise_waf():
+    if waf_initialised: return
+    
+    Logs.init_log()
+    
+    Context.waf_dir = wafdir
+    Context.top_dir = Context.run_dir = xpdeintUserDataPath
+    Context.out_dir = os.path.join(xpdeintUserDataPath, 'waf_configure')
+    
+    wscript_path = resource_filename(__name__, 'support/wscript')
+    Context.g_module = Context.load_module(wscript_path)
+    Context.g_module.root_path = wscript_path
+    Context.g_module.out = Context.out_dir
+    Context.g_module.configure = configure_wrapper(Context.g_module.configure)
+    Context.Context.recurse = \
+        lambda x, y: getattr(Context.g_module, x.cmd or x.fun, Utils.nada)(x)
+    
+    Options.OptionsContext().execute()
+
+
+def configure_wrapper(f):
+    def _(ctx, *args, **kw):
+        ctx.in_msg -= 1
+        return f(ctx, *args, **kw)
+    
+    return _
+
+def run_config(includePaths = None, libPaths = None):
+    includePaths = includePaths or []
+    libPaths = libPaths or []
+    
+    wafEnvironment = {}
+    
+    wafEnvironment['INCLUDES'] = unique(includePaths)
+    wafEnvironment['LIBPATH'] = unique(libPaths)
+    
+    cPickle.dump(wafEnvironment, file(config_arg_cache_filename, 'w'))
+    
+    initialise_waf()
+    
+    ctx = Context.create_context('configure')
+    ctx.options = Options.options
+    
+    env = ctx.env
+    
+    env.append_unique('INCLUDES', includePaths)
+    env.append_unique('LIBPATH', libPaths)
+    env.append_unique('RPATH', libPaths)
+    
+    for key in ['CXX', 'CXXFLAGS', 'LINKFLAGS']:
+        if key in os.environ:
+            env[key] = os.environ[key]
+    
+    ctx.in_msg = 1
+    
+    ret = -1
+    try:
+        ret = ctx.execute()
+    except Errors.ConfigurationError as e:
+        print "Configuration failed.  Address the above issue to use xmds2."
+    
+    print "Config log saved to ", os.path.join(xpdeintUserDataPath, 'waf_configure', 'config.log')
+    
+    # Copy wscript file to indicate what we configured with
+    wscript_path = resource_filename(__name__, 'support/wscript')
+    wscript_userdata_path = os.path.join(xpdeintUserDataPath, 'wscript')
+    
+    shutil.copyfile(wscript_path, wscript_userdata_path)
+    return ret
+
+
+def run_reconfig(includePaths = None, libPaths = None):
+    includePaths = includePaths or []
+    libPaths = libPaths or []
+    
+    wafEnvironment = {}
+    
+    if os.path.isfile(config_arg_cache_filename):
+        wafEnvironment.update(cPickle.load(file(config_arg_cache_filename)))
+    includePaths.extend(wafEnvironment.get('INCLUDES', []))
+    libPaths.extend(wafEnvironment.get('LIBPATH', []))
+    
+    return run_config(includePaths = includePaths, libPaths = libPaths)
+
+def run_build(source_name, target_name, variant = 'default', buildKWs = {}, verbose = False, userCFlags = None):
+    initialise_waf()
+    
+    source_name = str(source_name)
+    target_name = str(target_name)
+    
+    cwd = os.getcwd()
+    
+    ctx = Context.create_context('build', top_dir = cwd, run_dir = cwd)
+    ctx.load_envs()
+    
+    available_variants = ctx.all_envs.keys()
+    
+    if not variant in available_variants:
+        if variant == 'mpi':
+            print "xmds2 could not find MPI. Do you have an MPI library (like OpenMPI) installed?"
+            print "If you do, run 'xmds2 --reconfigure' to find it."
+        else:
+            print "xmds2 could not find build variant '%s'." % variant
+        return -1
+    
+    ctx.env = ctx.all_envs[variant]
+    available_uselib = ctx.env.uselib
+    
+    uselib = buildKWs['uselib']
+    # Expand the dependencies of any uselib variables
+    Context.g_module.expand_dependencies_of_list(uselib, uselib[:], ctx.env)
+    
+    missing_uselib = set([uselib for uselib in buildKWs['uselib'] if uselib]).difference(available_uselib)
+    if missing_uselib:
+        print "This script requires libraries or features that xmds2 could not find."
+        print "Make sure these requirements are installed and then run 'xmds2 --reconfigure'."
+        print "The missing %i feature(s) were: %s." % (len(missing_uselib), ', '.join(missing_uselib))
+        return -1
+    
+    buildKWs['uselib'].append('system')
+    
+    ctx.out_dir = cwd
+    def build(ctx):
+        ctx.program(
+            source = [source_name],
+            target = target_name,
+            **buildKWs
+        )
+    Context.g_module.build = build
+    
+    if not verbose:
+        ctx.to_log = lambda x: None
+        Logs.log.setLevel(logging.WARNING)
+    else:
+        Logs.log.setLevel(logging.DEBUG)
+        
+        old_exec_command = ctx.exec_command
+        def new_exec_command(cmd, **kw):
+            if not isinstance(cmd, basestring):
+                cmd_str = ' '.join([_ if ' ' not in _ else '"'+_+'"' for _ in cmd])
+            else:
+                cmd_str = cmd
+            print cmd_str
+            
+            return old_exec_command(cmd, **kw)
+        ctx.exec_command = new_exec_command
+    
+    ctx.store = lambda: None
+    
+    if userCFlags:
+        def wrap(ctx):
+            old_exec_command = ctx.exec_command
+            def new_exec_command(cmd, **kw):
+                assert isinstance(cmd, basestring)
+                cmd = cmd + " " + userCFlags
+                return old_exec_command(cmd, **kw)
+            ctx.exec_command = new_exec_command
+        wrap(ctx)
+    
+    
+    try:
+        ctx.execute()
+        
+        # Now clean up the intermediate file/s if we aren't in verbose mode
+        if not verbose:
+            tgen = ctx.get_tgen_by_name(target_name)
+            for t in tgen.compiled_tasks:
+                for n in t.outputs:
+                    n.delete()
+    except Errors.BuildError, err:
+        if verbose:
+            last_cmd = err.tasks[0].last_cmd
+            if type(last_cmd) is list:
+                last_cmd = ' '.join(last_cmd)
+            if userCFlags:
+                last_cmd = last_cmd + ' ' + userCFlags
+                
+            print "Failed command:"
+            print last_cmd
+        return -1
+    
+    return 0
+
diff --git a/xpdeint/Features/Arguments.py b/xpdeint/Features/Arguments.py
new file mode 100644
index 0000000..26038fe
--- /dev/null
+++ b/xpdeint/Features/Arguments.py
@@ -0,0 +1,583 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features._Feature import _Feature
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322830.838402
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:30 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/Arguments.tmpl'
+__CHEETAH_srcLastModified__ = 'Tue May 22 16:27:12 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class Arguments(_Feature):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(Arguments, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Command line argument processing at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Command line argument processing''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def includes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def includes at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(Arguments, self).includes()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''#include <getopt.h>
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def globals at line 35, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(Arguments, self).globals()
+        if _v is not None: write(_filter(_v))
+        # 
+        for argument in VFFSL(SL,"argumentList",True): # generated from line 39, col 3
+            if VFFSL(SL,"argument.type",True) == "string": # generated from line 40, col 5
+                _v = VFFSL(SL,"argument.type",True) # u'$argument.type' on line 41, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'$argument.type')) # from line 41, col 1.
+                write(u''' ''')
+                _v = VFFSL(SL,"argument.name",True) # u'$argument.name' on line 41, col 16
+                if _v is not None: write(_filter(_v, rawExpr=u'$argument.name')) # from line 41, col 16.
+                write(u''' = "''')
+                _v = VFFSL(SL,"argument.defaultValue",True) # u'$argument.defaultValue' on line 41, col 34
+                if _v is not None: write(_filter(_v, rawExpr=u'$argument.defaultValue')) # from line 41, col 34.
+                write(u'''";
+''')
+            else: # generated from line 42, col 5
+                _v = VFFSL(SL,"argument.type",True) # u'$argument.type' on line 43, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'$argument.type')) # from line 43, col 1.
+                write(u''' ''')
+                _v = VFFSL(SL,"argument.name",True) # u'$argument.name' on line 43, col 16
+                if _v is not None: write(_filter(_v, rawExpr=u'$argument.name')) # from line 43, col 16.
+                write(u''' = ''')
+                _v = VFFSL(SL,"argument.defaultValue",True) # u'$argument.defaultValue' on line 43, col 33
+                if _v is not None: write(_filter(_v, rawExpr=u'$argument.defaultValue')) # from line 43, col 33.
+                write(u'''; 
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def functionPrototypes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def functionPrototypes at line 49, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(Arguments, self).functionPrototypes()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''void _print_usage();
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def functionImplementations(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def functionImplementations at line 57, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(Arguments, self).functionImplementations()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''void _print_usage()
+{
+  // This function does not return.
+  _LOG(_NO_ERROR_TERMINATE_LOG_LEVEL, "\\n\\nUsage: ''')
+        _v = VFFSL(SL,"simulationName",True) # u'$simulationName' on line 64, col 51
+        if _v is not None: write(_filter(_v, rawExpr=u'$simulationName')) # from line 64, col 51.
+        for argument in VFFSL(SL,"argumentList",True): # generated from line 65, col 1
+            write(u''' --''')
+            _v = VFFSL(SL,"argument.name",True) # u'$argument.name' on line 66, col 4
+            if _v is not None: write(_filter(_v, rawExpr=u'$argument.name')) # from line 66, col 4.
+            write(u''' <''')
+            _v = VFFSL(SL,"argument.type",True) # u'$argument.type' on line 66, col 20
+            if _v is not None: write(_filter(_v, rawExpr=u'$argument.type')) # from line 66, col 20.
+            write(u'''>''')
+        write(u'''\\n\\n"
+                         "Details:\\n"
+                         "Option\\t\\tType\\t\\tDefault value\\n"
+''')
+        for argument in VFFSL(SL,"argumentList",True): # generated from line 71, col 1
+            write(u'''                         "-''')
+            _v = VFFSL(SL,"argument.shortName",True) # u'$argument.shortName' on line 72, col 28
+            if _v is not None: write(_filter(_v, rawExpr=u'$argument.shortName')) # from line 72, col 28.
+            write(u''',  --''')
+            _v = VFFSL(SL,"argument.name",True) # u'$argument.name' on line 72, col 52
+            if _v is not None: write(_filter(_v, rawExpr=u'$argument.name')) # from line 72, col 52.
+            write(u'''\\t''')
+            _v = VFFSL(SL,"argument.type",True) # u'$argument.type' on line 72, col 68
+            if _v is not None: write(_filter(_v, rawExpr=u'$argument.type')) # from line 72, col 68.
+            write(u''' \\t\\t''')
+            _v = VFFSL(SL,"argument.defaultValue",True) # u'$argument.defaultValue' on line 72, col 87
+            if _v is not None: write(_filter(_v, rawExpr=u'$argument.defaultValue')) # from line 72, col 87.
+            write(u'''\\n"
+''')
+        write(u'''                         );
+  // _LOG terminates the simulation.
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def preAllocation(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def preAllocation($dict) at line 86, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''// *********** Parse the command line for arguments, and set  *********
+// *********** the appropriate global variables               *********
+
+int resp;
+std::map<string, string> mInputArgsAndValues;
+
+while (1) {
+  static struct option long_options[] = 
+    {
+      {"help", no_argument, 0, \'h\'},
+''')
+        for argument in VFFSL(SL,"argumentList",True): # generated from line 97, col 3
+            write(u'''      {"''')
+            _v = VFFSL(SL,"argument.name",True) # u'$argument.name' on line 98, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'$argument.name')) # from line 98, col 9.
+            write(u'''", required_argument, 0, \'''')
+            _v = VFFSL(SL,"argument.shortName",True) # u'$argument.shortName' on line 98, col 49
+            if _v is not None: write(_filter(_v, rawExpr=u'$argument.shortName')) # from line 98, col 49.
+            write(u"""'},
+""")
+        write(u'''      {NULL, 0, 0, 0}
+    };
+  
+  int option_index = 0;
+
+  resp = getopt_long(argc, argv, "h''')
+        for argument in VFFSL(SL,"argumentList",True): # generated from line 106, col 3
+            _v = VFFSL(SL,"argument.shortName",True) # u'$argument.shortName' on line 107, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'$argument.shortName')) # from line 107, col 1.
+            write(u''':''')
+        write(u'''", long_options, &option_index);
+  
+  if (resp == -1)
+    break;
+
+  switch (resp) {
+    case \'?\':
+      // An unknown option was passed. Show allowed options and exit. 
+      _print_usage(); // This causes the simulation to exit
+
+    case \'h\':
+      _print_usage(); // This causes the simulation to exit
+''')
+        for argument in VFFSL(SL,"argumentList",True): # generated from line 121, col 3
+            write(u"""    
+    case '""")
+            _v = VFFSL(SL,"argument.shortName",True) # u'$argument.shortName' on line 123, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'$argument.shortName')) # from line 123, col 11.
+            write(u"""':
+""")
+            if VFFSL(SL,"appendArgsToOutputFilename",True): # generated from line 124, col 5
+                write(u'''      mInputArgsAndValues.insert ( pair<string, string> (string("''')
+                _v = VFFSL(SL,"argument.name",True) # u'$argument.name' on line 125, col 66
+                if _v is not None: write(_filter(_v, rawExpr=u'$argument.name')) # from line 125, col 66.
+                write(u'''"), string(optarg)));
+''')
+            if VFFSL(SL,"argument.type",True) == 'string': # generated from line 127, col 5
+                write(u'''      ''')
+                _v = VFFSL(SL,"argument.name",True) # u'$argument.name' on line 128, col 7
+                if _v is not None: write(_filter(_v, rawExpr=u'$argument.name')) # from line 128, col 7.
+                write(u''' = string(optarg);
+''')
+            elif VFFSL(SL,"argument.type",True) in ('integer', 'int', 'long'): # generated from line 129, col 5
+                write(u'''      ''')
+                _v = VFFSL(SL,"argument.name",True) # u'$argument.name' on line 130, col 7
+                if _v is not None: write(_filter(_v, rawExpr=u'$argument.name')) # from line 130, col 7.
+                write(u''' = strtol(optarg, NULL, 10);
+''')
+            elif VFFSL(SL,"argument.type",True) in 'real': # generated from line 131, col 5
+                write(u'''      ''')
+                _v = VFFSL(SL,"argument.name",True) # u'$argument.name' on line 132, col 7
+                if _v is not None: write(_filter(_v, rawExpr=u'$argument.name')) # from line 132, col 7.
+                write(u''' = strtod(optarg, NULL);
+''')
+            write(u'''      break;
+''')
+        write(u'''      
+    default:
+      _LOG(_ERROR_LOG_LEVEL, "Internal error in processing arguments.\\n");
+  }
+}
+
+''')
+        if VFFSL(SL,"appendArgsToOutputFilename",True): # generated from line 142, col 3
+            write(u"""// Try and insert all the default arguments; the insert will fail if that
+// argument is already in the map. This way we make sure that all the 
+// possible command line arguments are in the map, even if they weren't passed. 
+
+""")
+            for argument in VFFSL(SL,"argumentList",True): # generated from line 147, col 5
+                write(u'''mInputArgsAndValues.insert ( pair<string, string> (string("''')
+                _v = VFFSL(SL,"argument.name",True) # u'$argument.name' on line 148, col 60
+                if _v is not None: write(_filter(_v, rawExpr=u'$argument.name')) # from line 148, col 60.
+                write(u'''"), string("''')
+                _v = VFFSL(SL,"argument.defaultValue",True) # u'$argument.defaultValue' on line 148, col 86
+                if _v is not None: write(_filter(_v, rawExpr=u'$argument.defaultValue')) # from line 148, col 86.
+                write(u'''")));
+''')
+            write(u'''
+// Since the command line arguments and their values are to be appended to the
+// output filenames, construct the append string here
+for (map<string, string>::iterator iter=mInputArgsAndValues.begin() ; iter != mInputArgsAndValues.end(); iter++ ) {
+  gsArgsAndValues += string(".") + (*iter).first + string("_") + (*iter).second;
+}
+''')
+        write(u'''
+if (optind < argc)
+  _print_usage(); // This causes the simulation to exit.
+
+''')
+        if 'postArgumentProcessing' in self.codeBlocks: # generated from line 161, col 3
+            write(u'''// ******** Argument post-processing code *******
+''')
+            _v = VFN(VFFSL(SL,"codeBlocks",True)['postArgumentProcessing'],"codeString",True) # u"${codeBlocks['postArgumentProcessing'].codeString}" on line 163, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u"${codeBlocks['postArgumentProcessing'].codeString}")) # from line 163, col 1.
+            write(u'''// **********************************************
+
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def xsilOutputInfo(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def xsilOutputInfo($dict) at line 170, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        fp = dict['fp']
+        formatSpecifierMap = {'string': ('s', '.c_str()'),                              'int':    ('i', ''),                              'long':   ('li', ''),                              'integer': ('li', ''),                              'real': ('e', '')}
+        # 
+        write(u'''fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 179, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 179, col 9.
+        write(u''', "\\nVariables that can be specified on the command line:\\n");
+''')
+        for argument in VFFSL(SL,"argumentList",True): # generated from line 180, col 3
+            write(u'''
+''')
+            formatSpecifier, argumentSuffix = formatSpecifierMap[VFFSL(SL,"argument.type",True)]
+            write(u'''fprintf(''')
+            _v = VFFSL(SL,"fp",True) # u'$fp' on line 183, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 183, col 9.
+            write(u''', "  Command line argument ''')
+            _v = VFFSL(SL,"argument.name",True) # u'${argument.name}' on line 183, col 39
+            if _v is not None: write(_filter(_v, rawExpr=u'${argument.name}')) # from line 183, col 39.
+            write(u''' = %''')
+            _v = VFFSL(SL,"formatSpecifier",True) # u'${formatSpecifier}' on line 183, col 59
+            if _v is not None: write(_filter(_v, rawExpr=u'${formatSpecifier}')) # from line 183, col 59.
+            write(u'''\\n", ''')
+            _v = VFFSL(SL,"argument.name",True) # u'${argument.name}' on line 183, col 82
+            if _v is not None: write(_filter(_v, rawExpr=u'${argument.name}')) # from line 183, col 82.
+            _v = VFFSL(SL,"argumentSuffix",True) # u'${argumentSuffix}' on line 183, col 98
+            if _v is not None: write(_filter(_v, rawExpr=u'${argumentSuffix}')) # from line 183, col 98.
+            write(u''');
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # Arguments.tmpl
+        # 
+        # Created by Mattias Johnsson on 2008-02-21.
+        # 
+        # Copyright (c) 2008-2012 Mattias Johnsson
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+''')
+        #  This code needs to go at the very beginning of the main function
+        #  so we use the preAllocation code insertion point instead of mainBegin.
+        #  See SimulationDriver.tmpl for ordering of insertion points.
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    featureName = 'Arguments'
+
+    _mainCheetahMethod_for_Arguments= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(Arguments, '_initCheetahAttributes'):
+    templateAPIClass = getattr(Arguments, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(Arguments)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=Arguments()).run()
+
+
diff --git a/xpdeint/Features/Arguments.tmpl b/xpdeint/Features/Arguments.tmpl
new file mode 100644
index 0000000..aa0ea46
--- /dev/null
+++ b/xpdeint/Features/Arguments.tmpl
@@ -0,0 +1,186 @@
+@*
+Arguments.tmpl
+
+Created by Mattias Johnsson on 2008-02-21.
+
+Copyright (c) 2008-2012 Mattias Johnsson
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features._Feature
+
+ at def description: Command line argument processing
+ at attr featureName = 'Arguments'
+
+ at def includes
+  @#
+  @super
+  @#
+#include <getopt.h>
+  @#
+ at end def
+
+ at def globals
+  @#
+  @super
+  @#
+  @for $argument in $argumentList
+    @if $argument.type == "string"
+$argument.type $argument.name = "$argument.defaultValue";
+    @else
+$argument.type $argument.name = $argument.defaultValue; 
+    @end if
+  @end for
+  @#
+ at end def
+
+ at def functionPrototypes
+  @#
+  @super
+  @#
+void _print_usage();
+  @#
+ at end def
+
+ at def functionImplementations
+  @#
+  @super
+  @#
+void _print_usage()
+{
+  // This function does not return.
+  _LOG(_NO_ERROR_TERMINATE_LOG_LEVEL, "\n\nUsage: $simulationName at slurp
+ at for $argument in $argumentList
+ --$argument.name <$argument.type>@slurp
+ at end for
+\n\n"
+                         "Details:\n"
+                         "Option\t\tType\t\tDefault value\n"
+ at for $argument in $argumentList
+                         "-$argument.shortName,  --$argument.name\t$argument.type \t\t$argument.defaultValue\n"
+ at end for
+                         );
+  // _LOG terminates the simulation.
+}
+  @#
+ at end def
+
+
+
+@# This code needs to go at the very beginning of the main function
+@# so we use the preAllocation code insertion point instead of mainBegin.
+@# See SimulationDriver.tmpl for ordering of insertion points.
+
+ at def preAllocation($dict)
+// *********** Parse the command line for arguments, and set  *********
+// *********** the appropriate global variables               *********
+
+int resp;
+std::map<string, string> mInputArgsAndValues;
+
+while (1) {
+  static struct option long_options[] = 
+    {
+      {"help", no_argument, 0, 'h'},
+  @for $argument in $argumentList
+      {"$argument.name", required_argument, 0, '$argument.shortName'},
+  @end for
+      {NULL, 0, 0, 0}
+    };
+  
+  int option_index = 0;
+
+  resp = getopt_long(argc, argv, "h at slurp
+  @for $argument in $argumentList
+$argument.shortName:@slurp
+  @end for
+", long_options, &option_index);
+  
+  if (resp == -1)
+    break;
+
+  switch (resp) {
+    case '?':
+      // An unknown option was passed. Show allowed options and exit. 
+      _print_usage(); // This causes the simulation to exit
+
+    case 'h':
+      _print_usage(); // This causes the simulation to exit
+  @for $argument in $argumentList
+    
+    case '$argument.shortName':
+    @if $appendArgsToOutputFilename
+      mInputArgsAndValues.insert ( pair<string, string> (string("$argument.name"), string(optarg)));
+    @end if
+    @if $argument.type == 'string'
+      $argument.name = string(optarg);
+    @elif $argument.type in ('integer', 'int', 'long'):
+      $argument.name = strtol(optarg, NULL, 10);
+    @elif $argument.type in 'real'
+      $argument.name = strtod(optarg, NULL);
+    @end if
+      break;
+  @end for
+      
+    default:
+      _LOG(_ERROR_LOG_LEVEL, "Internal error in processing arguments.\n");
+  }
+}
+
+  @if $appendArgsToOutputFilename
+// Try and insert all the default arguments; the insert will fail if that
+// argument is already in the map. This way we make sure that all the 
+// possible command line arguments are in the map, even if they weren't passed. 
+
+    @for $argument in $argumentList
+mInputArgsAndValues.insert ( pair<string, string> (string("$argument.name"), string("$argument.defaultValue")));
+    @end for
+
+// Since the command line arguments and their values are to be appended to the
+// output filenames, construct the append string here
+for (map<string, string>::iterator iter=mInputArgsAndValues.begin() ; iter != mInputArgsAndValues.end(); iter++ ) {
+  gsArgsAndValues += string(".") + (*iter).first + string("_") + (*iter).second;
+}
+  @end if
+
+if (optind < argc)
+  _print_usage(); // This causes the simulation to exit.
+
+  @if 'postArgumentProcessing' in self.codeBlocks
+// ******** Argument post-processing code *******
+${codeBlocks['postArgumentProcessing'].codeString}@slurp
+// **********************************************
+
+  @end if
+  @#
+ at end def
+
+ at def xsilOutputInfo($dict)
+  @#
+  @set $fp = dict['fp']
+  @set $formatSpecifierMap = {'string': ('s', '.c_str()'),
+                              'int':    ('i', ''),
+                              'long':   ('li', ''),
+                              'integer': ('li', ''),
+                              'real': ('e', '')}
+  @#
+fprintf($fp, "\nVariables that can be specified on the command line:\n");
+  @for $argument in $argumentList
+
+    @set formatSpecifier, argumentSuffix = formatSpecifierMap[$argument.type]
+fprintf($fp, "  Command line argument ${argument.name} = %${formatSpecifier}\n", ${argument.name}${argumentSuffix});
+  @end for
+  @#
+ at end def
diff --git a/xpdeint/Features/AsciiFormat.py b/xpdeint/Features/AsciiFormat.py
new file mode 100644
index 0000000..102fd4e
--- /dev/null
+++ b/xpdeint/Features/AsciiFormat.py
@@ -0,0 +1,349 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features.OutputFormat import OutputFormat
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322830.807748
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:30 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/AsciiFormat.tmpl'
+__CHEETAH_srcLastModified__ = 'Mon Jul 23 09:42:26 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class AsciiFormat(OutputFormat):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(AsciiFormat, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: ascii output format at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''ascii output format''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeOutFunctionImplementationBody(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def writeOutFunctionImplementationBody($dict) at line 30, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        #  The function prototype in which this code is going is:
+        #   void _mgN_write_out(FILE* _outfile)
+        #  And this code is being automatically indented.
+        # 
+        fp = dict['fp']
+        field = dict['field']
+        basis = dict['basis']
+        # 
+        _v = VFFSL(SL,"writeOutFunctionImplementationBegin",False)(dict) # u'${writeOutFunctionImplementationBegin(dict)}' on line 39, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${writeOutFunctionImplementationBegin(dict)}')) # from line 39, col 1.
+        write(u'''  
+''')
+        dependentVariables = VFFSL(SL,"dict.dependentVariables",True)
+        write(u'''fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 42, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 42, col 9.
+        write(u''', "    <Stream><Metalink Format=\\"Text\\" Delimiter=\\" \\\\n\\"/>\\n");
+
+''')
+        vectors = set([variable['vector'] for variable in dependentVariables])
+        _v = VFFSL(SL,"loopOverFieldInBasisWithVectorsAndInnerContent",False)(field, basis, vectors, VFFSL(SL,"insideOutputLoops",False)(dict), loopingOrder=VFFSL(SL,"LoopingOrder.StrictlyAscendingOrder",True), vectorsNotNeedingDefines=vectors) # u'$loopOverFieldInBasisWithVectorsAndInnerContent(field, basis, vectors, $insideOutputLoops(dict), $loopingOrder=$LoopingOrder.StrictlyAscendingOrder, vectorsNotNeedingDefines=vectors)' on line 45, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'$loopOverFieldInBasisWithVectorsAndInnerContent(field, basis, vectors, $insideOutputLoops(dict), $loopingOrder=$LoopingOrder.StrictlyAscendingOrder, vectorsNotNeedingDefines=vectors)')) # from line 45, col 1.
+        write(u'''
+fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 47, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 47, col 9.
+        write(u''', "    </Stream>\\n");
+
+''')
+        _v = VFFSL(SL,"writeOutFunctionImplementationEnd",False)(dict) # u'${writeOutFunctionImplementationEnd(dict)}' on line 49, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${writeOutFunctionImplementationEnd(dict)}')) # from line 49, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideOutputLoops(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideOutputLoops(dict) at line 53, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        fp = dict['fp']
+        dependentVariables = dict['dependentVariables']
+        field = dict['field']
+        basis = dict['basis']
+        # 
+        componentCount = 0
+        for variable in VFFSL(SL,"dependentVariables",True): # generated from line 61, col 3
+            componentCount += len(VFFSL(SL,"variable.vector.components",True))
+            if VFFSL(SL,"variable.vector.type",True) == 'complex': # generated from line 63, col 5
+                componentCount += len(VFFSL(SL,"variable.vector.components",True))
+        # 
+        dict['componentCount'] = componentCount
+        variableCount = len(VFFSL(SL,"field.dimensions",True)) + componentCount
+        precisionPrefix = '.12'
+        if VFFSL(SL,"precision",True) == 'single': # generated from line 71, col 3
+            precisionPrefix = ''
+        write(u'''// UNVECTORISABLE
+fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 75, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 75, col 9.
+        write(u''', "''')
+        #  Loop over the variables that we're writing out
+        for variableNumber in range(VFFSL(SL,"variableCount",True)): # generated from line 77, col 3
+            if VFFSL(SL,"variableNumber",True) != 0: # generated from line 78, col 5
+                #  If this isn't the first dimension, include a space at the start
+                write(u''' %''')
+                _v = VFFSL(SL,"precisionPrefix",True) # u'${precisionPrefix}' on line 80, col 3
+                if _v is not None: write(_filter(_v, rawExpr=u'${precisionPrefix}')) # from line 80, col 3.
+                write(u'''e''')
+            else: # generated from line 81, col 5
+                write(u'''%''')
+                _v = VFFSL(SL,"precisionPrefix",True) # u'${precisionPrefix}' on line 82, col 2
+                if _v is not None: write(_filter(_v, rawExpr=u'${precisionPrefix}')) # from line 82, col 2.
+                write(u'''e''')
+        write(u'''\\n"''')
+        # 
+        for dimension in VFFSL(SL,"field.dimensions",True): # generated from line 87, col 3
+            write(u''', (real)''')
+            _v = VFN(VFN(VFFSL(SL,"dimension",True),"inBasis",False)(basis),"name",True) # u'${dimension.inBasis(basis).name}' on line 88, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimension.inBasis(basis).name}')) # from line 88, col 9.
+        # 
+        #  Now loop over the (dependent) variables
+        for variable in VFFSL(SL,"dependentVariables",True): # generated from line 92, col 3
+            for componentNumber, component in enumerate(VFFSL(SL,"variable.components",True)): # generated from line 93, col 5
+                if VFFSL(SL,"variable.vector.type",True) == 'real': # generated from line 94, col 7
+                    write(u''', ''')
+                    _v = VFFSL(SL,"variable.arrayName",True) # u'${variable.arrayName}' on line 95, col 3
+                    if _v is not None: write(_filter(_v, rawExpr=u'${variable.arrayName}')) # from line 95, col 3.
+                    write(u'''[_''')
+                    _v = VFFSL(SL,"variable.vector.id",True) # u'${variable.vector.id}' on line 95, col 26
+                    if _v is not None: write(_filter(_v, rawExpr=u'${variable.vector.id}')) # from line 95, col 26.
+                    write(u'''_index_pointer + ''')
+                    _v = VFFSL(SL,"componentNumber",True) # u'${componentNumber}' on line 95, col 64
+                    if _v is not None: write(_filter(_v, rawExpr=u'${componentNumber}')) # from line 95, col 64.
+                    write(u''']''')
+                else: # generated from line 96, col 7
+                    write(u''', ''')
+                    _v = VFFSL(SL,"variable.arrayName",True) # u'${variable.arrayName}' on line 97, col 3
+                    if _v is not None: write(_filter(_v, rawExpr=u'${variable.arrayName}')) # from line 97, col 3.
+                    write(u'''[_''')
+                    _v = VFFSL(SL,"variable.vector.id",True) # u'${variable.vector.id}' on line 97, col 26
+                    if _v is not None: write(_filter(_v, rawExpr=u'${variable.vector.id}')) # from line 97, col 26.
+                    write(u'''_index_pointer + ''')
+                    _v = VFFSL(SL,"componentNumber",True) # u'${componentNumber}' on line 97, col 64
+                    if _v is not None: write(_filter(_v, rawExpr=u'${componentNumber}')) # from line 97, col 64.
+                    write(u'''].Re(), ''')
+                    _v = VFFSL(SL,"variable.arrayName",True) # u'${variable.arrayName}' on line 97, col 90
+                    if _v is not None: write(_filter(_v, rawExpr=u'${variable.arrayName}')) # from line 97, col 90.
+                    write(u'''[_''')
+                    _v = VFFSL(SL,"variable.vector.id",True) # u'${variable.vector.id}' on line 97, col 113
+                    if _v is not None: write(_filter(_v, rawExpr=u'${variable.vector.id}')) # from line 97, col 113.
+                    write(u'''_index_pointer + ''')
+                    _v = VFFSL(SL,"componentNumber",True) # u'${componentNumber}' on line 97, col 151
+                    if _v is not None: write(_filter(_v, rawExpr=u'${componentNumber}')) # from line 97, col 151.
+                    write(u'''].Im()''')
+        write(u''');
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # AsciiFormat.tmpl
+        # 
+        # Created by Graham Dennis on 2007-09-18.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+''')
+        # 
+        #   Write out the data in ASCII format
+        write(u'''
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    name = 'ascii'
+
+    _mainCheetahMethod_for_AsciiFormat= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(AsciiFormat, '_initCheetahAttributes'):
+    templateAPIClass = getattr(AsciiFormat, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(AsciiFormat)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=AsciiFormat()).run()
+
+
diff --git a/xpdeint/Features/AsciiFormat.tmpl b/xpdeint/Features/AsciiFormat.tmpl
new file mode 100644
index 0000000..62b6838
--- /dev/null
+++ b/xpdeint/Features/AsciiFormat.tmpl
@@ -0,0 +1,103 @@
+@*
+AsciiFormat.tmpl
+
+Created by Graham Dennis on 2007-09-18.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features.OutputFormat
+
+ at def description: ascii output format
+ at attr $name = 'ascii'
+
+@*
+  Write out the data in ASCII format
+*@
+ at def writeOutFunctionImplementationBody($dict)
+  @# The function prototype in which this code is going is:
+  @#  void _mgN_write_out(FILE* _outfile)
+  @# And this code is being automatically indented.
+  @#
+  @set $fp = dict['fp']
+  @set $field = dict['field']
+  @set $basis = dict['basis']
+  @#
+${writeOutFunctionImplementationBegin(dict)}@slurp
+  
+  @set $dependentVariables = $dict.dependentVariables
+fprintf($fp, "    <Stream><Metalink Format=\"Text\" Delimiter=\" \\n\"/>\n");
+
+  @set $vectors = set([variable['vector'] for variable in dependentVariables])
+$loopOverFieldInBasisWithVectorsAndInnerContent(field, basis, vectors, $insideOutputLoops(dict), $loopingOrder=$LoopingOrder.StrictlyAscendingOrder, vectorsNotNeedingDefines=vectors)@slurp
+
+fprintf($fp, "    </Stream>\n");
+
+${writeOutFunctionImplementationEnd(dict)}@slurp
+  @#
+ at end def
+
+ at def insideOutputLoops(dict)
+  @#
+  @set $fp = dict['fp']
+  @set $dependentVariables = dict['dependentVariables']
+  @set $field = dict['field']
+  @set $basis = dict['basis']
+  @#
+  @set $componentCount = 0
+  @for $variable in $dependentVariables
+    @set $componentCount += len($variable.vector.components)
+    @if $variable.vector.type == 'complex'
+      @set $componentCount += len($variable.vector.components)
+    @end if
+  @end for
+  @#
+  @set dict['componentCount'] = componentCount
+  @set $variableCount = len($field.dimensions) + componentCount
+  @set $precisionPrefix = '.12'
+  @if $precision == 'single'
+    @set $precisionPrefix = ''
+  @end if
+// UNVECTORISABLE
+fprintf($fp, "@slurp
+  @# Loop over the variables that we're writing out
+  @for $variableNumber in range($variableCount)
+    @if $variableNumber != 0
+      @# If this isn't the first dimension, include a space at the start
+ %${precisionPrefix}e at slurp
+    @else
+%${precisionPrefix}e at slurp
+    @end if
+  @end for
+\n"@slurp
+  @#
+  @for $dimension in $field.dimensions
+, (real)${dimension.inBasis(basis).name}@slurp
+  @end for
+  @#
+  @# Now loop over the (dependent) variables
+  @for $variable in $dependentVariables
+    @for $componentNumber, $component in enumerate($variable.components)
+      @if $variable.vector.type == 'real'
+, ${variable.arrayName}[_${variable.vector.id}_index_pointer + ${componentNumber}]@slurp
+      @else
+, ${variable.arrayName}[_${variable.vector.id}_index_pointer + ${componentNumber}].Re(), ${variable.arrayName}[_${variable.vector.id}_index_pointer + ${componentNumber}].Im()@slurp
+      @end if
+    @end for
+  @end for
+);
+  @#
+ at end def
diff --git a/xpdeint/Features/AutoVectorise.py b/xpdeint/Features/AutoVectorise.py
new file mode 100644
index 0000000..7fd02d4
--- /dev/null
+++ b/xpdeint/Features/AutoVectorise.py
@@ -0,0 +1,219 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features._AutoVectorise import _AutoVectorise
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322830.787463
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:30 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/AutoVectorise.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class AutoVectorise(_AutoVectorise):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(AutoVectorise, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Auto-vectorisation at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Auto-vectorisation''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def defines(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def defines at line 28, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(AutoVectorise, self).defines()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''
+#define _MAKE_AUTOVEC_VARIABLE(x) real* const __restrict__ x ## _autovec = (real*) x
+#define _AUTOVEC(x) (x ## _autovec)
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # AutoVectorise.tmpl
+        # 
+        # Created by Graham Dennis on 2008-02-07.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    featureName = 'AutoVectorise'
+
+    uselib = ['vectorise']
+
+    _mainCheetahMethod_for_AutoVectorise= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(AutoVectorise, '_initCheetahAttributes'):
+    templateAPIClass = getattr(AutoVectorise, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(AutoVectorise)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=AutoVectorise()).run()
+
+
diff --git a/xpdeint/Features/AutoVectorise.tmpl b/xpdeint/Features/AutoVectorise.tmpl
new file mode 100644
index 0000000..04dd04b
--- /dev/null
+++ b/xpdeint/Features/AutoVectorise.tmpl
@@ -0,0 +1,36 @@
+@*
+AutoVectorise.tmpl
+
+Created by Graham Dennis on 2008-02-07.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features._AutoVectorise
+
+ at def description: Auto-vectorisation
+ at attr $featureName = 'AutoVectorise'
+ at attr $uselib = ['vectorise']
+
+ at def defines
+  @#
+  @super
+  @#
+
+#define _MAKE_AUTOVEC_VARIABLE(x) real* const __restrict__ x ## _autovec = (real*) x
+#define _AUTOVEC(x) (x ## _autovec)
+  @#
+ at end def
diff --git a/xpdeint/Features/Benchmark.py b/xpdeint/Features/Benchmark.py
new file mode 100644
index 0000000..87388e7
--- /dev/null
+++ b/xpdeint/Features/Benchmark.py
@@ -0,0 +1,247 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features._Feature import _Feature
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322830.826092
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:30 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/Benchmark.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class Benchmark(_Feature):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(Benchmark, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: benchmark at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''benchmark''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def mainBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def mainBegin($dict) at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''
+// Get the time at which the simulation started
+timeval _tim;
+gettimeofday(&_tim, NULL);
+double _startTime = _tim.tv_sec + (_tim.tv_usec/1e6);
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def mainEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def mainEnd($dict) at line 35, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''
+// Work out how long the simulation has run for
+gettimeofday(&_tim, NULL);
+double _endTime = _tim.tv_sec + (_tim.tv_usec/1e6);
+_LOG(_SIMULATION_LOG_LEVEL, "Time elapsed for simulation is: %.2f seconds\\n", _endTime - _startTime);
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # Benchmark.tmpl
+        # 
+        # Created by Graham Dennis on 2007-08-26.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    featureName = 'Benchmark'
+
+    _mainCheetahMethod_for_Benchmark= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(Benchmark, '_initCheetahAttributes'):
+    templateAPIClass = getattr(Benchmark, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(Benchmark)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=Benchmark()).run()
+
+
diff --git a/xpdeint/Features/Benchmark.tmpl b/xpdeint/Features/Benchmark.tmpl
new file mode 100644
index 0000000..cc52355
--- /dev/null
+++ b/xpdeint/Features/Benchmark.tmpl
@@ -0,0 +1,41 @@
+@*
+Benchmark.tmpl
+
+Created by Graham Dennis on 2007-08-26.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features._Feature
+
+ at def description: benchmark
+ at attr $featureName = 'Benchmark'
+
+ at def mainBegin($dict)
+
+// Get the time at which the simulation started
+timeval _tim;
+gettimeofday(&_tim, NULL);
+double _startTime = _tim.tv_sec + (_tim.tv_usec/1e6);
+ at end def
+
+ at def mainEnd($dict)
+
+// Work out how long the simulation has run for
+gettimeofday(&_tim, NULL);
+double _endTime = _tim.tv_sec + (_tim.tv_usec/1e6);
+_LOG(_SIMULATION_LOG_LEVEL, "Time elapsed for simulation is: %.2f seconds\n", _endTime - _startTime);
+ at end def
diff --git a/xpdeint/Features/BinaryFormat.py b/xpdeint/Features/BinaryFormat.py
new file mode 100644
index 0000000..825c9d7
--- /dev/null
+++ b/xpdeint/Features/BinaryFormat.py
@@ -0,0 +1,642 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features.OutputFormat import OutputFormat
+from xpdeint.Geometry.NonUniformDimensionRepresentation import NonUniformDimensionRepresentation
+from xpdeint.CallOnceGuards import callOncePerInstanceGuard
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322830.937738
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:30 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/BinaryFormat.tmpl'
+__CHEETAH_srcLastModified__ = 'Wed Aug  1 11:52:34 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class BinaryFormat(OutputFormat):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(BinaryFormat, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: binary output format at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''binary output format''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeOutFunctionImplementationBody(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def writeOutFunctionImplementationBody($dict) at line 30, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"writeOutFunctionImplementationBegin",False)(dict) # u'${writeOutFunctionImplementationBegin(dict)}' on line 32, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${writeOutFunctionImplementationBegin(dict)}')) # from line 32, col 1.
+        write(u'''
+''')
+        # 
+        featureOrdering = ['Driver']
+        featureDict = dict.copy()
+        featureDict['extraIndent'] = 0
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('binaryWriteOutBegin', featureOrdering, featureDict) # u"${insertCodeForFeatures('binaryWriteOutBegin', featureOrdering, featureDict)}" on line 38, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('binaryWriteOutBegin', featureOrdering, featureDict)}")) # from line 38, col 1.
+        extraIndent = featureDict['extraIndent']
+        write(u'''
+''')
+        _v = VFFSL(SL,"writeOutFunctionContents",False)(dict) # u'${writeOutFunctionContents(dict), extraIndent=extraIndent}' on line 41, col 1
+        if _v is not None: write(_filter(_v, extraIndent=extraIndent, rawExpr=u'${writeOutFunctionContents(dict), extraIndent=extraIndent}')) # from line 41, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('binaryWriteOutEnd', featureOrdering, featureDict) # u"${insertCodeForFeaturesInReverseOrder('binaryWriteOutEnd', featureOrdering, featureDict)}" on line 43, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeaturesInReverseOrder('binaryWriteOutEnd', featureOrdering, featureDict)}")) # from line 43, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"writeOutFunctionImplementationEnd",False)(dict) # u'${writeOutFunctionImplementationEnd(dict)}' on line 45, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${writeOutFunctionImplementationEnd(dict)}')) # from line 45, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def truncateOutputFiles(self, baseFilename, **KWS):
+
+
+
+        ## CHEETAH: generated from @def truncateOutputFiles($baseFilename) at line 49, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''char _dataFilename[200];
+for (int _i = 0; _i < ''')
+        _v = VFFSL(SL,"parent.outputGroups",True) # u'${parent.outputGroups}' on line 51, col 23
+        if _v is not None: write(_filter(_v, rawExpr=u'${parent.outputGroups}')) # from line 51, col 23.
+        write(u'''; _i++) {
+''')
+        #  FIXME: This is a dodgy, dodgy hack. chunked_output should either be removed or rethought.
+        if hasattr(self.parent, 'featureName') and self.parent.featureName == 'Output': # generated from line 53, col 2
+            write(u'''  snprintf(_dataFilename, 200, "%s_mg%i.dat", ''')
+            _v = VFFSL(SL,"baseFilename",True) # u'${baseFilename}' on line 54, col 47
+            if _v is not None: write(_filter(_v, rawExpr=u'${baseFilename}')) # from line 54, col 47.
+            write(u''', _i);
+''')
+        else: # generated from line 55, col 2
+            write(u'''  snprintf(_dataFilename, 200, "%s.dat", ''')
+            _v = VFFSL(SL,"baseFilename",True) # u'${baseFilename}' on line 56, col 42
+            if _v is not None: write(_filter(_v, rawExpr=u'${baseFilename}')) # from line 56, col 42.
+            write(u''');
+''')
+        write(u'''  fclose(fopen(_dataFilename, "wb"));  // truncate the file
+}
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeOutFunctionContents(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def writeOutFunctionContents($dict) at line 62, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        fp = dict['fp']
+        baseFilename = dict['baseFilename']
+        outputGroupFilenameSuffix = dict['outputGroupFilenameSuffix']
+        field = dict['field']
+        basis = dict['basis']
+        dependentVariables = dict['dependentVariables']
+        componentCount = 0
+        for variable in VFFSL(SL,"dependentVariables",True): # generated from line 71, col 3
+            componentCount += len(VFFSL(SL,"variable.vector.components",True))
+            if VFFSL(SL,"variable.vector.type",True) == 'complex': # generated from line 73, col 5
+                componentCount += len(VFFSL(SL,"variable.vector.components",True))
+        dict['componentCount'] = componentCount
+        # 
+        write(u'''const char *encoding = NULL;
+#if CFG_ENDIAN == CFG_ENDIAN_BIG
+  encoding = "BigEndian";
+#else
+  encoding = "LittleEndian";
+#endif
+
+char _datFilename[200];
+snprintf(_datFilename, 200, "%s''')
+        _v = VFFSL(SL,"outputGroupFilenameSuffix",True) # u'${outputGroupFilenameSuffix}' on line 87, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'${outputGroupFilenameSuffix}')) # from line 87, col 32.
+        write(u'''.dat", ''')
+        _v = VFFSL(SL,"baseFilename",True) # u'${baseFilename}' on line 87, col 67
+        if _v is not None: write(_filter(_v, rawExpr=u'${baseFilename}')) # from line 87, col 67.
+        write(u''');
+
+if (''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 89, col 5
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 89, col 5.
+        write(u''') {
+  const char *unsignedLongType = NULL;
+  if (sizeof(unsigned long) == 4)
+    unsignedLongType = "uint32";
+  else if (sizeof(unsigned long) == 8)
+    unsignedLongType = "uint64";
+  else
+    unsignedLongType = "ulong";
+
+  fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 98, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 98, col 11.
+        write(u''', "    <Stream><Metalink Format=\\"Binary\\" UnsignedLong=\\"%s\\" precision=\\"''')
+        _v = VFFSL(SL,"precision",True) # u'${precision}' on line 98, col 89
+        if _v is not None: write(_filter(_v, rawExpr=u'${precision}')) # from line 98, col 89.
+        write(u'''\\" Type=\\"Remote\\" Encoding=\\"%s\\"/>\\n",
+          unsignedLongType, encoding);
+  fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 100, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 100, col 11.
+        write(u''', "%s\\n", _datFilename);
+}
+
+FILE* fpBinary;
+if ((fpBinary = fopen(_datFilename, "r+b")) == NULL)
+  // _LOG will cause the simulation to exit
+  _LOG(_ERROR_LOG_LEVEL, "Unable to open output file %s\\n"
+                         "Chucking a spack...\\n", _datFilename);
+
+unsigned long dataSize;
+off_t fieldOffset = 0;
+real coordinate;
+
+''')
+        for dim in VFFSL(SL,"field.dimensions",True): # generated from line 113, col 3
+            dimRep = VFN(VFFSL(SL,"dim",True),"inBasis",False)(basis)
+            write(u'''dataSize = ''')
+            _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 115, col 12
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 115, col 12.
+            write(u''';
+if (fwrite(&dataSize, sizeof(unsigned long), 1, fpBinary) != 1) {
+  _LOG(_ERROR_LOG_LEVEL, "Error writing size of dimension \'''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 117, col 60
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 117, col 60.
+            write(u'''\' to binary data file \'%s\'.\\n", _datFilename);
+}
+''')
+            if isinstance(dimRep, NonUniformDimensionRepresentation): # generated from line 119, col 5
+                write(u'''if (fwrite(''')
+                _v = VFFSL(SL,"dimRep.arrayName",True) # u'${dimRep.arrayName}' on line 120, col 12
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.arrayName}')) # from line 120, col 12.
+                write(u''', sizeof(real), dataSize, fpBinary) != dataSize) {
+  _LOG(_ERROR_LOG_LEVEL, "Error writing coordinate values for dimension \'''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 121, col 74
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 121, col 74.
+                write(u'''\' to binary data file \'%s\'.\\n", _datFilename);
+}
+''')
+            else: # generated from line 123, col 5
+                write(u'''coordinate = ''')
+                _v = VFFSL(SL,"dimRep.minimum",True) # u'${dimRep.minimum}' on line 124, col 14
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.minimum}')) # from line 124, col 14.
+                write(u''';
+for (long _i0 = 0; _i0 < dataSize; _i0++, coordinate += ''')
+                _v = VFFSL(SL,"dimRep.stepSize",True) # u'${dimRep.stepSize}' on line 125, col 57
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.stepSize}')) # from line 125, col 57.
+                write(u''') {
+  if (fwrite(&coordinate, sizeof(real), 1, fpBinary) != 1) {
+    _LOG(_ERROR_LOG_LEVEL, "Error writing coordinate values for dimension \'''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 127, col 76
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 127, col 76.
+                write(u'''\' to binary data file \'%s\'.\\n", _datFilename);
+  }
+}
+''')
+            write(u'''fieldOffset += sizeof(unsigned long) + sizeof(real) * dataSize;
+
+''')
+        # 
+        if field.dimensions: # generated from line 135, col 3
+            write(u'''dataSize = ''')
+            _v = ' * '.join([dim.inBasis(basis).globalLattice for dim in field.dimensions]) # u"${' * '.join([dim.inBasis(basis).globalLattice for dim in field.dimensions])}" on line 136, col 12
+            if _v is not None: write(_filter(_v, rawExpr=u"${' * '.join([dim.inBasis(basis).globalLattice for dim in field.dimensions])}")) # from line 136, col 12.
+            write(u''';
+''')
+        else: # generated from line 137, col 3
+            write(u'''dataSize = 1;
+''')
+        write(u'''off_t vectorFieldSize = dataSize * sizeof(real) + sizeof(unsigned long);
+
+for (int _i = 0; _i < ''')
+        _v = VFFSL(SL,"componentCount",True) # u'${componentCount}' on line 142, col 23
+        if _v is not None: write(_filter(_v, rawExpr=u'${componentCount}')) # from line 142, col 23.
+        write(u'''; _i++) {
+  fseeko(fpBinary, fieldOffset + _i * vectorFieldSize, SEEK_SET);
+  if (fwrite(&dataSize, sizeof(unsigned long), 1, fpBinary) != 1) {
+    _LOG(_ERROR_LOG_LEVEL, "Error writing vector size to binary data file \'%s\'.\\n", _datFilename);
+  }
+}
+
+''')
+        #  This is where all of the magic MPI code goes
+        featureOrdering = ['Driver']
+        featureDict = dict.copy()
+        featureDict['extraIndent'] = 0
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('binaryWriteOutWriteDataBegin', VFFSL(SL,"featureOrdering",True), featureDict) # u"${insertCodeForFeatures('binaryWriteOutWriteDataBegin', $featureOrdering, featureDict)}" on line 153, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('binaryWriteOutWriteDataBegin', $featureOrdering, featureDict)}")) # from line 153, col 1.
+        extraIndent = featureDict['extraIndent']
+        write(u'''
+''')
+        _v = VFFSL(SL,"writeData",False)(dict) # u'${writeData(dict), extraIndent=extraIndent}' on line 156, col 1
+        if _v is not None: write(_filter(_v, extraIndent=extraIndent, rawExpr=u'${writeData(dict), extraIndent=extraIndent}')) # from line 156, col 1.
+        write(u'''
+''')
+        #  This is where the rest of the magic MPI code goes
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('binaryWriteOutWriteDataEnd', VFFSL(SL,"featureOrdering",True), featureDict) # u"${insertCodeForFeaturesInReverseOrder('binaryWriteOutWriteDataEnd', $featureOrdering, featureDict)}" on line 159, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeaturesInReverseOrder('binaryWriteOutWriteDataEnd', $featureOrdering, featureDict)}")) # from line 159, col 1.
+        write(u'''
+fclose(fpBinary);
+if (''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 162, col 5
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 162, col 5.
+        write(u''')
+  fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 163, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 163, col 11.
+        write(u''', "    </Stream>\\n");
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeData(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def writeData($dict) at line 168, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        field = dict['field']
+        basis = dict['basis']
+        dependentVariables = dict['dependentVariables']
+        # 
+        variablesInEarlierVectors = 0
+        for variable in VFFSL(SL,"dependentVariables",True): # generated from line 175, col 3
+            componentNameSizePrefix = ''
+            if VFFSL(SL,"variable.vector.type",True) == 'complex': # generated from line 177, col 5
+                componentNameSizePrefix = '2 * '
+            write(u"""// loop over components of vector '""")
+            _v = VFFSL(SL,"variable.vector.id",True) # u'${variable.vector.id}' on line 180, col 36
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.vector.id}')) # from line 180, col 36.
+            write(u"""' (array '""")
+            _v = VFFSL(SL,"variable.arrayName",True) # u'${variable.arrayName}' on line 180, col 67
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.arrayName}')) # from line 180, col 67.
+            write(u"""')
+for (unsigned int _component = 0; _component < """)
+            _v = VFFSL(SL,"componentNameSizePrefix",True) # u'${componentNameSizePrefix}' on line 181, col 48
+            if _v is not None: write(_filter(_v, rawExpr=u'${componentNameSizePrefix}')) # from line 181, col 48.
+            write(u'''_''')
+            _v = VFFSL(SL,"variable.vector.id",True) # u'${variable.vector.id}' on line 181, col 75
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.vector.id}')) # from line 181, col 75.
+            write(u'''_ncomponents; _component++) {
+  off_t _outputfield_index_pointer, _outputfield_old_index_pointer;
+  _outputfield_index_pointer = -42; // Just so that we always seek the first time
+
+''')
+            innerContent = VFFSL(SL,"innerLoopsForVariable",False)(VFFSL(SL,"variable",True), variablesInEarlierVectors, dict)
+            vectors = [VFFSL(SL,"variable.vector",True)]
+            write(u'''  ''')
+            _v = VFFSL(SL,"loopOverFieldInBasisWithVectorsAndInnerContent",False)(VFFSL(SL,"field",True), VFFSL(SL,"basis",True), VFFSL(SL,"vectors",True), VFFSL(SL,"innerContent",True), vectorsNotNeedingDefines=vectors) # u'${loopOverFieldInBasisWithVectorsAndInnerContent($field, $basis, $vectors, $innerContent, vectorsNotNeedingDefines=vectors), autoIndent=True}' on line 187, col 3
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${loopOverFieldInBasisWithVectorsAndInnerContent($field, $basis, $vectors, $innerContent, vectorsNotNeedingDefines=vectors), autoIndent=True}')) # from line 187, col 3.
+            write(u"""} // end loop over components of vector '""")
+            _v = VFFSL(SL,"variable.vector.id",True) # u'${variable.vector.id}' on line 188, col 42
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.vector.id}')) # from line 188, col 42.
+            write(u"""' (array '""")
+            _v = VFFSL(SL,"variable.arrayName",True) # u'${variable.arrayName}' on line 188, col 73
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.arrayName}')) # from line 188, col 73.
+            write(u"""')
+""")
+            variablesInEarlierVectors += VFFSL(SL,"variable.vector.nComponents",True)
+            if VFFSL(SL,"variable.vector.type",True) == 'complex': # generated from line 190, col 5
+                variablesInEarlierVectors += VFFSL(SL,"variable.vector.nComponents",True)
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def innerLoopsForVariable(self, variable, variablesInEarlierVectors, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def innerLoopsForVariable($variable, $variablesInEarlierVectors, $dict) at line 198, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        field = dict['field']
+        basis = dict['basis']
+        # 
+        write(u'''// UNVECTORISABLE
+_outputfield_old_index_pointer = _outputfield_index_pointer;
+_outputfield_index_pointer = 0;
+
+// Calculate the output field index pointer
+''')
+        for idx, dim in enumerate(field.dimensions): # generated from line 208, col 3
+            write(u'''_outputfield_index_pointer += (''')
+            _v = VFN(VFN(VFFSL(SL,"dim",True),"inBasis",False)(basis),"strictlyAscendingGlobalIndex",True) # u'$dim.inBasis(basis).strictlyAscendingGlobalIndex' on line 209, col 32
+            if _v is not None: write(_filter(_v, rawExpr=u'$dim.inBasis(basis).strictlyAscendingGlobalIndex')) # from line 209, col 32.
+            write(u''')''')
+            _v = ''.join([' * ' + dim.inBasis(basis).globalLattice for dim in field.dimensions[idx+1:]]) # u"${''.join([' * ' + dim.inBasis(basis).globalLattice for dim in field.dimensions[idx+1:]])}" on line 210, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u"${''.join([' * ' + dim.inBasis(basis).globalLattice for dim in field.dimensions[idx+1:]])}")) # from line 210, col 1.
+            write(u''';
+''')
+        write(u'''
+if (_outputfield_index_pointer != _outputfield_old_index_pointer + 1)
+  fseeko(fpBinary, fieldOffset + _outputfield_index_pointer * sizeof(real) + (''')
+        _v = VFFSL(SL,"variablesInEarlierVectors",True) # u'${variablesInEarlierVectors}' on line 214, col 79
+        if _v is not None: write(_filter(_v, rawExpr=u'${variablesInEarlierVectors}')) # from line 214, col 79.
+        write(u''' + _component) * vectorFieldSize + sizeof(unsigned long), SEEK_SET);
+
+''')
+        if VFFSL(SL,"variable.vector.type",True) == 'real': # generated from line 216, col 3
+            write(u'''if (fwrite(&''')
+            _v = VFFSL(SL,"variable.arrayName",True) # u'${variable.arrayName}' on line 217, col 13
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.arrayName}')) # from line 217, col 13.
+            write(u'''[_''')
+            _v = VFFSL(SL,"variable.vector.id",True) # u'${variable.vector.id}' on line 217, col 36
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.vector.id}')) # from line 217, col 36.
+            write(u'''_index_pointer + _component], sizeof(real), 1, fpBinary) != 1) {
+  _LOG(_ERROR_LOG_LEVEL, "Error writing output data.\\n");
+}
+''')
+        else: # generated from line 220, col 3
+            write(u'''if (_component & 1) {
+  if (fwrite(&''')
+            _v = VFFSL(SL,"variable.arrayName",True) # u'${variable.arrayName}' on line 222, col 15
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.arrayName}')) # from line 222, col 15.
+            write(u'''[_''')
+            _v = VFFSL(SL,"variable.vector.id",True) # u'${variable.vector.id}' on line 222, col 38
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.vector.id}')) # from line 222, col 38.
+            write(u'''_index_pointer + _component/2].Im(), sizeof(real), 1, fpBinary) != 1) {
+    _LOG(_ERROR_LOG_LEVEL, "Error writing output data.\\n");
+  }
+} else {
+  if (fwrite(&''')
+            _v = VFFSL(SL,"variable.arrayName",True) # u'${variable.arrayName}' on line 226, col 15
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.arrayName}')) # from line 226, col 15.
+            write(u'''[_''')
+            _v = VFFSL(SL,"variable.vector.id",True) # u'${variable.vector.id}' on line 226, col 38
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.vector.id}')) # from line 226, col 38.
+            write(u'''_index_pointer + _component/2].Re(), sizeof(real), 1, fpBinary) != 1) {
+    _LOG(_ERROR_LOG_LEVEL, "Error writing output data.\\n");
+  }
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # BinaryFormat.tmpl
+        # 
+        # Created by Graham Dennis on 2007-09-20.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    name = 'binary'
+
+    mpiSafe = True
+
+    _mainCheetahMethod_for_BinaryFormat= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(BinaryFormat, '_initCheetahAttributes'):
+    templateAPIClass = getattr(BinaryFormat, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(BinaryFormat)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=BinaryFormat()).run()
+
+
diff --git a/xpdeint/Features/BinaryFormat.tmpl b/xpdeint/Features/BinaryFormat.tmpl
new file mode 100644
index 0000000..1a90e42
--- /dev/null
+++ b/xpdeint/Features/BinaryFormat.tmpl
@@ -0,0 +1,235 @@
+@*
+BinaryFormat.tmpl
+
+Created by Graham Dennis on 2007-09-20.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features.OutputFormat
+ at from xpdeint.Geometry.NonUniformDimensionRepresentation import NonUniformDimensionRepresentation
+ at from xpdeint.CallOnceGuards import callOncePerInstanceGuard
+
+ at def description: binary output format
+ at attr $name = 'binary'
+ at attr $mpiSafe = True
+
+ at def writeOutFunctionImplementationBody($dict)
+  @#
+${writeOutFunctionImplementationBegin(dict)}@slurp
+
+  @#
+  @set $featureOrdering = ['Driver']
+  @set $featureDict = dict.copy()
+  @set $featureDict['extraIndent'] = 0
+${insertCodeForFeatures('binaryWriteOutBegin', featureOrdering, featureDict)}@slurp
+  @set $extraIndent = featureDict['extraIndent']
+
+${writeOutFunctionContents(dict), extraIndent=extraIndent}@slurp
+
+${insertCodeForFeaturesInReverseOrder('binaryWriteOutEnd', featureOrdering, featureDict)}@slurp
+
+${writeOutFunctionImplementationEnd(dict)}@slurp
+  @#
+ at end def
+
+ at def truncateOutputFiles($baseFilename)
+char _dataFilename[200];
+for (int _i = 0; _i < ${parent.outputGroups}; _i++) {
+	@# FIXME: This is a dodgy, dodgy hack. chunked_output should either be removed or rethought.
+	@if hasattr(self.parent, 'featureName') and self.parent.featureName == 'Output'
+  snprintf(_dataFilename, 200, "%s_mg%i.dat", ${baseFilename}, _i);
+	@else
+  snprintf(_dataFilename, 200, "%s.dat", ${baseFilename});
+	@end if
+  fclose(fopen(_dataFilename, "wb"));  // truncate the file
+}
+ at end def
+
+ at def writeOutFunctionContents($dict)
+  @#
+  @set $fp = dict['fp']
+  @set $baseFilename = dict['baseFilename']
+  @set $outputGroupFilenameSuffix = dict['outputGroupFilenameSuffix']
+  @set $field = dict['field']
+  @set $basis = dict['basis']
+  @set $dependentVariables = dict['dependentVariables']
+  @set $componentCount = 0
+  @for $variable in $dependentVariables
+    @set $componentCount += len($variable.vector.components)
+    @if $variable.vector.type == 'complex'
+      @set $componentCount += len($variable.vector.components)
+    @end if
+  @end for
+  @set dict['componentCount'] = componentCount
+  @#
+const char *encoding = NULL;
+#if CFG_ENDIAN == CFG_ENDIAN_BIG
+  encoding = "BigEndian";
+#else
+  encoding = "LittleEndian";
+#endif
+
+char _datFilename[200];
+snprintf(_datFilename, 200, "%s${outputGroupFilenameSuffix}.dat", ${baseFilename});
+
+if ($fp) {
+  const char *unsignedLongType = NULL;
+  if (sizeof(unsigned long) == 4)
+    unsignedLongType = "uint32";
+  else if (sizeof(unsigned long) == 8)
+    unsignedLongType = "uint64";
+  else
+    unsignedLongType = "ulong";
+
+  fprintf($fp, "    <Stream><Metalink Format=\"Binary\" UnsignedLong=\"%s\" precision=\"${precision}\" Type=\"Remote\" Encoding=\"%s\"/>\n",
+          unsignedLongType, encoding);
+  fprintf($fp, "%s\n", _datFilename);
+}
+
+FILE* fpBinary;
+if ((fpBinary = fopen(_datFilename, "r+b")) == NULL)
+  // _LOG will cause the simulation to exit
+  _LOG(_ERROR_LOG_LEVEL, "Unable to open output file %s\n"
+                         "Chucking a spack...\n", _datFilename);
+
+unsigned long dataSize;
+off_t fieldOffset = 0;
+real coordinate;
+
+  @for $dim in $field.dimensions
+    @set $dimRep = $dim.inBasis(basis)
+dataSize = ${dimRep.globalLattice};
+if (fwrite(&dataSize, sizeof(unsigned long), 1, fpBinary) != 1) {
+  _LOG(_ERROR_LOG_LEVEL, "Error writing size of dimension '${dimRep.name}' to binary data file '%s'.\n", _datFilename);
+}
+    @if isinstance(dimRep, NonUniformDimensionRepresentation)
+if (fwrite(${dimRep.arrayName}, sizeof(real), dataSize, fpBinary) != dataSize) {
+  _LOG(_ERROR_LOG_LEVEL, "Error writing coordinate values for dimension '${dimRep.name}' to binary data file '%s'.\n", _datFilename);
+}
+    @else
+coordinate = ${dimRep.minimum};
+for (long _i0 = 0; _i0 < dataSize; _i0++, coordinate += ${dimRep.stepSize}) {
+  if (fwrite(&coordinate, sizeof(real), 1, fpBinary) != 1) {
+    _LOG(_ERROR_LOG_LEVEL, "Error writing coordinate values for dimension '${dimRep.name}' to binary data file '%s'.\n", _datFilename);
+  }
+}
+    @end if
+fieldOffset += sizeof(unsigned long) + sizeof(real) * dataSize;
+
+  @end for
+  @#
+  @if field.dimensions
+dataSize = ${' * '.join([dim.inBasis(basis).globalLattice for dim in field.dimensions])};
+  @else
+dataSize = 1;
+  @end if
+off_t vectorFieldSize = dataSize * sizeof(real) + sizeof(unsigned long);
+
+for (int _i = 0; _i < ${componentCount}; _i++) {
+  fseeko(fpBinary, fieldOffset + _i * vectorFieldSize, SEEK_SET);
+  if (fwrite(&dataSize, sizeof(unsigned long), 1, fpBinary) != 1) {
+    _LOG(_ERROR_LOG_LEVEL, "Error writing vector size to binary data file '%s'.\n", _datFilename);
+  }
+}
+
+  @# This is where all of the magic MPI code goes
+  @set $featureOrdering = ['Driver']
+  @set $featureDict = dict.copy()
+  @set $featureDict['extraIndent'] = 0
+${insertCodeForFeatures('binaryWriteOutWriteDataBegin', $featureOrdering, featureDict)}@slurp
+  @set $extraIndent = featureDict['extraIndent']
+
+${writeData(dict), extraIndent=extraIndent}@slurp
+
+  @# This is where the rest of the magic MPI code goes
+${insertCodeForFeaturesInReverseOrder('binaryWriteOutWriteDataEnd', $featureOrdering, featureDict)}@slurp
+
+fclose(fpBinary);
+if ($fp)
+  fprintf($fp, "    </Stream>\n");
+  @#
+ at end def
+
+
+ at def writeData($dict)
+  @#
+  @set $field = dict['field']
+  @set $basis = dict['basis']
+  @set $dependentVariables = dict['dependentVariables']
+  @#
+  @set variablesInEarlierVectors = 0
+  @for $variable in $dependentVariables
+    @set $componentNameSizePrefix = ''
+    @if $variable.vector.type == 'complex'
+      @set $componentNameSizePrefix = '2 * '
+    @end if
+// loop over components of vector '${variable.vector.id}' (array '${variable.arrayName}')
+for (unsigned int _component = 0; _component < ${componentNameSizePrefix}_${variable.vector.id}_ncomponents; _component++) {
+  off_t _outputfield_index_pointer, _outputfield_old_index_pointer;
+  _outputfield_index_pointer = -42; // Just so that we always seek the first time
+
+    @set $innerContent = $innerLoopsForVariable($variable, variablesInEarlierVectors, dict)
+    @set $vectors = [$variable.vector]
+  ${loopOverFieldInBasisWithVectorsAndInnerContent($field, $basis, $vectors, $innerContent, vectorsNotNeedingDefines=vectors), autoIndent=True}@slurp
+} // end loop over components of vector '${variable.vector.id}' (array '${variable.arrayName}')
+    @set $variablesInEarlierVectors += $variable.vector.nComponents
+    @if $variable.vector.type == 'complex'
+      @set $variablesInEarlierVectors += $variable.vector.nComponents
+    @end if
+  @end for
+
+  @#
+ at end def
+
+ at def innerLoopsForVariable($variable, $variablesInEarlierVectors, $dict)
+  @#
+  @set $field = dict['field']
+  @set $basis = dict['basis']
+  @#
+// UNVECTORISABLE
+_outputfield_old_index_pointer = _outputfield_index_pointer;
+_outputfield_index_pointer = 0;
+
+// Calculate the output field index pointer
+  @for idx, dim in enumerate(field.dimensions)
+_outputfield_index_pointer += ($dim.inBasis(basis).strictlyAscendingGlobalIndex)@slurp
+${''.join([' * ' + dim.inBasis(basis).globalLattice for dim in field.dimensions[idx+1:]])};
+  @end for
+
+if (_outputfield_index_pointer != _outputfield_old_index_pointer + 1)
+  fseeko(fpBinary, fieldOffset + _outputfield_index_pointer * sizeof(real) + (${variablesInEarlierVectors} + _component) * vectorFieldSize + sizeof(unsigned long), SEEK_SET);
+
+  @if $variable.vector.type == 'real'
+if (fwrite(&${variable.arrayName}[_${variable.vector.id}_index_pointer + _component], sizeof(real), 1, fpBinary) != 1) {
+  _LOG(_ERROR_LOG_LEVEL, "Error writing output data.\n");
+}
+  @else
+if (_component & 1) {
+  if (fwrite(&${variable.arrayName}[_${variable.vector.id}_index_pointer + _component/2].Im(), sizeof(real), 1, fpBinary) != 1) {
+    _LOG(_ERROR_LOG_LEVEL, "Error writing output data.\n");
+  }
+} else {
+  if (fwrite(&${variable.arrayName}[_${variable.vector.id}_index_pointer + _component/2].Re(), sizeof(real), 1, fpBinary) != 1) {
+    _LOG(_ERROR_LOG_LEVEL, "Error writing output data.\n");
+  }
+}
+  @end if
+  @#
+ at end def
+
+
+
diff --git a/xpdeint/Features/Bing.py b/xpdeint/Features/Bing.py
new file mode 100644
index 0000000..0d9d22b
--- /dev/null
+++ b/xpdeint/Features/Bing.py
@@ -0,0 +1,212 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features._Feature import _Feature
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322830.872355
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:30 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/Bing.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class Bing(_Feature):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(Bing, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: bing at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''bing''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def mainEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def mainEnd($dict) at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''
+// Bing!
+_LOG(_SIMULATION_LOG_LEVEL, "\\a");
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # Bing.tmpl
+        # 
+        # Created by Graham Dennis on 2007-08-26.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    featureName = 'Bing'
+
+    _mainCheetahMethod_for_Bing= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(Bing, '_initCheetahAttributes'):
+    templateAPIClass = getattr(Bing, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(Bing)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=Bing()).run()
+
+
diff --git a/xpdeint/Features/Bing.tmpl b/xpdeint/Features/Bing.tmpl
new file mode 100644
index 0000000..a582ced
--- /dev/null
+++ b/xpdeint/Features/Bing.tmpl
@@ -0,0 +1,31 @@
+@*
+Bing.tmpl
+
+Created by Graham Dennis on 2007-08-26.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features._Feature
+
+ at def description: bing
+ at attr featureName = 'Bing'
+
+ at def mainEnd($dict)
+
+// Bing!
+_LOG(_SIMULATION_LOG_LEVEL, "\a");
+ at end def
diff --git a/xpdeint/Features/CFlags.py b/xpdeint/Features/CFlags.py
new file mode 100644
index 0000000..9c5f667
--- /dev/null
+++ b/xpdeint/Features/CFlags.py
@@ -0,0 +1,212 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features._Feature import _Feature
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322830.916453
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:30 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/CFlags.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class CFlags(_Feature):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(CFlags, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: 'CFlags' element at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u"""'CFlags' element""")
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def cflags(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def cflags at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"cflagsString",True) # u'${cflagsString}' on line 29, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${cflagsString}')) # from line 29, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # CFlags.tmpl
+        # 
+        # Created by Graham Dennis on 2008-08-26.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    featureName = 'CFlags'
+
+    _mainCheetahMethod_for_CFlags= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(CFlags, '_initCheetahAttributes'):
+    templateAPIClass = getattr(CFlags, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(CFlags)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=CFlags()).run()
+
+
diff --git a/xpdeint/Features/CFlags.tmpl b/xpdeint/Features/CFlags.tmpl
new file mode 100644
index 0000000..0c2e7d8
--- /dev/null
+++ b/xpdeint/Features/CFlags.tmpl
@@ -0,0 +1,31 @@
+@*
+CFlags.tmpl
+
+Created by Graham Dennis on 2008-08-26.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features._Feature
+
+ at def description: 'CFlags' element
+ at attr featureName = 'CFlags'
+
+ at def cflags
+  @#
+${cflagsString}@slurp
+  @#
+ at end def
diff --git a/xpdeint/Features/ChunkedOutput.py b/xpdeint/Features/ChunkedOutput.py
new file mode 100644
index 0000000..97cfbac
--- /dev/null
+++ b/xpdeint/Features/ChunkedOutput.py
@@ -0,0 +1,406 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features._ChunkedOutput import _ChunkedOutput
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322830.931505
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:30 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/ChunkedOutput.tmpl'
+__CHEETAH_srcLastModified__ = 'Wed Aug  1 11:52:34 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class ChunkedOutput(_ChunkedOutput):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(ChunkedOutput, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Chunked Output at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Chunked Output''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def defines(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def defines at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(ChunkedOutput, self).defines()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''
+#define _CHUNK_SIZE ((long)''')
+        _v = VFFSL(SL,"chunkSize",True) # u'$chunkSize' on line 32, col 28
+        if _v is not None: write(_filter(_v, rawExpr=u'$chunkSize')) # from line 32, col 28.
+        write(u''')
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def preAllocation(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def preAllocation($dict) at line 36, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        for mg in VFFSL(SL,"momentGroups",True): # generated from line 38, col 3
+            propDimRep = mg.propDimRep
+            if not propDimRep: # generated from line 40, col 5
+                continue
+            _v = VFFSL(SL,"propDimRep.localLattice",True) # u'${propDimRep.localLattice}' on line 43, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${propDimRep.localLattice}')) # from line 43, col 1.
+            write(u''' = ''')
+            _v = VFFSL(SL,"propDimRep.globalLattice",True) # u'${propDimRep.globalLattice}' on line 43, col 30
+            if _v is not None: write(_filter(_v, rawExpr=u'${propDimRep.globalLattice}')) # from line 43, col 30.
+            write(u''';
+if (''')
+            _v = VFN(VFFSL(SL,"mg.processedVector",True),"sizeInBasis",False)(mg.codeBlocks['sampling'].basis) # u"${mg.processedVector.sizeInBasis(mg.codeBlocks['sampling'].basis)}" on line 44, col 5
+            if _v is not None: write(_filter(_v, rawExpr=u"${mg.processedVector.sizeInBasis(mg.codeBlocks['sampling'].basis)}")) # from line 44, col 5.
+            write(u''')
+  ''')
+            _v = VFFSL(SL,"propDimRep.localLattice",True) # u'${propDimRep.localLattice}' on line 45, col 3
+            if _v is not None: write(_filter(_v, rawExpr=u'${propDimRep.localLattice}')) # from line 45, col 3.
+            write(u''' = MIN((_CHUNK_SIZE-1) / (''')
+            _v = VFN(VFFSL(SL,"mg.processedVector",True),"sizeInBasis",False)(mg.codeBlocks['sampling'].basis) # u"${mg.processedVector.sizeInBasis(mg.codeBlocks['sampling'].basis)}" on line 45, col 55
+            if _v is not None: write(_filter(_v, rawExpr=u"${mg.processedVector.sizeInBasis(mg.codeBlocks['sampling'].basis)}")) # from line 45, col 55.
+            write(u''' / ''')
+            _v = VFFSL(SL,"propDimRep.globalLattice",True) # u'${propDimRep.globalLattice}' on line 45, col 124
+            if _v is not None: write(_filter(_v, rawExpr=u'${propDimRep.globalLattice}')) # from line 45, col 124.
+            write(u''' * sizeof(''')
+            _v = VFFSL(SL,"mg.processedVector.type",True) # u'${mg.processedVector.type}' on line 45, col 161
+            if _v is not None: write(_filter(_v, rawExpr=u'${mg.processedVector.type}')) # from line 45, col 161.
+            write(u''')) + 1, ''')
+            _v = VFFSL(SL,"propDimRep.globalLattice",True) # u'${propDimRep.globalLattice}' on line 45, col 195
+            if _v is not None: write(_filter(_v, rawExpr=u'${propDimRep.globalLattice}')) # from line 45, col 195.
+            write(u''');
+''')
+            _v = VFFSL(SL,"insertCodeForFeatures",False)('findMax', ['Driver'], {'variable': '&' + propDimRep.localLattice, 'count': 1, 'op': 'min', 'type': 'long'}) # u"${insertCodeForFeatures('findMax', ['Driver'], {'variable': '&' + propDimRep.localLattice, 'count': 1, 'op': 'min', 'type': 'long'}), autoIndent=True}" on line 46, col 1
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeatures('findMax', ['Driver'], {'variable': '&' + propDimRep.localLattice, 'count': 1, 'op': 'min', 'type': 'long'}), autoIndent=True}")) # from line 46, col 1.
+            write(u'''// Now find the minimum and broadcast it.
+''')
+        #  Initialise output files
+        outputFeature = VFFSL(SL,"features",True)['Output']
+        _v = VFN(VFFSL(SL,"outputFeature.outputFormat",True),"writeOutSetup",False)(''.join([u'("',str(VFFSL(SL,"outputFeature.filename",True)),u'" + gsArgsAndValues).c_str()']), outputFeature) # u'${outputFeature.outputFormat.writeOutSetup(c\'("${outputFeature.filename}" + gsArgsAndValues).c_str()\', outputFeature)}' on line 51, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${outputFeature.outputFormat.writeOutSetup(c\'("${outputFeature.filename}" + gsArgsAndValues).c_str()\', outputFeature)}')) # from line 51, col 1.
+        _v = VFFSL(SL,"outputFeature.outputFormat.writeOutTearDown",True) # u'${outputFeature.outputFormat.writeOutTearDown}' on line 52, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${outputFeature.outputFormat.writeOutTearDown}')) # from line 52, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def sampleFunctionEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def sampleFunctionEnd($dict) at line 56, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        mg = dict['caller']
+        propDimRep = mg.propDimRep
+        # 
+        if not propDimRep: # generated from line 61, col 3
+            return
+        write(u'''if (''')
+        _v = VFFSL(SL,"propDimRep.index",True) # u'${propDimRep.index}' on line 64, col 5
+        if _v is not None: write(_filter(_v, rawExpr=u'${propDimRep.index}')) # from line 64, col 5.
+        write(u''' == ''')
+        _v = VFFSL(SL,"propDimRep.localLattice",True) # u'${propDimRep.localLattice}' on line 64, col 28
+        if _v is not None: write(_filter(_v, rawExpr=u'${propDimRep.localLattice}')) # from line 64, col 28.
+        write(u'''
+    && (''')
+        _v = VFFSL(SL,"propDimRep.index",True) # u'${propDimRep.index}' on line 65, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${propDimRep.index}')) # from line 65, col 9.
+        write(u''' + ''')
+        _v = VFFSL(SL,"propDimRep.localOffset",True) # u'${propDimRep.localOffset}' on line 65, col 31
+        if _v is not None: write(_filter(_v, rawExpr=u'${propDimRep.localOffset}')) # from line 65, col 31.
+        write(u''') != ''')
+        _v = VFFSL(SL,"propDimRep.globalLattice",True) # u'${propDimRep.globalLattice}' on line 65, col 61
+        if _v is not None: write(_filter(_v, rawExpr=u'${propDimRep.globalLattice}')) # from line 65, col 61.
+        write(u''')
+{
+  ''')
+        _v = VFN(VFN(VFFSL(SL,"mg",True),"functions",True)['writeOut'],"call",False)(_outfile='NULL') # u"${mg.functions['writeOut'].call(_outfile='NULL'), autoIndent=True}" on line 67, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${mg.functions['writeOut'].call(_outfile='NULL'), autoIndent=True}")) # from line 67, col 3.
+        write(u'''
+  _LOG(_SIMULATION_LOG_LEVEL, "Written a chunk of moment group ''')
+        _v = VFFSL(SL,"mg.number",True)+1 # u'${mg.number+1}' on line 68, col 64
+        if _v is not None: write(_filter(_v, rawExpr=u'${mg.number+1}')) # from line 68, col 64.
+        write(u'''\\n");
+  ''')
+        _v = VFFSL(SL,"propDimRep.localOffset",True) # u'${propDimRep.localOffset}' on line 69, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${propDimRep.localOffset}')) # from line 69, col 3.
+        write(u''' += ''')
+        _v = VFFSL(SL,"propDimRep.index",True) # u'${propDimRep.index}' on line 69, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'${propDimRep.index}')) # from line 69, col 32.
+        write(u''';
+  ''')
+        _v = VFFSL(SL,"propDimRep.index",True) # u'${propDimRep.index}' on line 70, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${propDimRep.index}')) # from line 70, col 3.
+        write(u''' = 0;
+''')
+        if mg.integratingComponents: # generated from line 71, col 3
+            write(u'''  ''')
+            _v = VFFSL(SL,"mg.rawVector.initialise",True) # u'${mg.rawVector.initialise, autoIndent=True}' on line 72, col 3
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${mg.rawVector.initialise, autoIndent=True}')) # from line 72, col 3.
+        write(u'''}
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeOutBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def writeOutBegin($dict) at line 77, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        for mg in VFFSL(SL,"momentGroups",True): # generated from line 79, col 3
+            propDimRep = mg.propDimRep
+            if not propDimRep: # generated from line 81, col 5
+                continue
+            _v = VFFSL(SL,"propDimRep.localLattice",True) # u'${propDimRep.localLattice}' on line 84, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${propDimRep.localLattice}')) # from line 84, col 1.
+            write(u''' = ''')
+            _v = VFFSL(SL,"propDimRep.index",True) # u'${propDimRep.index}' on line 84, col 30
+            if _v is not None: write(_filter(_v, rawExpr=u'${propDimRep.index}')) # from line 84, col 30.
+            write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # ChunkedOutput.tmpl
+        # 
+        # Created by Graham Dennis on 2010-09-17.
+        # 
+        # Copyright (c) 2010-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    featureName = 'ChunkedOutput'
+
+    _mainCheetahMethod_for_ChunkedOutput= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(ChunkedOutput, '_initCheetahAttributes'):
+    templateAPIClass = getattr(ChunkedOutput, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(ChunkedOutput)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=ChunkedOutput()).run()
+
+
diff --git a/xpdeint/Features/ChunkedOutput.tmpl b/xpdeint/Features/ChunkedOutput.tmpl
new file mode 100644
index 0000000..0c05c25
--- /dev/null
+++ b/xpdeint/Features/ChunkedOutput.tmpl
@@ -0,0 +1,87 @@
+@*
+ChunkedOutput.tmpl
+
+Created by Graham Dennis on 2010-09-17.
+
+Copyright (c) 2010-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features._ChunkedOutput
+
+ at def description: Chunked Output
+ at attr featureName = 'ChunkedOutput'
+
+ at def defines
+  @#
+  @super
+  @#
+
+#define _CHUNK_SIZE ((long)$chunkSize)
+  @#
+ at end def
+
+ at def preAllocation($dict)
+  @#
+  @for mg in $momentGroups
+    @set propDimRep = mg.propDimRep
+    @if not propDimRep
+      @continue
+    @end if
+${propDimRep.localLattice} = ${propDimRep.globalLattice};
+if (${mg.processedVector.sizeInBasis(mg.codeBlocks['sampling'].basis)})
+  ${propDimRep.localLattice} = MIN((_CHUNK_SIZE-1) / (${mg.processedVector.sizeInBasis(mg.codeBlocks['sampling'].basis)} / ${propDimRep.globalLattice} * sizeof(${mg.processedVector.type})) + 1, ${propDimRep.globalLattice});
+${insertCodeForFeatures('findMax', ['Driver'], {'variable': '&' + propDimRep.localLattice, 'count': 1, 'op': 'min', 'type': 'long'}), autoIndent=True}@slurp
+// Now find the minimum and broadcast it.
+  @end for
+  @# Initialise output files
+  @set outputFeature = $features['Output']
+${outputFeature.outputFormat.writeOutSetup(c'("${outputFeature.filename}" + gsArgsAndValues).c_str()', outputFeature)}@slurp
+${outputFeature.outputFormat.writeOutTearDown}@slurp
+  @#
+ at end def
+
+ at def sampleFunctionEnd($dict)
+  @#
+  @set mg = dict['caller']
+  @set propDimRep = mg.propDimRep
+  @#
+  @if not propDimRep
+    @return
+  @end if
+if (${propDimRep.index} == ${propDimRep.localLattice}
+    && (${propDimRep.index} + ${propDimRep.localOffset}) != ${propDimRep.globalLattice})
+{
+  ${mg.functions['writeOut'].call(_outfile='NULL'), autoIndent=True}
+  _LOG(_SIMULATION_LOG_LEVEL, "Written a chunk of moment group ${mg.number+1}\n");
+  ${propDimRep.localOffset} += ${propDimRep.index};
+  ${propDimRep.index} = 0;
+  @if mg.integratingComponents
+  ${mg.rawVector.initialise, autoIndent=True}@slurp
+  @end if
+}
+ at end def
+
+ at def writeOutBegin($dict)
+  @#
+  @for mg in $momentGroups
+    @set propDimRep = mg.propDimRep
+    @if not propDimRep
+      @continue
+    @end if
+${propDimRep.localLattice} = ${propDimRep.index};
+  @end for
+  @#
+ at end def
diff --git a/xpdeint/Features/Diagnostics.py b/xpdeint/Features/Diagnostics.py
new file mode 100644
index 0000000..b42a44b
--- /dev/null
+++ b/xpdeint/Features/Diagnostics.py
@@ -0,0 +1,449 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features._Diagnostics import _Diagnostics
+from xpdeint.Geometry.UniformDimensionRepresentation import UniformDimensionRepresentation
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322830.97162
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:30 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/Diagnostics.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class Diagnostics(_Diagnostics):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(Diagnostics, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Simulation diagnostics at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Simulation diagnostics''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def timestepErrorBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def timestepErrorBegin($dict) at line 34, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        vector = dict['vector']
+        # 
+        write(u'''real _component_errors[_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 38, col 25
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 38, col 25.
+        write(u'''_ncomponents];
+for (long _i0 = 0; _i0 < _''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 39, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 39, col 27.
+        write(u'''_ncomponents; _i0++)
+  _component_errors[_i0] = 0.0;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def timestepErrorEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def timestepErrorEnd($dict) at line 44, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        vector = dict['vector']
+        integrator = dict['caller']
+        # 
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('findMax', ['Driver'], {'variable': '_component_errors', 'count': ''.join([u'_',str(VFFSL(SL,"vector.id",True)),u'_ncomponents'])}) # u"${insertCodeForFeatures('findMax', ['Driver'], {'variable': '_component_errors', 'count': c'_${vector.id}_ncomponents'})}" on line 49, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('findMax', ['Driver'], {'variable': '_component_errors', 'count': c'_${vector.id}_ncomponents'})}")) # from line 49, col 1.
+        write(u'''if (_error > ''')
+        _v = VFFSL(SL,"integrator.tolerance",True) # u'$integrator.tolerance' on line 50, col 14
+        if _v is not None: write(_filter(_v, rawExpr=u'$integrator.tolerance')) # from line 50, col 14.
+        write(u''')
+''')
+        if len(VFFSL(SL,"vector.field.dimensions",True)): # generated from line 51, col 3
+            write(u'''  _LOG(_WARNING_LOG_LEVEL, "''')
+            _v = ', '.join([componentName + '_error: %.1e (cutoff: %.1e)' for componentName in vector.components]) # u"${', '.join([componentName + '_error: %.1e (cutoff: %.1e)' for componentName in vector.components])}" on line 52, col 29
+            if _v is not None: write(_filter(_v, rawExpr=u"${', '.join([componentName + '_error: %.1e (cutoff: %.1e)' for componentName in vector.components])}")) # from line 52, col 29.
+            write(u'''\\n",
+                           ''')
+            _v = ', '.join([''.join([u'_component_errors[',str(VFFSL(SL,"componentIndex",True)),u'], _cutoff[',str(VFFSL(SL,"componentIndex",True)),u']']) for componentIndex in range(len(vector.components))]) # u"${', '.join([c'_component_errors[${componentIndex}], _cutoff[${componentIndex}]' for componentIndex in range(len(vector.components))])}" on line 53, col 28
+            if _v is not None: write(_filter(_v, rawExpr=u"${', '.join([c'_component_errors[${componentIndex}], _cutoff[${componentIndex}]' for componentIndex in range(len(vector.components))])}")) # from line 53, col 28.
+            write(u''');
+''')
+        else: # generated from line 54, col 3
+            write(u'''  _LOG(_WARNING_LOG_LEVEL, "''')
+            _v = ', '.join([componentName + '_error: %.1e (size: %.1e)' for componentName in vector.components]) # u"${', '.join([componentName + '_error: %.1e (size: %.1e)' for componentName in vector.components])}" on line 55, col 29
+            if _v is not None: write(_filter(_v, rawExpr=u"${', '.join([componentName + '_error: %.1e (size: %.1e)' for componentName in vector.components])}")) # from line 55, col 29.
+            write(u'''\\n",
+                           ''')
+            _v = ', '.join([''.join([u'_component_errors[',str(VFFSL(SL,"componentIndex",True)),u'], mod(_active_',str(VFFSL(SL,"vector.id",True)),u'[',str(VFFSL(SL,"componentIndex",True)),u'])']) for componentIndex in range(len(vector.components))]) # u"${', '.join([c'_component_errors[${componentIndex}], mod(_active_${vector.id}[${componentIndex}])' for componentIndex in range(len(vector.components))])}" on line 56, col 28
+            if _v is not None: write(_filter(_v, rawExpr=u"${', '.join([c'_component_errors[${componentIndex}], mod(_active_${vector.id}[${componentIndex}])' for componentIndex in range(len(vector.components))])}")) # from line 56, col 28.
+            write(u''');
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def updateMaximumError(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def updateMaximumError($dict) at line 61, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''if (_temp_error > _component_errors[_i1])
+  _component_errors[_i1] = _temp_error;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def adaptiveStepFailed(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def adaptiveStepFailed($dict) at line 76, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        integrator = dict['caller']
+        # 
+        write(u'''if (_error == 2.0*''')
+        _v = VFFSL(SL,"integrator.tolerance",True) # u'${integrator.tolerance}' on line 80, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${integrator.tolerance}')) # from line 80, col 19.
+        write(u''')
+  _LOG(_SEGMENT_LOG_LEVEL, "NaN hit on this step. Retrying. (Error set to %e)\\n", 2.0*''')
+        _v = VFFSL(SL,"integrator.tolerance",True) # u'${integrator.tolerance}' on line 81, col 87
+        if _v is not None: write(_filter(_v, rawExpr=u'${integrator.tolerance}')) # from line 81, col 87.
+        write(u''');
+_LOG(_SEGMENT_LOG_LEVEL, "Step size %e failed, ''')
+        _v = VFFSL(SL,"integrator.propagationDimension",True) # u'${integrator.propagationDimension}' on line 82, col 48
+        if _v is not None: write(_filter(_v, rawExpr=u'${integrator.propagationDimension}')) # from line 82, col 48.
+        write(u''' = %e, error = %e\\n", _step, ''')
+        _v = VFFSL(SL,"integrator.propagationDimension",True) # u'${integrator.propagationDimension}' on line 82, col 111
+        if _v is not None: write(_filter(_v, rawExpr=u'${integrator.propagationDimension}')) # from line 82, col 111.
+        write(u''', _error);
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def nonlocalAccessValidationFunctionContents(self, dimRepsNeeded, nonlocalAccessString, componentName, func, **KWS):
+
+
+
+        ## CHEETAH: generated from @def nonlocalAccessValidationFunctionContents($dimRepsNeeded, $nonlocalAccessString, $componentName, $func) at line 86, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        for dimRep in [dimRep for dimRep in dimRepsNeeded if dimRep.type == 'long' and isinstance(dimRep, UniformDimensionRepresentation)]: # generated from line 88, col 3
+            write(u'''if (''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 89, col 5
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 89, col 5.
+            write(u''' < 0 || ''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 89, col 32
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 89, col 32.
+            write(u''' >= ''')
+            _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 89, col 55
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 89, col 55.
+            write(u''') {
+  _LOG(
+    _ERROR_LOG_LEVEL,
+    "Error: Invalid access of dimension ''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 92, col 41
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 92, col 41.
+            write(u''' in %s on line %i.\\n"
+    "       Value %li is out of range (%li, %li).\\n"
+    "       Error was caused by accessing variable \'''')
+            _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 94, col 53
+            if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 94, col 53.
+            write(u'''\' nonlocally.\\n",
+    filename, line_number, ''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 95, col 28
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 95, col 28.
+            write(u''' + ''')
+            _v = VFFSL(SL,"dimRep.minimum",True) # u'${dimRep.minimum}' on line 95, col 50
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.minimum}')) # from line 95, col 50.
+            write(u''', ''')
+            _v = VFFSL(SL,"dimRep.minimum",True) # u'${dimRep.minimum}' on line 95, col 69
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.minimum}')) # from line 95, col 69.
+            write(u''', ''')
+            _v = VFFSL(SL,"dimRep.maximum",True) # u'${dimRep.maximum}' on line 95, col 88
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.maximum}')) # from line 95, col 88.
+            write(u'''
+  );
+}
+''')
+        write(u'''return ''')
+        _v = VFFSL(SL,"nonlocalAccessString",True) # u'${nonlocalAccessString}' on line 99, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${nonlocalAccessString}')) # from line 99, col 8.
+        write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # Diagnostics.tmpl
+        # 
+        # Created by Graham Dennis on 2008-04-08.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+''')
+        #  As more gets added to this we are going to want a way of turning parts of this on and off
+        #  The way I think this should be done in the future is to have a _DIAGNOSTIC_LOG function that instead
+        #  of a log level includes a 'log location' string or the like, then the user can pass a list of
+        #  log locations to the diagnostics feature, and those 'log locations' are turned on.
+        write(u'''
+
+
+
+''')
+        #  @def adaptiveStepSucceeded($dict)
+        #    @#
+        #    @set $integrator = dict['caller']
+        #    @#
+        #  _LOG(_WARNING_LOG_LEVEL, "Step size %e succeeded, ${integrator.propagationDimension} = %e, error = %e\n", _step, ${integrator.propagationDimension}, _error);
+        #    @#
+        #  @end def
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    featureName = 'Diagnostics'
+
+    _mainCheetahMethod_for_Diagnostics= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(Diagnostics, '_initCheetahAttributes'):
+    templateAPIClass = getattr(Diagnostics, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(Diagnostics)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=Diagnostics()).run()
+
+
diff --git a/xpdeint/Features/Diagnostics.tmpl b/xpdeint/Features/Diagnostics.tmpl
new file mode 100644
index 0000000..dafe55f
--- /dev/null
+++ b/xpdeint/Features/Diagnostics.tmpl
@@ -0,0 +1,101 @@
+@*
+Diagnostics.tmpl
+
+Created by Graham Dennis on 2008-04-08.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features._Diagnostics
+
+ at from xpdeint.Geometry.UniformDimensionRepresentation import UniformDimensionRepresentation
+
+ at def description: Simulation diagnostics
+ at attr featureName = 'Diagnostics'
+
+@# As more gets added to this we are going to want a way of turning parts of this on and off
+@# The way I think this should be done in the future is to have a _DIAGNOSTIC_LOG function that instead
+@# of a log level includes a 'log location' string or the like, then the user can pass a list of
+@# log locations to the diagnostics feature, and those 'log locations' are turned on.
+
+ at def timestepErrorBegin($dict)
+  @#
+  @set $vector = dict['vector']
+  @#
+real _component_errors[_${vector.id}_ncomponents];
+for (long _i0 = 0; _i0 < _${vector.id}_ncomponents; _i0++)
+  _component_errors[_i0] = 0.0;
+  @#
+ at end def
+
+ at def timestepErrorEnd($dict)
+  @#
+  @set $vector = dict['vector']
+  @set $integrator = dict['caller']
+  @#
+${insertCodeForFeatures('findMax', ['Driver'], {'variable': '_component_errors', 'count': c'_${vector.id}_ncomponents'})}@slurp
+if (_error > $integrator.tolerance)
+  @if len($vector.field.dimensions)
+  _LOG(_WARNING_LOG_LEVEL, "${', '.join([componentName + '_error: %.1e (cutoff: %.1e)' for componentName in vector.components])}\n",
+                           ${', '.join([c'_component_errors[${componentIndex}], _cutoff[${componentIndex}]' for componentIndex in range(len(vector.components))])});
+  @else
+  _LOG(_WARNING_LOG_LEVEL, "${', '.join([componentName + '_error: %.1e (size: %.1e)' for componentName in vector.components])}\n",
+                           ${', '.join([c'_component_errors[${componentIndex}], mod(_active_${vector.id}[${componentIndex}])' for componentIndex in range(len(vector.components))])});
+  @end if
+  @#
+ at end def
+
+ at def updateMaximumError($dict)
+  @#
+if (_temp_error > _component_errors[_i1])
+  _component_errors[_i1] = _temp_error;
+  @#
+ at end def
+
+@# @def adaptiveStepSucceeded($dict)
+@#   @#
+@#   @set $integrator = dict['caller']
+@#   @#
+@# _LOG(_WARNING_LOG_LEVEL, "Step size %e succeeded, ${integrator.propagationDimension} = %e, error = %e\n", _step, ${integrator.propagationDimension}, _error);
+@#   @#
+@# @end def
+
+ at def adaptiveStepFailed($dict)
+  @#
+  @set $integrator = dict['caller']
+  @#
+if (_error == 2.0*${integrator.tolerance})
+  _LOG(_SEGMENT_LOG_LEVEL, "NaN hit on this step. Retrying. (Error set to %e)\n", 2.0*${integrator.tolerance});
+_LOG(_SEGMENT_LOG_LEVEL, "Step size %e failed, ${integrator.propagationDimension} = %e, error = %e\n", _step, ${integrator.propagationDimension}, _error);
+  @#
+ at end def
+
+ at def nonlocalAccessValidationFunctionContents($dimRepsNeeded, $nonlocalAccessString, $componentName, $func)
+  @#
+  @for dimRep in [dimRep for dimRep in dimRepsNeeded if dimRep.type == 'long' and isinstance(dimRep, UniformDimensionRepresentation)]
+if (${dimRep.loopIndex} < 0 || ${dimRep.loopIndex} >= ${dimRep.globalLattice}) {
+  _LOG(
+    _ERROR_LOG_LEVEL,
+    "Error: Invalid access of dimension ${dimRep.name} in %s on line %i.\n"
+    "       Value %li is out of range (%li, %li).\n"
+    "       Error was caused by accessing variable '${componentName}' nonlocally.\n",
+    filename, line_number, ${dimRep.loopIndex} + ${dimRep.minimum}, ${dimRep.minimum}, ${dimRep.maximum}
+  );
+}
+  @end for
+return ${nonlocalAccessString};
+  @#
+ at end def
diff --git a/xpdeint/Features/ErrorCheck.py b/xpdeint/Features/ErrorCheck.py
new file mode 100644
index 0000000..a088a30
--- /dev/null
+++ b/xpdeint/Features/ErrorCheck.py
@@ -0,0 +1,604 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features._ErrorCheck import _ErrorCheck
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.051289
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/ErrorCheck.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class ErrorCheck(_ErrorCheck):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(ErrorCheck, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: error check at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''error check''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def globals at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(ErrorCheck, self).globals()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''bool _half_step;
+''')
+        for momentGroup in VFFSL(SL,"momentGroups",True): # generated from line 32, col 3
+            momentGroupOutputField = VFFSL(SL,"momentGroup.outputField",True)
+            write(u'''
+// Arrays for full- and half-step moment group results
+real* _''')
+            _v = VFFSL(SL,"momentGroupOutputField.name",True) # u'${momentGroupOutputField.name}' on line 36, col 8
+            if _v is not None: write(_filter(_v, rawExpr=u'${momentGroupOutputField.name}')) # from line 36, col 8.
+            write(u'''_fullstep;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def topLevelSequenceBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def topLevelSequenceBegin($dict) at line 41, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  Loop over moment groups allocating half step array
+        #  and saving the pointer to the original array
+        #  Note that we allocate the half step array now and not
+        #  later when we actually need it so that if allocating it would
+        #  cause us to run out of virtual memory, we do that at the *start*
+        #  of the simulation, not half way through
+        for momentGroup in VFFSL(SL,"momentGroups",True): # generated from line 49, col 3
+            momentGroupOutputField = VFFSL(SL,"momentGroup.outputField",True)
+            write(u'''
+_''')
+            _v = VFFSL(SL,"momentGroupOutputField.name",True) # u'${momentGroupOutputField.name}' on line 52, col 2
+            if _v is not None: write(_filter(_v, rawExpr=u'${momentGroupOutputField.name}')) # from line 52, col 2.
+            write(u'''_fullstep = _''')
+            _v = VFFSL(SL,"momentGroup.processedVector.id",True) # u'${momentGroup.processedVector.id}' on line 52, col 45
+            if _v is not None: write(_filter(_v, rawExpr=u'${momentGroup.processedVector.id}')) # from line 52, col 45.
+            write(u''';
+// _''')
+            _v = VFFSL(SL,"momentGroupOutputField.name",True) # u'${momentGroupOutputField.name}' on line 53, col 5
+            if _v is not None: write(_filter(_v, rawExpr=u'${momentGroupOutputField.name}')) # from line 53, col 5.
+            write(u'''_halfstep has already been allocated
+''')
+        write(u'''
+for (_half_step = false; ; _half_step = true)
+{
+  if (!_half_step) {
+    _LOG(_SIMULATION_LOG_LEVEL, "Beginning full step integration ...\\n");
+''')
+        #  Loop over the moment groups setting the output field to the fullstep fiel
+        for momentGroup in VFFSL(SL,"momentGroups",True): # generated from line 61, col 3
+            momentGroupOutputField = VFFSL(SL,"momentGroup.outputField",True)
+            write(u'''    
+    _active_''')
+            _v = VFFSL(SL,"momentGroup.processedVector.id",True) # u'${momentGroup.processedVector.id}' on line 64, col 13
+            if _v is not None: write(_filter(_v, rawExpr=u'${momentGroup.processedVector.id}')) # from line 64, col 13.
+            write(u''' = _''')
+            _v = VFFSL(SL,"momentGroupOutputField.name",True) # u'${momentGroupOutputField.name}' on line 64, col 50
+            if _v is not None: write(_filter(_v, rawExpr=u'${momentGroupOutputField.name}')) # from line 64, col 50.
+            write(u'''_fullstep;
+''')
+        write(u'''  }
+  else {
+    _LOG(_SIMULATION_LOG_LEVEL, "Beginning half step integration ...\\n");
+''')
+        #  Loop over the moment groups setting the output field to the already-allocated halfstep field
+        for momentGroup in VFFSL(SL,"momentGroups",True): # generated from line 70, col 3
+            momentGroupOutputField = VFFSL(SL,"momentGroup.outputField",True)
+            write(u'''    
+''')
+            for aliasName in momentGroup.processedVector.aliases: # generated from line 73, col 5
+                if not aliasName==''.join([u'_',str(VFFSL(SL,"momentGroupOutputField.name",True)),u'_halfstep']): # generated from line 74, col 7
+                    write(u'''    _active_''')
+                    _v = VFFSL(SL,"momentGroup.processedVector.id",True) # u'${momentGroup.processedVector.id}' on line 75, col 13
+                    if _v is not None: write(_filter(_v, rawExpr=u'${momentGroup.processedVector.id}')) # from line 75, col 13.
+                    write(u''' = ''')
+                    _v = VFFSL(SL,"aliasName",True) # u'$aliasName' on line 75, col 49
+                    if _v is not None: write(_filter(_v, rawExpr=u'$aliasName')) # from line 75, col 49.
+                    write(u''';
+    ''')
+                    _v = VFN(VFN(VFFSL(SL,"momentGroup.processedVector",True),"functions",True)['initialise'],"call",False)() # u"${momentGroup.processedVector.functions['initialise'].call()}" on line 76, col 5
+                    if _v is not None: write(_filter(_v, rawExpr=u"${momentGroup.processedVector.functions['initialise'].call()}")) # from line 76, col 5.
+                    write(u'''
+''')
+            write(u'''    
+    _active_''')
+            _v = VFFSL(SL,"momentGroup.processedVector.id",True) # u'${momentGroup.processedVector.id}' on line 80, col 13
+            if _v is not None: write(_filter(_v, rawExpr=u'${momentGroup.processedVector.id}')) # from line 80, col 13.
+            write(u''' = _''')
+            _v = VFFSL(SL,"momentGroupOutputField.name",True) # u'${momentGroupOutputField.name}' on line 80, col 50
+            if _v is not None: write(_filter(_v, rawExpr=u'${momentGroupOutputField.name}')) # from line 80, col 50.
+            write(u'''_halfstep;
+''')
+        write(u'''  }
+  
+''')
+        VFFSL(SL,"dict",True)['extraIndent'] += 2
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def topLevelSequenceEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def topLevelSequenceEnd($dict) at line 88, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''  
+  if (_half_step)
+      break;
+}
+''')
+        VFFSL(SL,"dict",True)['extraIndent'] -= 2
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeOutFunctionImplementationBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def writeOutFunctionImplementationBegin($dict) at line 100, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        momentGroup = dict['caller']
+        dependentVariables = dict['dependentVariables']
+        fieldName = VFFSL(SL,"momentGroup.outputField.name",True)
+        # 
+        #  So our job is to create 'error_' versions of all of the variables in the momentGroup's outputField.
+        newVariableDict = {'vector': VFFSL(SL,"momentGroup.processedVector",True),                           'arrayName': ''.join([u'_',str(VFFSL(SL,"fieldName",True)),u'_fullstep']),                           'components': ['error_' + component for component in VFFSL(SL,"momentGroup.processedVector.components",True)],                          }
+        dependentVariables.append(newVariableDict)
+        # 
+        #  Now return the template that will be used to create the error vector
+        write(u'''// Copy the error into the fullstep array
+_''')
+        _v = VFFSL(SL,"fieldName",True) # u'${fieldName}' on line 115, col 2
+        if _v is not None: write(_filter(_v, rawExpr=u'${fieldName}')) # from line 115, col 2.
+        write(u'''_fullstep[$index] = _''')
+        _v = VFFSL(SL,"fieldName",True) # u'${fieldName}' on line 115, col 36
+        if _v is not None: write(_filter(_v, rawExpr=u'${fieldName}')) # from line 115, col 36.
+        write(u'''_fullstep[$index] - _''')
+        _v = VFFSL(SL,"fieldName",True) # u'${fieldName}' on line 115, col 70
+        if _v is not None: write(_filter(_v, rawExpr=u'${fieldName}')) # from line 115, col 70.
+        write(u'''_halfstep[$index];
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def createFixedStepVariable(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def createFixedStepVariable($dict) at line 119, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''
+// If we are doing half-step integration, divide the step size by 2
+if (_half_step)
+  _step /= 2.0;
+// Regardless, the step size for generated noise is the half-step
+_noiseStep /= 2.0;
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def createToleranceVariable(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def createToleranceVariable($dict) at line 128, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''
+// If we are doing half-step integration, divide the tolerance by 16
+if (_half_step)
+  _tolerance /= 16.0;
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def integrateFixedStepInnerLoopBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def integrateFixedStepInnerLoopBegin($dict) at line 135, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        integrator = dict['caller']
+        write(u'''
+// If we are doing half-step integration, then we need to do each integrate step twice (but with half the step size)
+for (int _error_check_loop_iter = (_half_step ? 2 : 1); _error_check_loop_iter > 0; _error_check_loop_iter--) {
+''')
+        VFFSL(SL,"dict",True)['extraIndent'] += 2
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def integrateFixedStepInnerLoopEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def integrateFixedStepInnerLoopEnd($dict) at line 145, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''}
+''')
+        VFFSL(SL,"dict",True)['extraIndent'] -= 2
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeOutFunctionImplementationBody(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def writeOutFunctionImplementationBody($dict) at line 152, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        momentGroup = dict['caller']
+        processedVector = VFFSL(SL,"momentGroup.processedVector",True)
+        outputFieldName = momentGroup.outputField.name
+        write(u'''_active_''')
+        _v = VFFSL(SL,"processedVector.id",True) # u'${processedVector.id}' on line 156, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${processedVector.id}')) # from line 156, col 9.
+        write(u''' = _''')
+        _v = VFFSL(SL,"outputFieldName",True) # u'${outputFieldName}' on line 156, col 34
+        if _v is not None: write(_filter(_v, rawExpr=u'${outputFieldName}')) # from line 156, col 34.
+        write(u'''_fullstep;
+
+''')
+        _v = VFN(VFFSL(SL,"processedVector",True),"findMaximum",False)('_max_step_error', basis = momentGroup.outputBasis) # u"${processedVector.findMaximum('_max_step_error', basis = momentGroup.outputBasis)}" on line 158, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${processedVector.findMaximum('_max_step_error', basis = momentGroup.outputBasis)}")) # from line 158, col 1.
+        write(u'''
+// Restore active pointer for processed vector
+_active_''')
+        _v = VFFSL(SL,"processedVector.id",True) # u'${processedVector.id}' on line 161, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${processedVector.id}')) # from line 161, col 9.
+        write(u''' = _''')
+        _v = VFFSL(SL,"outputFieldName",True) # u'${outputFieldName}' on line 161, col 34
+        if _v is not None: write(_filter(_v, rawExpr=u'${outputFieldName}')) # from line 161, col 34.
+        write(u'''_halfstep;
+
+_LOG(_SIMULATION_LOG_LEVEL, "Maximum step error in moment group ''')
+        _v = VFFSL(SL,"momentGroup.number",True)+1 # u'${momentGroup.number+1}' on line 163, col 65
+        if _v is not None: write(_filter(_v, rawExpr=u'${momentGroup.number+1}')) # from line 163, col 65.
+        write(u''' was %e\\n", _max_step_error);
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # ErrorCheck.tmpl
+        # 
+        # Created by Graham Dennis on 2007-08-26.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+''')
+        # 
+        #   This function returns a Cheetah template string suitable for passing to loopOverVectorsWithInnerContentTemplate
+        write(u'''
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    featureName = 'ErrorCheck'
+
+    _mainCheetahMethod_for_ErrorCheck= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(ErrorCheck, '_initCheetahAttributes'):
+    templateAPIClass = getattr(ErrorCheck, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(ErrorCheck)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=ErrorCheck()).run()
+
+
diff --git a/xpdeint/Features/ErrorCheck.tmpl b/xpdeint/Features/ErrorCheck.tmpl
new file mode 100644
index 0000000..6b79d21
--- /dev/null
+++ b/xpdeint/Features/ErrorCheck.tmpl
@@ -0,0 +1,164 @@
+@*
+ErrorCheck.tmpl
+
+Created by Graham Dennis on 2007-08-26.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features._ErrorCheck
+
+ at def description: error check
+ at attr $featureName = 'ErrorCheck'
+
+ at def globals
+  @#
+  @super
+  @#
+bool _half_step;
+  @for $momentGroup in $momentGroups
+    @set $momentGroupOutputField = $momentGroup.outputField
+
+// Arrays for full- and half-step moment group results
+real* _${momentGroupOutputField.name}_fullstep;
+  @end for
+  @#
+ at end def
+
+ at def topLevelSequenceBegin($dict)
+  @#
+  @# Loop over moment groups allocating half step array
+  @# and saving the pointer to the original array
+  @# Note that we allocate the half step array now and not
+  @# later when we actually need it so that if allocating it would
+  @# cause us to run out of virtual memory, we do that at the *start*
+  @# of the simulation, not half way through
+  @for $momentGroup in $momentGroups
+    @set $momentGroupOutputField = $momentGroup.outputField
+
+_${momentGroupOutputField.name}_fullstep = _${momentGroup.processedVector.id};
+// _${momentGroupOutputField.name}_halfstep has already been allocated
+  @end for
+
+for (_half_step = false; ; _half_step = true)
+{
+  if (!_half_step) {
+    _LOG(_SIMULATION_LOG_LEVEL, "Beginning full step integration ...\n");
+  @# Loop over the moment groups setting the output field to the fullstep fiel
+  @for $momentGroup in $momentGroups
+    @set $momentGroupOutputField = $momentGroup.outputField
+    
+    _active_${momentGroup.processedVector.id} = _${momentGroupOutputField.name}_fullstep;
+  @end for
+  }
+  else {
+    _LOG(_SIMULATION_LOG_LEVEL, "Beginning half step integration ...\n");
+  @# Loop over the moment groups setting the output field to the already-allocated halfstep field
+  @for $momentGroup in $momentGroups
+    @set $momentGroupOutputField = $momentGroup.outputField
+    
+    @for aliasName in momentGroup.processedVector.aliases
+      @if not aliasName==c"_${momentGroupOutputField.name}_halfstep"
+    _active_${momentGroup.processedVector.id} = $aliasName;
+    ${momentGroup.processedVector.functions['initialise'].call()}
+      @end if
+    @end for
+    
+    _active_${momentGroup.processedVector.id} = _${momentGroupOutputField.name}_halfstep;
+  @end for
+  }
+  
+  @silent $dict['extraIndent'] += 2
+  @#
+ at end def
+
+ at def topLevelSequenceEnd($dict)
+  
+  if (_half_step)
+      break;
+}
+  @silent $dict['extraIndent'] -= 2
+ at end def
+
+
+@*
+  This function returns a Cheetah template string suitable for passing to loopOverVectorsWithInnerContentTemplate
+*@
+ at def writeOutFunctionImplementationBegin($dict)
+  @#
+  @set $momentGroup = dict['caller']
+  @set $dependentVariables = dict['dependentVariables']
+  @set $fieldName = $momentGroup.outputField.name
+  @#
+  @# So our job is to create 'error_' versions of all of the variables in the momentGroup's outputField.
+  @set $newVariableDict = {'vector': $momentGroup.processedVector,
+                           'arrayName': c'_${fieldName}_fullstep',
+                           'components': ['error_' + component for component in $momentGroup.processedVector.components],
+                          }
+  @silent dependentVariables.append(newVariableDict)
+  @#
+  @# Now return the template that will be used to create the error vector
+// Copy the error into the fullstep array
+_${fieldName}_fullstep[\$index] = _${fieldName}_fullstep[\$index] - _${fieldName}_halfstep[\$index];
+  @#
+ at end def
+
+ at def createFixedStepVariable($dict)
+
+// If we are doing half-step integration, divide the step size by 2
+if (_half_step)
+  _step /= 2.0;
+// Regardless, the step size for generated noise is the half-step
+_noiseStep /= 2.0;
+ at end def
+
+ at def createToleranceVariable($dict)
+
+// If we are doing half-step integration, divide the tolerance by 16
+if (_half_step)
+  _tolerance /= 16.0;
+ at end def
+
+ at def integrateFixedStepInnerLoopBegin($dict)
+  @#
+  @set $integrator = dict['caller']
+
+// If we are doing half-step integration, then we need to do each integrate step twice (but with half the step size)
+for (int _error_check_loop_iter = (_half_step ? 2 : 1); _error_check_loop_iter > 0; _error_check_loop_iter--) {
+  @silent $dict['extraIndent'] += 2
+  @#
+ at end def
+
+ at def integrateFixedStepInnerLoopEnd($dict)
+  @#
+}
+  @silent $dict['extraIndent'] -= 2
+  @#
+ at end def
+
+ at def writeOutFunctionImplementationBody($dict)
+  @set $momentGroup = dict['caller']
+  @set $processedVector = $momentGroup.processedVector
+  @set $outputFieldName = momentGroup.outputField.name
+_active_${processedVector.id} = _${outputFieldName}_fullstep;
+
+${processedVector.findMaximum('_max_step_error', basis = momentGroup.outputBasis)}@slurp
+
+// Restore active pointer for processed vector
+_active_${processedVector.id} = _${outputFieldName}_halfstep;
+
+_LOG(_SIMULATION_LOG_LEVEL, "Maximum step error in moment group ${momentGroup.number+1} was %e\n", _max_step_error);
+ at end def
diff --git a/xpdeint/Features/Globals.py b/xpdeint/Features/Globals.py
new file mode 100644
index 0000000..c02f3e1
--- /dev/null
+++ b/xpdeint/Features/Globals.py
@@ -0,0 +1,217 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features._Feature import _Feature
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.008777
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/Globals.tmpl'
+__CHEETAH_srcLastModified__ = 'Wed Feb 22 16:33:31 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class Globals(_Feature):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(Globals, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: 'Globals' element at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u"""'Globals' element""")
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def globals at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(Globals, self).globals()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''
+''')
+        _v = VFN(VFFSL(SL,"codeBlocks",True)['globalsCode'],"codeString",True) # u"${codeBlocks['globalsCode'].codeString}" on line 32, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${codeBlocks['globalsCode'].codeString}")) # from line 32, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # Globals.tmpl
+        # 
+        # Created by Graham Dennis on 2008-01-03.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    featureName = 'Globals'
+
+    _mainCheetahMethod_for_Globals= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(Globals, '_initCheetahAttributes'):
+    templateAPIClass = getattr(Globals, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(Globals)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=Globals()).run()
+
+
diff --git a/xpdeint/Features/Globals.tmpl b/xpdeint/Features/Globals.tmpl
new file mode 100644
index 0000000..33bd45f
--- /dev/null
+++ b/xpdeint/Features/Globals.tmpl
@@ -0,0 +1,34 @@
+@*
+Globals.tmpl
+
+Created by Graham Dennis on 2008-01-03.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features._Feature
+
+ at def description: 'Globals' element
+ at attr featureName = 'Globals'
+
+ at def globals
+  @#
+  @super
+  @#
+
+${codeBlocks['globalsCode'].codeString}@slurp
+  @#
+ at end def
diff --git a/xpdeint/Features/HDF5Format.py b/xpdeint/Features/HDF5Format.py
new file mode 100644
index 0000000..7377d2a
--- /dev/null
+++ b/xpdeint/Features/HDF5Format.py
@@ -0,0 +1,630 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features._HDF5Format import _HDF5Format
+from xpdeint.Geometry.SplitUniformDimensionRepresentation import SplitUniformDimensionRepresentation
+from xpdeint.CallOnceGuards import callOnceGuard, callOncePerInstanceGuard
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.095543
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/HDF5Format.tmpl'
+__CHEETAH_srcLastModified__ = 'Wed Aug  1 11:52:34 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class HDF5Format(_HDF5Format):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(HDF5Format, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: HDF5 output format at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''HDF5 output format''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOnceGuard
+    def includes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def includes at line 32, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(HDF5Format, self).includes()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''#if defined(HAVE_HDF5_HL)
+  #include <hdf5_hl.h>
+#endif
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeOutFunctionImplementationBody(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def writeOutFunctionImplementationBody($dict) at line 41, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"writeOutFunctionImplementationBegin",False)(dict) # u'${writeOutFunctionImplementationBegin(dict)}' on line 43, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${writeOutFunctionImplementationBegin(dict)}')) # from line 43, col 1.
+        write(u'''
+''')
+        featureOrdering = ['Driver']
+        featureDict = dict.copy()
+        featureDict['extraIndent'] = 0
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('binaryWriteOutBegin', featureOrdering, featureDict) # u"${insertCodeForFeatures('binaryWriteOutBegin', featureOrdering, featureDict)}" on line 48, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('binaryWriteOutBegin', featureOrdering, featureDict)}")) # from line 48, col 1.
+        extraIndent = featureDict['extraIndent']
+        write(u'''
+''')
+        _v = VFFSL(SL,"writeOutFunctionContents",False)(dict) # u'${writeOutFunctionContents(dict), extraIndent=extraIndent}' on line 51, col 1
+        if _v is not None: write(_filter(_v, extraIndent=extraIndent, rawExpr=u'${writeOutFunctionContents(dict), extraIndent=extraIndent}')) # from line 51, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('binaryWriteOutEnd', featureOrdering, featureDict) # u"${insertCodeForFeaturesInReverseOrder('binaryWriteOutEnd', featureOrdering, featureDict)}" on line 53, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeaturesInReverseOrder('binaryWriteOutEnd', featureOrdering, featureDict)}")) # from line 53, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"writeOutFunctionImplementationEnd",False)(dict) # u'${writeOutFunctionImplementationEnd(dict)}' on line 55, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${writeOutFunctionImplementationEnd(dict)}')) # from line 55, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def truncateOutputFiles(self, baseFilename, **KWS):
+
+
+
+        ## CHEETAH: generated from @def truncateOutputFiles($baseFilename) at line 59, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''char _dataFilename[200];
+snprintf(_dataFilename, 200, "%s.h5", ''')
+        _v = VFFSL(SL,"baseFilename",True) # u'${baseFilename}' on line 61, col 39
+        if _v is not None: write(_filter(_v, rawExpr=u'${baseFilename}')) # from line 61, col 39.
+        write(u''');
+
+H5Fclose(H5Fcreate(_dataFilename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT));
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeOutFunctionContents(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def writeOutFunctionContents($dict) at line 67, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        fp = dict['fp']
+        baseFilename = dict['baseFilename']
+        groupID = dict['groupID']
+        field = dict['field']
+        basis = dict['basis']
+        dependentVariables = dict['dependentVariables']
+        componentCount = 0
+        for variable in VFFSL(SL,"dependentVariables",True): # generated from line 76, col 3
+            componentCount += len(VFFSL(SL,"variable.vector.components",True))
+            if VFFSL(SL,"variable.vector.type",True) == 'complex': # generated from line 78, col 5
+                componentCount += len(VFFSL(SL,"variable.vector.components",True))
+        dict['componentCount'] = componentCount
+        # 
+        write(u'''char _h5Filename[200];
+snprintf(_h5Filename, 200, "%s.h5", ''')
+        _v = VFFSL(SL,"baseFilename",True) # u'${baseFilename}' on line 85, col 37
+        if _v is not None: write(_filter(_v, rawExpr=u'${baseFilename}')) # from line 85, col 37.
+        write(u''');
+
+/* Open the file */
+hid_t hdf5_file = H5Fopen(_h5Filename, H5F_ACC_RDWR, H5P_DEFAULT);
+
+/* Create the group for this data */
+hid_t group;
+if (!H5Lexists(hdf5_file, "/''')
+        _v = VFFSL(SL,"groupID",True) # u'${groupID}' on line 92, col 29
+        if _v is not None: write(_filter(_v, rawExpr=u'${groupID}')) # from line 92, col 29.
+        write(u'''", H5P_DEFAULT))
+  group = H5Gcreate(hdf5_file, "/''')
+        _v = VFFSL(SL,"groupID",True) # u'${groupID}' on line 93, col 34
+        if _v is not None: write(_filter(_v, rawExpr=u'${groupID}')) # from line 93, col 34.
+        write(u'''", H5P_DEFAULT);
+else
+  group = H5Gopen(hdf5_file, "/''')
+        _v = VFFSL(SL,"groupID",True) # u'${groupID}' on line 95, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'${groupID}')) # from line 95, col 32.
+        write(u'''");
+
+if (''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 97, col 5
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 97, col 5.
+        write(u''') {
+  fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 98, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 98, col 11.
+        write(u''', "    <Stream><Metalink Format=\\"HDF5\\" Type=\\"Remote\\" Group=\\"/''')
+        _v = VFFSL(SL,"groupID",True) # u'${groupID}' on line 98, col 80
+        if _v is not None: write(_filter(_v, rawExpr=u'${groupID}')) # from line 98, col 80.
+        write(u'''\\"/>\\n");
+  fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 99, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 99, col 11.
+        write(u''', "%s.h5\\n", ''')
+        _v = VFFSL(SL,"baseFilename",True) # u'${baseFilename}' on line 99, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'${baseFilename}')) # from line 99, col 27.
+        write(u''');
+  fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 100, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 100, col 11.
+        write(u''', "    </Stream>\\n");
+}
+
+/* Create the coordinate data sets */
+hsize_t coordinate_length;
+hid_t coordinate_dataspace;
+''')
+        for dim in field.dimensions: # generated from line 106, col 3
+            dimRep = dim.inBasis(basis)
+            write(u'''coordinate_length = ''')
+            _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 108, col 21
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 108, col 21.
+            write(u''';
+coordinate_dataspace = H5Screate_simple(1, &coordinate_length, NULL);
+''')
+            dataType = {'real': 'H5T_NATIVE_REAL', 'long': 'H5T_NATIVE_LONG'}[VFFSL(SL,"dimRep.type",True)]
+            write(u'''hid_t dataset_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 111, col 15
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 111, col 15.
+            write(u''';
+if (!H5Lexists(hdf5_file, "/''')
+            _v = VFFSL(SL,"groupID",True) # u'${groupID}' on line 112, col 29
+            if _v is not None: write(_filter(_v, rawExpr=u'${groupID}')) # from line 112, col 29.
+            write(u'''/''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 112, col 40
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 112, col 40.
+            write(u'''", H5P_DEFAULT))
+  dataset_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 113, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 113, col 11.
+            write(u''' = H5Dcreate(hdf5_file, "/''')
+            _v = VFFSL(SL,"groupID",True) # u'${groupID}' on line 113, col 51
+            if _v is not None: write(_filter(_v, rawExpr=u'${groupID}')) # from line 113, col 51.
+            write(u'''/''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 113, col 62
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 113, col 62.
+            write(u'''", ''')
+            _v = VFFSL(SL,"dataType",True) # u'${dataType}' on line 113, col 79
+            if _v is not None: write(_filter(_v, rawExpr=u'${dataType}')) # from line 113, col 79.
+            write(u''', coordinate_dataspace, H5P_DEFAULT);
+else
+  dataset_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 115, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 115, col 11.
+            write(u''' = H5Dopen(hdf5_file, "/''')
+            _v = VFFSL(SL,"groupID",True) # u'${groupID}' on line 115, col 49
+            if _v is not None: write(_filter(_v, rawExpr=u'${groupID}')) # from line 115, col 49.
+            write(u'''/''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 115, col 60
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 115, col 60.
+            write(u'''");
+''')
+            if isinstance(dimRep, SplitUniformDimensionRepresentation): # generated from line 116, col 5
+                dimArrayName = ''.join([str(VFFSL(SL,"dimRep.name",True)),u'_data'])
+                _v = VFFSL(SL,"dimRep.type",True) # u'${dimRep.type}' on line 118, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.type}')) # from line 118, col 1.
+                write(u'''* ''')
+                _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 118, col 17
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 118, col 17.
+                write(u''' = (''')
+                _v = VFFSL(SL,"dimRep.type",True) # u'${dimRep.type}' on line 118, col 36
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.type}')) # from line 118, col 36.
+                write(u'''*)xmds_malloc(''')
+                _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 118, col 64
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 118, col 64.
+                write(u''' * sizeof(''')
+                _v = VFFSL(SL,"dimRep.type",True) # u'${dimRep.type}' on line 118, col 97
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.type}')) # from line 118, col 97.
+                write(u'''));
+for (long _i0 = 0; _i0 < ''')
+                _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 119, col 26
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 119, col 26.
+                write(u'''; _i0++) {
+  ''')
+                _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 120, col 3
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 120, col 3.
+                write(u'''[_i0] = ''')
+                _v = VFFSL(SL,"dimRep.arrayName",True) # u'${dimRep.arrayName}' on line 120, col 26
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.arrayName}')) # from line 120, col 26.
+                write(u'''[(_i0 + (''')
+                _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 120, col 54
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 120, col 54.
+                write(u'''+1)/2) % ''')
+                _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 120, col 86
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 120, col 86.
+                write(u'''];
+}
+''')
+            else: # generated from line 122, col 5
+                dimArrayName = dimRep.arrayName
+            write(u'''H5Dwrite(dataset_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 125, col 18
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 125, col 18.
+            write(u''', ''')
+            _v = VFFSL(SL,"dataType",True) # u'$dataType' on line 125, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'$dataType')) # from line 125, col 34.
+            write(u''', H5S_ALL, H5S_ALL, H5P_DEFAULT, ''')
+            _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 125, col 76
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 125, col 76.
+            write(u''');
+#if defined(HAVE_HDF5_HL)
+  H5DSset_scale(dataset_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 127, col 25
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 127, col 25.
+            write(u''', "''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 127, col 42
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 127, col 42.
+            write(u'''");
+#endif
+
+''')
+            if isinstance(dimRep, SplitUniformDimensionRepresentation): # generated from line 130, col 5
+                write(u'''xmds_free(''')
+                _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 131, col 11
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 131, col 11.
+                write(u''');
+''')
+            write(u'''H5Sclose(coordinate_dataspace);
+''')
+        write(u'''
+hsize_t file_dims[] = {''')
+        _v = ', '.join(dim.inBasis(basis).globalLattice for dim in field.dimensions) # u"${', '.join(dim.inBasis(basis).globalLattice for dim in field.dimensions)}" on line 136, col 24
+        if _v is not None: write(_filter(_v, rawExpr=u"${', '.join(dim.inBasis(basis).globalLattice for dim in field.dimensions)}")) # from line 136, col 24.
+        write(u'''};
+hid_t file_dataspace = H5Screate_simple(''')
+        _v = VFFSL(SL,"len",False)(field.dimensions) # u'${len(field.dimensions)}' on line 137, col 41
+        if _v is not None: write(_filter(_v, rawExpr=u'${len(field.dimensions)}')) # from line 137, col 41.
+        write(u''', file_dims, NULL);
+
+''')
+        for variable in dependentVariables: # generated from line 139, col 3
+            if VFFSL(SL,"variable.vector.type",True) == 'real': # generated from line 140, col 5
+                variable['separatedComponents'] = list(enumerate(VFFSL(SL,"variable.components",True)))
+            else: # generated from line 142, col 5
+                components = []
+                variable['separatedComponents'] = components
+                for offset, componentName in enumerate(VFFSL(SL,"variable.components",True)): # generated from line 145, col 7
+                    components.extend([(2*offset, componentName + 'R'), (2*offset+1, componentName + 'I')])
+            for offset, componentName in VFFSL(SL,"variable.separatedComponents",True): # generated from line 149, col 5
+                write(u'''hid_t dataset_''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 150, col 15
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 150, col 15.
+                write(u''';
+if (!H5Lexists(hdf5_file, "/''')
+                _v = VFFSL(SL,"groupID",True) # u'${groupID}' on line 151, col 29
+                if _v is not None: write(_filter(_v, rawExpr=u'${groupID}')) # from line 151, col 29.
+                write(u'''/''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 151, col 40
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 151, col 40.
+                write(u'''", H5P_DEFAULT))
+  dataset_''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 152, col 11
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 152, col 11.
+                write(u''' = H5Dcreate(hdf5_file, "/''')
+                _v = VFFSL(SL,"groupID",True) # u'${groupID}' on line 152, col 53
+                if _v is not None: write(_filter(_v, rawExpr=u'${groupID}')) # from line 152, col 53.
+                write(u'''/''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 152, col 64
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 152, col 64.
+                write(u'''", H5T_NATIVE_REAL, file_dataspace, H5P_DEFAULT);
+else
+  dataset_''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 154, col 11
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 154, col 11.
+                write(u''' = H5Dopen(hdf5_file, "/''')
+                _v = VFFSL(SL,"groupID",True) # u'${groupID}' on line 154, col 51
+                if _v is not None: write(_filter(_v, rawExpr=u'${groupID}')) # from line 154, col 51.
+                write(u'''/''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 154, col 62
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 154, col 62.
+                write(u'''");
+#if defined(HAVE_HDF5_HL)
+''')
+                for dimNum, dim in enumerate(field.dimensions): # generated from line 156, col 7
+                    write(u'''  H5DSattach_scale(dataset_''')
+                    _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 157, col 28
+                    if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 157, col 28.
+                    write(u''', dataset_''')
+                    _v = VFN(VFN(VFFSL(SL,"dim",True),"inBasis",False)(basis),"name",True) # u'${dim.inBasis(basis).name}' on line 157, col 54
+                    if _v is not None: write(_filter(_v, rawExpr=u'${dim.inBasis(basis).name}')) # from line 157, col 54.
+                    write(u''', ''')
+                    _v = VFFSL(SL,"dimNum",True) # u'${dimNum}' on line 157, col 82
+                    if _v is not None: write(_filter(_v, rawExpr=u'${dimNum}')) # from line 157, col 82.
+                    write(u''');
+''')
+                write(u'''#endif
+''')
+        for dim in field.dimensions: # generated from line 162, col 3
+            dimRep = dim.inBasis(basis)
+            write(u'''H5Dclose(dataset_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 164, col 18
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 164, col 18.
+            write(u''');
+''')
+        write(u'''
+''')
+        #  This is where all of the magic MPI code goes
+        featureOrdering = ['Driver']
+        featureDict = dict.copy()
+        featureDict['extraIndent'] = 0
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('binaryWriteOutWriteDataBegin', VFFSL(SL,"featureOrdering",True), featureDict) # u"${insertCodeForFeatures('binaryWriteOutWriteDataBegin', $featureOrdering, featureDict)}" on line 171, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('binaryWriteOutWriteDataBegin', $featureOrdering, featureDict)}")) # from line 171, col 1.
+        extraIndent = featureDict['extraIndent']
+        dict['operation'] = 'write'
+        dict['variables'] = dict['dependentVariables']
+        write(u'''
+if (''')
+        _v = VFN(VFFSL(SL,"field",True),"sizeInBasis",False)(basis) # u'${field.sizeInBasis(basis)}' on line 176, col 5
+        if _v is not None: write(_filter(_v, rawExpr=u'${field.sizeInBasis(basis)}')) # from line 176, col 5.
+        write(u''') {
+  ''')
+        _v = VFFSL(SL,"processData",False)(dict) # u'${processData(dict), autoIndent=True, extraIndent=extraIndent}' on line 177, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, extraIndent=extraIndent, rawExpr=u'${processData(dict), autoIndent=True, extraIndent=extraIndent}')) # from line 177, col 3.
+        write(u'''}
+
+''')
+        #  This is where the rest of the magic MPI code goes
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('binaryWriteOutWriteDataEnd', VFFSL(SL,"featureOrdering",True), featureDict) # u"${insertCodeForFeaturesInReverseOrder('binaryWriteOutWriteDataEnd', $featureOrdering, featureDict)}" on line 181, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeaturesInReverseOrder('binaryWriteOutWriteDataEnd', $featureOrdering, featureDict)}")) # from line 181, col 1.
+        write(u'''
+''')
+        for variable in dependentVariables: # generated from line 183, col 3
+            for offset, componentName in VFFSL(SL,"variable.separatedComponents",True): # generated from line 184, col 5
+                write(u'''H5Dclose(dataset_''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 185, col 18
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 185, col 18.
+                write(u''');
+''')
+        write(u'''
+H5Sclose(file_dataspace);
+H5Gclose(group);
+H5Fclose(hdf5_file);
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # HDF5Format.tmpl
+        # 
+        # Created by Graham Dennis on 2009-01-24.
+        # 
+        # Copyright (c) 2009-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    name = 'hdf5'
+
+    mpiSafe = True
+
+    _mainCheetahMethod_for_HDF5Format= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(HDF5Format, '_initCheetahAttributes'):
+    templateAPIClass = getattr(HDF5Format, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(HDF5Format)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=HDF5Format()).run()
+
+
diff --git a/xpdeint/Features/HDF5Format.tmpl b/xpdeint/Features/HDF5Format.tmpl
new file mode 100644
index 0000000..ad8f3b7
--- /dev/null
+++ b/xpdeint/Features/HDF5Format.tmpl
@@ -0,0 +1,193 @@
+@*
+HDF5Format.tmpl
+
+Created by Graham Dennis on 2009-01-24.
+
+Copyright (c) 2009-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features._HDF5Format
+ at from xpdeint.Geometry.SplitUniformDimensionRepresentation import SplitUniformDimensionRepresentation
+ at from xpdeint.CallOnceGuards import callOnceGuard, callOncePerInstanceGuard
+
+ at def description: HDF5 output format
+
+ at attr $name = 'hdf5'
+ at attr $mpiSafe = True
+
+@@callOnceGuard
+ at def includes
+  @#
+  @super
+  @#
+#if defined(HAVE_HDF5_HL)
+  #include <hdf5_hl.h>
+#endif
+ at end def
+
+ at def writeOutFunctionImplementationBody($dict)
+  @#
+${writeOutFunctionImplementationBegin(dict)}@slurp
+
+  @set $featureOrdering = ['Driver']
+  @set $featureDict = dict.copy()
+  @set $featureDict['extraIndent'] = 0
+${insertCodeForFeatures('binaryWriteOutBegin', featureOrdering, featureDict)}@slurp
+  @set $extraIndent = featureDict['extraIndent']
+
+${writeOutFunctionContents(dict), extraIndent=extraIndent}@slurp
+
+${insertCodeForFeaturesInReverseOrder('binaryWriteOutEnd', featureOrdering, featureDict)}@slurp
+
+${writeOutFunctionImplementationEnd(dict)}@slurp
+  @#
+ at end def
+
+ at def truncateOutputFiles($baseFilename)
+char _dataFilename[200];
+snprintf(_dataFilename, 200, "%s.h5", ${baseFilename});
+
+H5Fclose(H5Fcreate(_dataFilename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT));
+ at end def
+
+
+ at def writeOutFunctionContents($dict)
+  @#
+  @set $fp = dict['fp']
+  @set $baseFilename = dict['baseFilename']
+  @set $groupID = dict['groupID']
+  @set $field = dict['field']
+  @set $basis = dict['basis']
+  @set $dependentVariables = dict['dependentVariables']
+  @set $componentCount = 0
+  @for $variable in $dependentVariables
+    @set $componentCount += len($variable.vector.components)
+    @if $variable.vector.type == 'complex'
+      @set $componentCount += len($variable.vector.components)
+    @end if
+  @end for
+  @set dict['componentCount'] = componentCount
+  @#
+char _h5Filename[200];
+snprintf(_h5Filename, 200, "%s.h5", ${baseFilename});
+
+/* Open the file */
+hid_t hdf5_file = H5Fopen(_h5Filename, H5F_ACC_RDWR, H5P_DEFAULT);
+
+/* Create the group for this data */
+hid_t group;
+if (!H5Lexists(hdf5_file, "/${groupID}", H5P_DEFAULT))
+  group = H5Gcreate(hdf5_file, "/${groupID}", H5P_DEFAULT);
+else
+  group = H5Gopen(hdf5_file, "/${groupID}");
+
+if ($fp) {
+  fprintf($fp, "    <Stream><Metalink Format=\"HDF5\" Type=\"Remote\" Group=\"/${groupID}\"/>\n");
+  fprintf($fp, "%s.h5\n", ${baseFilename});
+  fprintf($fp, "    </Stream>\n");
+}
+
+/* Create the coordinate data sets */
+hsize_t coordinate_length;
+hid_t coordinate_dataspace;
+  @for dim in field.dimensions
+    @set $dimRep = dim.inBasis(basis)
+coordinate_length = ${dimRep.globalLattice};
+coordinate_dataspace = H5Screate_simple(1, &coordinate_length, NULL);
+    @set $dataType = {'real': 'H5T_NATIVE_REAL', 'long': 'H5T_NATIVE_LONG'}[$dimRep.type]
+hid_t dataset_${dimRep.name};
+if (!H5Lexists(hdf5_file, "/${groupID}/${dimRep.name}", H5P_DEFAULT))
+  dataset_${dimRep.name} = H5Dcreate(hdf5_file, "/${groupID}/${dimRep.name}", ${dataType}, coordinate_dataspace, H5P_DEFAULT);
+else
+  dataset_${dimRep.name} = H5Dopen(hdf5_file, "/${groupID}/${dimRep.name}");
+    @if isinstance(dimRep, SplitUniformDimensionRepresentation)
+      @set $dimArrayName = c'${dimRep.name}_data'
+${dimRep.type}* ${dimArrayName} = (${dimRep.type}*)xmds_malloc(${dimRep.globalLattice} * sizeof(${dimRep.type}));
+for (long _i0 = 0; _i0 < ${dimRep.globalLattice}; _i0++) {
+  ${dimArrayName}[_i0] = ${dimRep.arrayName}[(_i0 + (${dimRep.globalLattice}+1)/2) % ${dimRep.globalLattice}];
+}
+    @else
+      @set $dimArrayName = dimRep.arrayName
+    @end if
+H5Dwrite(dataset_${dimRep.name}, $dataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, ${dimArrayName});
+#if defined(HAVE_HDF5_HL)
+  H5DSset_scale(dataset_${dimRep.name}, "${dimRep.name}");
+#endif
+
+    @if isinstance(dimRep, SplitUniformDimensionRepresentation)
+xmds_free(${dimArrayName});
+    @end if
+H5Sclose(coordinate_dataspace);
+  @end for
+
+hsize_t file_dims[] = {${', '.join(dim.inBasis(basis).globalLattice for dim in field.dimensions)}};
+hid_t file_dataspace = H5Screate_simple(${len(field.dimensions)}, file_dims, NULL);
+
+  @for variable in dependentVariables
+    @if $variable.vector.type == 'real'
+      @set $variable['separatedComponents'] = list(enumerate($variable.components))
+    @else
+      @set $components = []
+      @set variable['separatedComponents'] = components
+      @for offset, componentName in enumerate($variable.components)
+        @silent components.extend([(2*offset, componentName + 'R'), (2*offset+1, componentName + 'I')])
+      @end for
+    @end if
+    @for offset, componentName in $variable.separatedComponents
+hid_t dataset_${componentName};
+if (!H5Lexists(hdf5_file, "/${groupID}/${componentName}", H5P_DEFAULT))
+  dataset_${componentName} = H5Dcreate(hdf5_file, "/${groupID}/${componentName}", H5T_NATIVE_REAL, file_dataspace, H5P_DEFAULT);
+else
+  dataset_${componentName} = H5Dopen(hdf5_file, "/${groupID}/${componentName}");
+#if defined(HAVE_HDF5_HL)
+      @for dimNum, dim in enumerate(field.dimensions)
+  H5DSattach_scale(dataset_${componentName}, dataset_${dim.inBasis(basis).name}, ${dimNum});
+      @end for
+#endif
+    @end for
+  @end for
+  @for dim in field.dimensions
+    @set $dimRep = dim.inBasis(basis)
+H5Dclose(dataset_${dimRep.name});
+  @end for
+
+  @# This is where all of the magic MPI code goes
+  @set $featureOrdering = ['Driver']
+  @set $featureDict = dict.copy()
+  @set $featureDict['extraIndent'] = 0
+${insertCodeForFeatures('binaryWriteOutWriteDataBegin', $featureOrdering, featureDict)}@slurp
+  @set $extraIndent = featureDict['extraIndent']
+  @silent dict['operation'] = 'write'
+  @silent dict['variables'] = dict['dependentVariables']
+
+if (${field.sizeInBasis(basis)}) {
+  ${processData(dict), autoIndent=True, extraIndent=extraIndent}@slurp
+}
+
+  @# This is where the rest of the magic MPI code goes
+${insertCodeForFeaturesInReverseOrder('binaryWriteOutWriteDataEnd', $featureOrdering, featureDict)}@slurp
+
+  @for variable in dependentVariables
+    @for offset, componentName in $variable.separatedComponents
+H5Dclose(dataset_${componentName});
+    @end for
+  @end for
+
+H5Sclose(file_dataspace);
+H5Gclose(group);
+H5Fclose(hdf5_file);
+  @#
+ at end def
diff --git a/xpdeint/Features/HaltNonFinite.py b/xpdeint/Features/HaltNonFinite.py
new file mode 100644
index 0000000..78eb162
--- /dev/null
+++ b/xpdeint/Features/HaltNonFinite.py
@@ -0,0 +1,256 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features._Feature import _Feature
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.043321
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/HaltNonFinite.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class HaltNonFinite(_Feature):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(HaltNonFinite, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Halt simulation on non-finite results at line 25, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Halt simulation on non-finite results''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def postSingleStep(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def postSingleStep($dict) at line 29, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        integrator = dict['caller']
+        write(u'''// Check if a component of any integration vector is non-finite
+// no need to check all components since they will be quickly mixed
+''')
+        # 
+        write(u'''if (''')
+        separator = ''
+        for integrationVector in integrator.integrationVectors: # generated from line 37, col 3
+            suffix = ''
+            if integrationVector.type == 'complex': # generated from line 39, col 5
+                #  Check the real component
+                suffix = '.Re()'
+            _v = VFFSL(SL,"separator",True) # u'${separator}' on line 43, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${separator}')) # from line 43, col 1.
+            write(u'''_xmds_isnonfinite(_active_''')
+            _v = VFFSL(SL,"integrationVector.id",True) # u'${integrationVector.id}' on line 43, col 39
+            if _v is not None: write(_filter(_v, rawExpr=u'${integrationVector.id}')) # from line 43, col 39.
+            write(u'''[0]''')
+            _v = VFFSL(SL,"suffix",True) # u'${suffix}' on line 43, col 65
+            if _v is not None: write(_filter(_v, rawExpr=u'${suffix}')) # from line 43, col 65.
+            write(u''')''')
+            separator = ' || '
+        write(u''') {
+  // One of the integration vectors has gone non-finite.
+  // Sample any moment groups that have pending samples,
+  // then leave the integrator.
+  _LOG(_WARNING_LOG_LEVEL, "WARNING: halt_non_finite: Integration halted at ''')
+        _v = VFFSL(SL,"integrator.propagationDimension",True) # u'${integrator.propagationDimension}' on line 50, col 77
+        if _v is not None: write(_filter(_v, rawExpr=u'${integrator.propagationDimension}')) # from line 50, col 77.
+        write(u''' = %e.\\n"
+                           "         Non-finite number in integration vector in segment ''')
+        _v = VFFSL(SL,"integrator.segmentNumber",True) # u'${integrator.segmentNumber}' on line 51, col 89
+        if _v is not None: write(_filter(_v, rawExpr=u'${integrator.segmentNumber}')) # from line 51, col 89.
+        write(u'''.\\n", ''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'$propagationDimension' on line 51, col 122
+        if _v is not None: write(_filter(_v, rawExpr=u'$propagationDimension')) # from line 51, col 122.
+        write(u''');
+  
+  ''')
+        _v = VFFSL(SL,"integrator.earlyTerminationCode",True) # u'${integrator.earlyTerminationCode, autoIndent=True}' on line 53, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${integrator.earlyTerminationCode, autoIndent=True}')) # from line 53, col 3.
+        write(u'''}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # HaltNonFinite.tmpl
+        # 
+        # Created by Graham Dennis on 2008-05-04.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        # Based on code originally written by Gabriel McManus
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    featureName = 'HaltNonFinite'
+
+    uselib = ['safe_math']
+
+    _mainCheetahMethod_for_HaltNonFinite= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(HaltNonFinite, '_initCheetahAttributes'):
+    templateAPIClass = getattr(HaltNonFinite, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(HaltNonFinite)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=HaltNonFinite()).run()
+
+
diff --git a/xpdeint/Features/HaltNonFinite.tmpl b/xpdeint/Features/HaltNonFinite.tmpl
new file mode 100644
index 0000000..0996b11
--- /dev/null
+++ b/xpdeint/Features/HaltNonFinite.tmpl
@@ -0,0 +1,56 @@
+@*
+HaltNonFinite.tmpl
+
+Created by Graham Dennis on 2008-05-04.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Based on code originally written by Gabriel McManus
+*@
+ at extends xpdeint.Features._Feature
+
+ at def description: Halt simulation on non-finite results
+ at attr featureName = 'HaltNonFinite'
+ at attr uselib = ['safe_math']
+
+ at def postSingleStep($dict)
+  @#
+  @set $integrator = dict['caller']
+// Check if a component of any integration vector is non-finite
+// no need to check all components since they will be quickly mixed
+  @#
+if (@slurp
+  @set $separator = ''
+  @for integrationVector in integrator.integrationVectors
+    @set $suffix = ''
+    @if integrationVector.type == 'complex'
+      @# Check the real component
+      @set $suffix = '.Re()'
+    @end if
+${separator}_xmds_isnonfinite(_active_${integrationVector.id}[0]${suffix})@slurp
+    @set $separator = ' || '
+  @end for
+) {
+  // One of the integration vectors has gone non-finite.
+  // Sample any moment groups that have pending samples,
+  // then leave the integrator.
+  _LOG(_WARNING_LOG_LEVEL, "WARNING: halt_non_finite: Integration halted at ${integrator.propagationDimension} = %e.\n"
+                           "         Non-finite number in integration vector in segment ${integrator.segmentNumber}.\n", $propagationDimension);
+  
+  ${integrator.earlyTerminationCode, autoIndent=True}@slurp
+}
+  @#
+ at end def
diff --git a/xpdeint/Features/MaxIterations.py b/xpdeint/Features/MaxIterations.py
new file mode 100644
index 0000000..5ef8ed2
--- /dev/null
+++ b/xpdeint/Features/MaxIterations.py
@@ -0,0 +1,174 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.048385
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/MaxIterations.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class MaxIterations(Template):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(MaxIterations, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def respond(self, trans=None):
+
+
+
+        ## CHEETAH: main method generated for this template
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # MaxIterations.tmpl
+        # 
+        # Created by Graham Dennis on 2008-05-04.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        # @extends xpdeint.Features._Feature
+        # 
+        # @def description: Restrict the maximum number of iterations for an adaptive integrator
+        # @attr featureName = 'MaxIterations'
+        # 
+        # @def integrateAdaptiveStepOuterLoopEnd($dict)
+        #   @#
+        #   @set $integrator = dict['caller']
+        #   @#
+        #   @# If we don't have a maximum number of iterations for this integrator
+        #   @# then we don't have any code to insert
+        #   @if not integrator in $maxIterationsDict
+        #     @return
+        #   @end if
+        #   @#
+        # 
+        # if (_attempted_steps >= ${maxIterationsDict[integrator]}) {
+        #   _LOG(_WARNING_LOG_LEVEL, "Reached ${maxIterationsDict[integrator]} iterations, exiting at ${integrator.propagationDimension} = %e\n"
+        #                            "Last error: %e\n"
+        #                            "Last planned timestep: %e\n\n", ${integrator.propagationDimension}, _error, _step);
+        #   
+        #   ${integrator.earlyTerminationCode, autoIndent=True}@slurp
+        # }
+        #   @#
+        # @end def
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_MaxIterations= 'respond'
+
+## END CLASS DEFINITION
+
+if not hasattr(MaxIterations, '_initCheetahAttributes'):
+    templateAPIClass = getattr(MaxIterations, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(MaxIterations)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=MaxIterations()).run()
+
+
diff --git a/xpdeint/Features/MaxIterations.tmpl b/xpdeint/Features/MaxIterations.tmpl
new file mode 100644
index 0000000..03d42a4
--- /dev/null
+++ b/xpdeint/Features/MaxIterations.tmpl
@@ -0,0 +1,46 @@
+@*
+MaxIterations.tmpl
+
+Created by Graham Dennis on 2008-05-04.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+ at extends xpdeint.Features._Feature
+
+ at def description: Restrict the maximum number of iterations for an adaptive integrator
+ at attr featureName = 'MaxIterations'
+
+ at def integrateAdaptiveStepOuterLoopEnd($dict)
+  @#
+  @set $integrator = dict['caller']
+  @#
+  @# If we don't have a maximum number of iterations for this integrator
+  @# then we don't have any code to insert
+  @if not integrator in $maxIterationsDict
+    @return
+  @end if
+  @#
+
+if (_attempted_steps >= ${maxIterationsDict[integrator]}) {
+  _LOG(_WARNING_LOG_LEVEL, "Reached ${maxIterationsDict[integrator]} iterations, exiting at ${integrator.propagationDimension} = %e\n"
+                           "Last error: %e\n"
+                           "Last planned timestep: %e\n\n", ${integrator.propagationDimension}, _error, _step);
+  
+  ${integrator.earlyTerminationCode, autoIndent=True}@slurp
+}
+  @#
+ at end def
+
diff --git a/xpdeint/Features/OpenMP.py b/xpdeint/Features/OpenMP.py
new file mode 100644
index 0000000..759d8b3
--- /dev/null
+++ b/xpdeint/Features/OpenMP.py
@@ -0,0 +1,542 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features._Feature import _Feature
+from xpdeint.CallOnceGuards import callOnceGuard
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.203906
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/OpenMP.tmpl'
+__CHEETAH_srcLastModified__ = 'Thu Oct 18 19:50:44 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class OpenMP(_Feature):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(OpenMP, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: OpenMP at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''OpenMP''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOnceGuard
+    def includes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def includes at line 31, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(OpenMP, self).includes()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''#ifdef _OPENMP
+#include <omp.h>
+#endif
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def mainBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def mainBegin($dict) at line 41, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        if VFFSL(SL,"threadCount",True): # generated from line 43, col 3
+            write(u'''#ifdef _OPENMP
+omp_set_num_threads(''')
+            _v = VFFSL(SL,"threadCount",True) # u'$threadCount' on line 45, col 21
+            if _v is not None: write(_filter(_v, rawExpr=u'$threadCount')) # from line 45, col 21.
+            write(u''');
+#endif
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def loopOverVectorsWithInnerContentTemplateBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def loopOverVectorsWithInnerContentTemplateBegin($dict) at line 51, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        if 'UNVECTORISABLE' in dict['templateString']: # generated from line 53, col 3
+            return
+        write(u'''#ifdef _OPENMP
+#pragma omp parallel for
+#endif
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def loopOverVectorsWithInnerContentBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def loopOverVectorsWithInnerContentBegin($dict) at line 62, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        if 'UNVECTORISABLE' in dict['loopCode']: # generated from line 64, col 3
+            return
+        # 
+        vectors = dict['vectors']
+        index_pointers = [''.join([u'_',str(VFFSL(SL,"vector.id",True)),u'_index_pointer']) for vector in vectors]
+        # 
+        write(u'''bool __initialised = false;
+#ifdef _OPENMP
+''')
+        suffix = ''
+        if index_pointers: # generated from line 74, col 3
+            suffix = ''.join([u' private(',str(", ".join(index_pointers)),u')'])
+        write(u'''#pragma omp parallel for firstprivate(__initialised)''')
+        _v = VFFSL(SL,"suffix",True) # u'${suffix}' on line 77, col 53
+        if _v is not None: write(_filter(_v, rawExpr=u'${suffix}')) # from line 77, col 53.
+        write(u'''
+#endif
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def loopOverVectorsWithInnerContentEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def loopOverVectorsWithInnerContentEnd($dict) at line 82, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        if 'UNVECTORISABLE' in dict['loopCode']: # generated from line 84, col 3
+            return
+        # 
+        vectors = dict['vectors']
+        # 
+        write(u'''if (!__initialised) {
+''')
+        for vector in vectors: # generated from line 91, col 3
+            write(u'''  _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 92, col 4
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 92, col 4.
+            write(u'''_index_pointer = _i0 * _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 92, col 40
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 92, col 40.
+            write(u'''_ncomponents;
+''')
+        write(u'''  __initialised = true;
+}
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def loopOverFieldInBasisWithVectorsAndInnerContentLoopOpenBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def loopOverFieldInBasisWithVectorsAndInnerContentLoopOpenBegin($dict) at line 98, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  What about the copyDeltaA code? Is that parallel-safe?
+        #  If we have already parallelised a dimension, don't do any more
+        #  and if we can't parallelise, don't.
+        if 'UNVECTORISABLE' in dict['loopCode'] or 'openMPParallelDimRep' in dict: # generated from line 103, col 3
+            return
+        # 
+        vectorOverrides = dict['vectorOverrides']
+        field = dict['field']
+        basis = dict['basis']
+        dimRep = dict['dimRep']
+        dimensionsBeingIntegratedOver = set()
+        if vectorOverrides: # generated from line 112, col 3
+            dimensionsBeingIntegratedOver.update(field.dimensions)
+            for dim in dimensionsBeingIntegratedOver.copy(): # generated from line 114, col 5
+                for vector in vectorOverrides: # generated from line 115, col 7
+                    if vector.field.hasDimension(dim): # generated from line 116, col 9
+                        dimensionsBeingIntegratedOver.discard(dim)
+                        break
+        # 
+        #  If this dim rep is being integrated over, we can't parallelise this dimension, so return
+        for dim in dimensionsBeingIntegratedOver: # generated from line 125, col 3
+            if dim.inBasis(basis) == dimRep: # generated from line 126, col 5
+                return
+        # 
+        for fieldDimRep in reversed(field.inBasis(basis)): # generated from line 131, col 3
+            #  If there's pre or post dimension loop opening code, we can't trust that we can parallelise this.
+            if fieldDimRep.name in dict['preDimensionLoopOpeningCode'] or fieldDimRep.name in dict['postDimensionLoopClosingCode']: # generated from line 133, col 5
+                return
+            # 
+            if fieldDimRep == dimRep: # generated from line 137, col 5
+                break
+        # 
+        dict['openMPParallelDimRep'] = dict['dimRep']
+        # 
+        vectorsNotRequiringExplicitIndexPointers = dict['vectorsNotRequiringExplicitIndexPointers']
+        private_variables = [''.join([u'_',str(VFFSL(SL,"vector.id",True)),u'_index_pointer']) for vector in vectorsNotRequiringExplicitIndexPointers]
+        for vector in dict['vectorOverrides']: # generated from line 146, col 3
+            private_variables.extend(vector.components)
+        # 
+        suffix = ''
+        if private_variables: # generated from line 151, col 3
+            suffix = ''.join([u' private(',str(", ".join(private_variables)),u')'])
+        write(u'''bool __initialised = false;
+#ifdef _OPENMP
+#pragma omp parallel for firstprivate(__initialised)''')
+        _v = VFFSL(SL,"suffix",True) # u'${suffix}' on line 156, col 53
+        if _v is not None: write(_filter(_v, rawExpr=u'${suffix}')) # from line 156, col 53.
+        write(u'''
+#endif
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def loopOverFieldInBasisWithVectorsAndInnerContentLoopOpenEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def loopOverFieldInBasisWithVectorsAndInnerContentLoopOpenEnd($dict) at line 161, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  Only complete initialisation for the parallel loop if this is that loop
+        if dict.get('openMPParallelDimRep') is not dict['dimRep']: # generated from line 164, col 3
+            return
+        # 
+        vectorsNotRequiringExplicitIndexPointers = dict['vectorsNotRequiringExplicitIndexPointers']
+        dimRep = dict['dimRep']
+        field = dict['field']
+        basis = dict['basis']
+        # 
+        write(u'''if (!__initialised) {
+''')
+        for vector in vectorsNotRequiringExplicitIndexPointers: # generated from line 174, col 3
+            write(u'''  _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 175, col 4
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 175, col 4.
+            write(u'''_index_pointer = ''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 175, col 33
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 175, col 33.
+            write(u''' * ''')
+            _v = VFN(VFFSL(SL,"vector.field",True),"localPointsInDimensionsAfterDimRepInBasis",False)(dimRep, basis) # u'${vector.field.localPointsInDimensionsAfterDimRepInBasis(dimRep, basis)}' on line 175, col 55
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.field.localPointsInDimensionsAfterDimRepInBasis(dimRep, basis)}')) # from line 175, col 55.
+            write(u''' * _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 175, col 131
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 175, col 131.
+            write(u'''_ncomponents;
+''')
+            for prefixDimRep in field.inBasis(basis): # generated from line 176, col 5
+                if prefixDimRep is dimRep: # generated from line 177, col 7
+                    break
+                write(u'''  _''')
+                _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 180, col 4
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 180, col 4.
+                write(u'''_index_pointer += ''')
+                _v = VFFSL(SL,"prefixDimRep.loopIndex",True) # u'${prefixDimRep.loopIndex}' on line 180, col 34
+                if _v is not None: write(_filter(_v, rawExpr=u'${prefixDimRep.loopIndex}')) # from line 180, col 34.
+                write(u''' * ''')
+                _v = VFN(VFFSL(SL,"vector.field",True),"localPointsInDimensionsAfterDimRepInBasis",False)(prefixDimRep, basis) # u'${vector.field.localPointsInDimensionsAfterDimRepInBasis(prefixDimRep, basis)}' on line 180, col 62
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.field.localPointsInDimensionsAfterDimRepInBasis(prefixDimRep, basis)}')) # from line 180, col 62.
+                write(u''' * _''')
+                _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 180, col 144
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 180, col 144.
+                write(u'''_ncomponents;
+''')
+        write(u'''  __initialised = true;
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # OpenMP.tmpl
+        # 
+        # Created by Graham Dennis on 2007-12-18.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    featureName = 'OpenMP'
+
+    uselib = ['openmp']
+
+    _mainCheetahMethod_for_OpenMP= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(OpenMP, '_initCheetahAttributes'):
+    templateAPIClass = getattr(OpenMP, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(OpenMP)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=OpenMP()).run()
+
+
diff --git a/xpdeint/Features/OpenMP.tmpl b/xpdeint/Features/OpenMP.tmpl
new file mode 100644
index 0000000..b7d0a84
--- /dev/null
+++ b/xpdeint/Features/OpenMP.tmpl
@@ -0,0 +1,186 @@
+@*
+OpenMP.tmpl
+
+Created by Graham Dennis on 2007-12-18.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features._Feature
+
+ at from xpdeint.CallOnceGuards import callOnceGuard
+
+ at def description: OpenMP
+ at attr featureName = 'OpenMP'
+ at attr uselib = ['openmp']
+
+@@callOnceGuard
+ at def includes
+  @#
+  @super
+  @#
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+  @#
+ at end def
+
+ at def mainBegin($dict)
+  @#
+  @if $threadCount
+#ifdef _OPENMP
+omp_set_num_threads($threadCount);
+#endif
+  @end if
+  @#
+ at end def
+
+ at def loopOverVectorsWithInnerContentTemplateBegin($dict)
+  @#
+  @if 'UNVECTORISABLE' in dict['templateString']
+    @return
+  @end if
+#ifdef _OPENMP
+#pragma omp parallel for
+#endif
+  @#
+ at end def
+
+ at def loopOverVectorsWithInnerContentBegin($dict)
+  @#
+  @if 'UNVECTORISABLE' in dict['loopCode']
+    @return
+  @end if
+  @#
+  @set $vectors = dict['vectors']
+  @set $index_pointers = [c'_${vector.id}_index_pointer' for vector in vectors]
+  @#
+bool __initialised = false;
+#ifdef _OPENMP
+  @set suffix = ''
+  @if index_pointers
+    @set suffix = c' private(${", ".join(index_pointers)})'
+  @end if
+#pragma omp parallel for firstprivate(__initialised)${suffix}
+#endif
+  @#
+ at end def
+
+ at def loopOverVectorsWithInnerContentEnd($dict)
+  @#
+  @if 'UNVECTORISABLE' in dict['loopCode']
+    @return
+  @end if
+  @#
+  @set $vectors = dict['vectors']
+  @#
+if (!__initialised) {
+  @for vector in vectors
+  _${vector.id}_index_pointer = _i0 * _${vector.id}_ncomponents;
+  @end for
+  __initialised = true;
+}
+ at end def
+
+ at def loopOverFieldInBasisWithVectorsAndInnerContentLoopOpenBegin($dict)
+  @#
+  @# What about the copyDeltaA code? Is that parallel-safe?
+  @# If we have already parallelised a dimension, don't do any more
+  @# and if we can't parallelise, don't.
+  @if 'UNVECTORISABLE' in dict['loopCode'] or 'openMPParallelDimRep' in dict
+    @return
+  @end if
+  @#
+  @set vectorOverrides = dict['vectorOverrides']
+  @set field = dict['field']
+  @set basis = dict['basis']
+  @set dimRep = dict['dimRep']
+  @set dimensionsBeingIntegratedOver = set()
+  @if vectorOverrides
+    @silent dimensionsBeingIntegratedOver.update(field.dimensions)
+    @for dim in dimensionsBeingIntegratedOver.copy()
+      @for vector in vectorOverrides
+        @if vector.field.hasDimension(dim)
+          @silent dimensionsBeingIntegratedOver.discard(dim)
+          @break
+        @end if
+      @end for
+    @end for
+  @end if
+  @#
+  @# If this dim rep is being integrated over, we can't parallelise this dimension, so return
+  @for dim in dimensionsBeingIntegratedOver
+    @if dim.inBasis(basis) == dimRep
+      @return
+    @end if
+  @end for
+  @#
+  @for fieldDimRep in reversed(field.inBasis(basis))
+    @# If there's pre or post dimension loop opening code, we can't trust that we can parallelise this.
+    @if fieldDimRep.name in dict['preDimensionLoopOpeningCode'] or fieldDimRep.name in dict['postDimensionLoopClosingCode']
+      @return
+    @end if
+    @#
+    @if fieldDimRep == dimRep
+      @break
+    @end if
+  @end for
+  @#
+  @silent dict['openMPParallelDimRep'] = dict['dimRep']
+  @#
+  @set $vectorsNotRequiringExplicitIndexPointers = dict['vectorsNotRequiringExplicitIndexPointers']
+  @set $private_variables = [c'_${vector.id}_index_pointer' for vector in vectorsNotRequiringExplicitIndexPointers]
+  @for vector in dict['vectorOverrides']
+    @silent private_variables.extend(vector.components)
+  @end for
+  @#
+  @set suffix = ''
+  @if private_variables
+    @set suffix = c' private(${", ".join(private_variables)})'
+  @end if
+bool __initialised = false;
+#ifdef _OPENMP
+#pragma omp parallel for firstprivate(__initialised)${suffix}
+#endif
+  @#
+ at end def
+
+ at def loopOverFieldInBasisWithVectorsAndInnerContentLoopOpenEnd($dict)
+  @#
+  @# Only complete initialisation for the parallel loop if this is that loop
+  @if dict.get('openMPParallelDimRep') is not dict['dimRep']
+    @return
+  @end if
+  @#
+  @set $vectorsNotRequiringExplicitIndexPointers = dict['vectorsNotRequiringExplicitIndexPointers']
+  @set $dimRep = dict['dimRep']
+  @set $field = dict['field']
+  @set $basis = dict['basis']
+  @#
+if (!__initialised) {
+  @for vector in vectorsNotRequiringExplicitIndexPointers
+  _${vector.id}_index_pointer = ${dimRep.loopIndex} * ${vector.field.localPointsInDimensionsAfterDimRepInBasis(dimRep, basis)} * _${vector.id}_ncomponents;
+    @for prefixDimRep in field.inBasis(basis)
+      @if prefixDimRep is dimRep
+        @break
+      @end if
+  _${vector.id}_index_pointer += ${prefixDimRep.loopIndex} * ${vector.field.localPointsInDimensionsAfterDimRepInBasis(prefixDimRep, basis)} * _${vector.id}_ncomponents;
+    @end for
+  @end for
+  __initialised = true;
+}
+  @#
+ at end def
\ No newline at end of file
diff --git a/xpdeint/Features/Output.py b/xpdeint/Features/Output.py
new file mode 100644
index 0000000..9f4cf7e
--- /dev/null
+++ b/xpdeint/Features/Output.py
@@ -0,0 +1,538 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features._Feature import _Feature
+from xpdeint.Utilities import lazy_property
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.205964
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/Output.tmpl'
+__CHEETAH_srcLastModified__ = 'Mon Sep  3 14:15:51 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class Output(_Feature):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(Output, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: output at line 25, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''output''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @lazy_property
+    def outputGroups(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def outputGroups at line 29, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        return len(VFFSL(SL,"momentGroups",True))
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def functionPrototypes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def functionPrototypes at line 33, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(Output, self).functionPrototypes()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''void _write_output();
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def functionImplementations(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def functionImplementations at line 41, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(Output, self).functionImplementations()
+        if _v is not None: write(_filter(_v))
+        # 
+        _v = VFFSL(SL,"writeOutFunctionImplementation",True) # u'${writeOutFunctionImplementation}' on line 45, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${writeOutFunctionImplementation}')) # from line 45, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeOutFunctionImplementation(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def writeOutFunctionImplementation at line 49, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''void _write_output()
+{
+  _LOG(_SIMULATION_LOG_LEVEL, "Generating output for ''')
+        _v = VFFSL(SL,"simulationName",True) # u'${simulationName}' on line 52, col 54
+        if _v is not None: write(_filter(_v, rawExpr=u'${simulationName}')) # from line 52, col 54.
+        write(u'''\\n");
+  
+''')
+        if not VFFSL(SL,"momentGroups",True): # generated from line 54, col 3
+            write(u'''  _LOG(_SIMULATION_LOG_LEVEL, "Warning: No output moment groups.\\n");
+''')
+        else: # generated from line 56, col 3
+            featureOrdering = ['Driver', 'ChunkedOutput']
+            write(u'''  ''')
+            _v = VFFSL(SL,"insertCodeForFeatures",False)('writeOutBegin', featureOrdering) # u"${insertCodeForFeatures('writeOutBegin', featureOrdering), autoIndent=True}" on line 58, col 3
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeatures('writeOutBegin', featureOrdering), autoIndent=True}")) # from line 58, col 3.
+            write(u'''  
+  ''')
+            _v = VFN(VFFSL(SL,"outputFormat",True),"writeOutSetup",False)(''.join([u'("',str(VFFSL(SL,"filename",True)),u'" + gsArgsAndValues).c_str()']), self) # u'${outputFormat.writeOutSetup(c\'("${filename}" + gsArgsAndValues).c_str()\', self), autoIndent=True}' on line 60, col 3
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${outputFormat.writeOutSetup(c\'("${filename}" + gsArgsAndValues).c_str()\', self), autoIndent=True}')) # from line 60, col 3.
+            for momentGroup in VFFSL(SL,"momentGroups",True): # generated from line 61, col 5
+                write(u'''  ''')
+                _v = VFN(VFN(VFFSL(SL,"momentGroup",True),"functions",True)['writeOut'],"call",False)(_outfile = '_outfile') # u"${momentGroup.functions['writeOut'].call(_outfile = '_outfile')}" on line 62, col 3
+                if _v is not None: write(_filter(_v, rawExpr=u"${momentGroup.functions['writeOut'].call(_outfile = '_outfile')}")) # from line 62, col 3.
+                write(u'''
+''')
+            write(u'''  
+  ''')
+            _v = VFFSL(SL,"outputFormat.writeOutTearDown",True) # u'${outputFormat.writeOutTearDown, autoIndent=True}' on line 65, col 3
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${outputFormat.writeOutTearDown, autoIndent=True}')) # from line 65, col 3.
+            write(u'''  
+  ''')
+            _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('writeOutEnd', featureOrdering) # u"${insertCodeForFeaturesInReverseOrder('writeOutEnd', featureOrdering), autoIndent=True}" on line 67, col 3
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeaturesInReverseOrder('writeOutEnd', featureOrdering), autoIndent=True}")) # from line 67, col 3.
+        write(u'''}
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeOutFunctionImplementationBody(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def writeOutFunctionImplementationBody($dict) at line 72, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        dict.setdefault('baseFilename', ''.join([u'("',str(VFFSL(SL,"filename",True)),u'" + gsArgsAndValues).c_str()']))
+        dict.setdefault('outputGroupFilenameSuffix', '_' + dict['caller'].name)
+        _v = VFN(VFFSL(SL,"outputFormat",True),"writeOutFunctionImplementationBody",False)(dict) # u'${outputFormat.writeOutFunctionImplementationBody(dict)}' on line 75, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${outputFormat.writeOutFunctionImplementationBody(dict)}')) # from line 75, col 1.
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def mainEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def mainEnd($dict) at line 78, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''
+_write_output();
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def integrateFixedStepInnerLoopEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def integrateFixedStepInnerLoopEnd($dict) at line 83, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        integrator = dict['caller']
+        assert len(VFFSL(SL,"momentGroups",True)) == len(VFFSL(SL,"integrator.samples",True))
+        # 
+        for momentGroupNumber, sampleCount in enumerate(VFFSL(SL,"integrator.samples",True)): # generated from line 88, col 3
+            if VFFSL(SL,"sampleCount",True) > 0: # generated from line 89, col 5
+                assert (VFFSL(SL,"integrator.stepCount",True) % VFFSL(SL,"sampleCount",True)) == 0
+                sampleEveryNthStep = VFFSL(SL,"integrator.stepCount",True) / VFFSL(SL,"sampleCount",True)
+                write(u'''if ((_istep % ''')
+                _v = VFFSL(SL,"sampleEveryNthStep",True) # u'$sampleEveryNthStep' on line 92, col 15
+                if _v is not None: write(_filter(_v, rawExpr=u'$sampleEveryNthStep')) # from line 92, col 15.
+                write(u''') == ''')
+                _v = VFFSL(SL,"sampleEveryNthStep",True) - 1 # u'${sampleEveryNthStep - 1}' on line 92, col 39
+                if _v is not None: write(_filter(_v, rawExpr=u'${sampleEveryNthStep - 1}')) # from line 92, col 39.
+                write(u''')
+  _mg''')
+                _v = VFFSL(SL,"momentGroupNumber",True) # u'${momentGroupNumber}' on line 93, col 6
+                if _v is not None: write(_filter(_v, rawExpr=u'${momentGroupNumber}')) # from line 93, col 6.
+                write(u'''_sample();
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def integrateAdaptiveStepOuterLoopEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def integrateAdaptiveStepOuterLoopEnd($dict) at line 99, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        integrator = dict['caller']
+        assert len(VFFSL(SL,"momentGroups",True)) == len(VFFSL(SL,"integrator.samples",True))
+        # 
+        write(u'''if (_break_next) {
+''')
+        for momentGroupNumber, sampleCount in enumerate(VFFSL(SL,"integrator.samples",True)): # generated from line 105, col 3
+            write(u'''  if (_next_sample_flag[''')
+            _v = VFFSL(SL,"momentGroupNumber",True) # u'$momentGroupNumber' on line 106, col 25
+            if _v is not None: write(_filter(_v, rawExpr=u'$momentGroupNumber')) # from line 106, col 25.
+            write(u''']) {
+    _mg''')
+            _v = VFFSL(SL,"momentGroupNumber",True) # u'${momentGroupNumber}' on line 107, col 8
+            if _v is not None: write(_filter(_v, rawExpr=u'${momentGroupNumber}')) # from line 107, col 8.
+            write(u'''_sample();
+    _next_sample_counter[''')
+            _v = VFFSL(SL,"momentGroupNumber",True) # u'$momentGroupNumber' on line 108, col 26
+            if _v is not None: write(_filter(_v, rawExpr=u'$momentGroupNumber')) # from line 108, col 26.
+            write(u''']++;
+  }
+''')
+        momentGroupCount = len(VFFSL(SL,"integrator.samples",True))
+        write(u'''  if (_next_sample_flag[''')
+        _v = VFFSL(SL,"momentGroupCount",True) # u'${momentGroupCount}' on line 112, col 25
+        if _v is not None: write(_filter(_v, rawExpr=u'${momentGroupCount}')) # from line 112, col 25.
+        write(u'''])
+    _next_sample_flag[''')
+        _v = VFFSL(SL,"momentGroupCount",True) + 1 # u'${momentGroupCount + 1}' on line 113, col 23
+        if _v is not None: write(_filter(_v, rawExpr=u'${momentGroupCount + 1}')) # from line 113, col 23.
+        write(u'''] = true;
+  else {
+    _break_next = false;
+    _''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 116, col 6
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 116, col 6.
+        write(u'''_break_next = _''')
+        _v = VFFSL(SL,"integrator.name",True) # u'${integrator.name}' on line 116, col 44
+        if _v is not None: write(_filter(_v, rawExpr=u'${integrator.name}')) # from line 116, col 44.
+        write(u'''_setup_sampling(_next_sample_flag, _next_sample_counter);
+  }
+}
+
+if ( (_''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 120, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 120, col 8.
+        write(u'''_local + _step)*(1.0 + _EPSILON) > _''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 120, col 67
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 120, col 67.
+        write(u'''_break_next) {
+  _break_next = true;
+  _LOG(_SAMPLE_LOG_LEVEL, "Current timestep: %e\\n", _old_step);
+  _step = _''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 123, col 12
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 123, col 12.
+        write(u'''_break_next - _''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 123, col 50
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 123, col 50.
+        write(u'''_local;
+}
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # Output.tmpl
+        # 
+        # Created by Graham Dennis on 2007-08-26.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    featureName = 'Output'
+
+    _mainCheetahMethod_for_Output= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(Output, '_initCheetahAttributes'):
+    templateAPIClass = getattr(Output, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(Output)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=Output()).run()
+
+
diff --git a/xpdeint/Features/Output.tmpl b/xpdeint/Features/Output.tmpl
new file mode 100644
index 0000000..41c0eed
--- /dev/null
+++ b/xpdeint/Features/Output.tmpl
@@ -0,0 +1,125 @@
+@*
+Output.tmpl
+
+Created by Graham Dennis on 2007-08-26.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features._Feature
+ at from xpdeint.Utilities import lazy_property
+
+ at def description: output
+ at attr $featureName = 'Output'
+
+@@lazy_property
+ at def outputGroups
+  @return len($momentGroups)
+ at end def
+
+ at def functionPrototypes
+  @#
+  @super
+  @#
+void _write_output();
+  @#
+ at end def
+
+ at def functionImplementations
+  @#
+  @super
+  @#
+${writeOutFunctionImplementation}@slurp
+  @#
+ at end def
+
+ at def writeOutFunctionImplementation
+void _write_output()
+{
+  _LOG(_SIMULATION_LOG_LEVEL, "Generating output for ${simulationName}\n");
+  
+  @if not $momentGroups
+  _LOG(_SIMULATION_LOG_LEVEL, "Warning: No output moment groups.\n");
+  @else
+    @set $featureOrdering = ['Driver', 'ChunkedOutput']
+  ${insertCodeForFeatures('writeOutBegin', featureOrdering), autoIndent=True}@slurp
+  
+  ${outputFormat.writeOutSetup(c'("${filename}" + gsArgsAndValues).c_str()', self), autoIndent=True}@slurp
+    @for $momentGroup in $momentGroups
+  ${momentGroup.functions['writeOut'].call(_outfile = '_outfile')}
+    @end for
+  
+  ${outputFormat.writeOutTearDown, autoIndent=True}@slurp
+  
+  ${insertCodeForFeaturesInReverseOrder('writeOutEnd', featureOrdering), autoIndent=True}@slurp
+  @end if
+}
+ at end def
+
+ at def writeOutFunctionImplementationBody($dict)
+  @silent dict.setdefault('baseFilename', c'("${filename}" + gsArgsAndValues).c_str()')
+  @silent dict.setdefault('outputGroupFilenameSuffix', '_' + dict['caller'].name)
+${outputFormat.writeOutFunctionImplementationBody(dict)}@slurp
+ at end def
+
+ at def mainEnd($dict)
+
+_write_output();
+ at end def
+
+ at def integrateFixedStepInnerLoopEnd($dict)
+  @#
+  @set $integrator = dict['caller']
+  @assert len($momentGroups) == len($integrator.samples)
+  @#
+  @for $momentGroupNumber, $sampleCount in enumerate($integrator.samples)
+    @if $sampleCount > 0
+      @assert ($integrator.stepCount % $sampleCount) == 0
+      @set $sampleEveryNthStep = $integrator.stepCount / $sampleCount
+if ((_istep % $sampleEveryNthStep) == ${sampleEveryNthStep - 1})
+  _mg${momentGroupNumber}_sample();
+    @end if
+  @end for
+  @#
+ at end def
+
+ at def integrateAdaptiveStepOuterLoopEnd($dict)
+  @#
+  @set $integrator = dict['caller']
+  @assert len($momentGroups) == len($integrator.samples)
+  @#
+if (_break_next) {
+  @for $momentGroupNumber, $sampleCount in enumerate($integrator.samples)
+  if (_next_sample_flag[$momentGroupNumber]) {
+    _mg${momentGroupNumber}_sample();
+    _next_sample_counter[$momentGroupNumber]++;
+  }
+  @end for
+  @set $momentGroupCount = len($integrator.samples)
+  if (_next_sample_flag[${momentGroupCount}])
+    _next_sample_flag[${momentGroupCount + 1}] = true;
+  else {
+    _break_next = false;
+    _${propagationDimension}_break_next = _${integrator.name}_setup_sampling(_next_sample_flag, _next_sample_counter);
+  }
+}
+
+if ( (_${propagationDimension}_local + _step)*(1.0 + _EPSILON) > _${propagationDimension}_break_next) {
+  _break_next = true;
+  _LOG(_SAMPLE_LOG_LEVEL, "Current timestep: %e\n", _old_step);
+  _step = _${propagationDimension}_break_next - _${propagationDimension}_local;
+}
+ at end def
diff --git a/xpdeint/Features/OutputFormat.py b/xpdeint/Features/OutputFormat.py
new file mode 100644
index 0000000..b5b68cd
--- /dev/null
+++ b/xpdeint/Features/OutputFormat.py
@@ -0,0 +1,694 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.ScriptElement import ScriptElement
+from xpdeint.PrintfSafeFilter import PrintfSafeFilter
+from xpdeint.CallOnceGuards import callOnceGuard, callOncePerInstanceGuard
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.224401
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/OutputFormat.tmpl'
+__CHEETAH_srcLastModified__ = 'Thu Nov 29 13:43:25 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class OutputFormat(ScriptElement):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(OutputFormat, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Unnamed Output Format at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Unnamed Output Format''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOnceGuard
+    def functionPrototypes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def functionPrototypes at line 33, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(OutputFormat, self).functionPrototypes()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''FILE* _open_xsil_file(const char* _filename);
+void _close_xsil_file(FILE*& fp);
+void _write_xsil_header(FILE* fp);
+void _write_xsil_footer(FILE* fp);
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOnceGuard
+    def functionImplementations(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def functionImplementations at line 45, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(OutputFormat, self).functionImplementations()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''
+FILE* _open_xsil_file(const char* _filename)
+{
+''')
+        featureOrdering = ['Driver']
+        write(u'''  ''')
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('openXSILFile', featureOrdering) # u"${insertCodeForFeatures('openXSILFile', featureOrdering), autoIndent=True}" on line 53, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeatures('openXSILFile', featureOrdering), autoIndent=True}")) # from line 53, col 3.
+        write(u'''  
+  FILE* fp = fopen(_filename, "w");
+  
+  if (fp == NULL)
+    // _LOG will cause the simulation to exit
+    _LOG(_ERROR_LOG_LEVEL, "Unable to open output file \'%s\'.\\n"
+                           "Exiting.\\n", _filename);
+  
+  return fp;
+}
+
+void _close_xsil_file(FILE*& fp)
+{
+  if (fp)
+    fclose(fp);
+  fp = NULL;
+  
+  ''')
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('closeXSILFile', featureOrdering) # u"${insertCodeForFeaturesInReverseOrder('closeXSILFile', featureOrdering), autoIndent=True}" on line 71, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeaturesInReverseOrder('closeXSILFile', featureOrdering), autoIndent=True}")) # from line 71, col 3.
+        write(u'''}
+
+''')
+        _v = VFFSL(SL,"writeXSILHeaderFunctionImplementation",True) # u'${writeXSILHeaderFunctionImplementation}' on line 74, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${writeXSILHeaderFunctionImplementation}')) # from line 74, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"writeXSILFooterFunctionImplementation",True) # u'${writeXSILFooterFunctionImplementation}' on line 76, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${writeXSILFooterFunctionImplementation}')) # from line 76, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeXSILHeaderFunctionImplementation(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def writeXSILHeaderFunctionImplementation at line 80, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''void _write_xsil_header(FILE* fp)
+{
+  if (!fp)
+    return;
+''')
+        #  The input script may contain entity references to other documents.  The content of the XSIL is the full, expanded simulation
+        #  so that a simulation can be re-run even if the external references have changed.
+        expandedInputScript = VFN(VFFSL(SL,"xmlDocument",True),"toxml",False)()
+        #  Find the end tag in a case-insensitive way
+        indexForEndTag = VFN(VFN(VFFSL(SL,"expandedInputScript",True),"lower",False)(),"rfind",False)('</simulation>')
+        xsilOutputHeader = VFFSL(SL,"expandedInputScript",True)[0:VFFSL(SL,"indexForEndTag",True)]
+        _orig_filter_32065636 = _filter
+        _filter = self._CHEETAH__currentFilter = VFFSL(SL,"PrintfSafeFilter",True)(self).filter
+        for line in VFN(VFFSL(SL,"xsilOutputHeader",True),"splitlines",False)(): # generated from line 92, col 5
+            write(u'''  fprintf(fp, "''')
+            _v = VFFSL(SL,"line",True) # u'${line}' on line 93, col 16
+            if _v is not None: write(_filter(_v, rawExpr=u'${line}')) # from line 93, col 16.
+            write(u'''\\n");
+''')
+        write(u'''  
+  fprintf(fp, "\\n<info>\\n");
+  fprintf(fp, "Script compiled with XMDS2 version ''')
+        _v = VFFSL(SL,"xmds.versionString",True) # u'${xmds.versionString}' on line 97, col 51
+        if _v is not None: write(_filter(_v, rawExpr=u'${xmds.versionString}')) # from line 97, col 51.
+        write(u''' (''')
+        _v = VFFSL(SL,"xmds.subversionRevision",True) # u'${xmds.subversionRevision}' on line 97, col 74
+        if _v is not None: write(_filter(_v, rawExpr=u'${xmds.subversionRevision}')) # from line 97, col 74.
+        write(u''')\\n");
+  fprintf(fp, "See http://www.xmds.org for more information.\\n");
+''')
+        _filter = self._CHEETAH__currentFilter = _orig_filter_32065636
+        # 
+        featureOrderingXSILInfo = ['Arguments', 'Stochastic']
+        write(u'''  ''')
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('xsilOutputInfo', VFFSL(SL,"featureOrderingXSILInfo",True), {'fp': 'fp'}) # u"${insertCodeForFeatures('xsilOutputInfo', $featureOrderingXSILInfo, {'fp': 'fp'}), autoIndent=True}" on line 102, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeatures('xsilOutputInfo', $featureOrderingXSILInfo, {'fp': 'fp'}), autoIndent=True}")) # from line 102, col 3.
+        write(u'''  fprintf(fp, "</info>\\n");
+  
+}
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeXSILFooterFunctionImplementation(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def writeXSILFooterFunctionImplementation at line 108, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''// In addition to writing the footer (if \'fp\' is not NULL)
+// this function closes the fp file pointer.
+void _write_xsil_footer(FILE* fp)
+{
+  if (fp) {
+    fprintf(fp, "</simulation>\\n");
+  }
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeOutSetup(self, filename, caller, **KWS):
+
+
+
+        ## CHEETAH: generated from @def writeOutSetup($filename, $caller) at line 121, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''char *_xsilFilename = (char*)malloc(256);
+snprintf(_xsilFilename, 256, "%s.xsil", ''')
+        _v = VFFSL(SL,"filename",True) # u'$filename' on line 123, col 41
+        if _v is not None: write(_filter(_v, rawExpr=u'$filename')) # from line 123, col 41.
+        write(u''');
+
+FILE* _outfile = _open_xsil_file(_xsilFilename);
+
+if (_outfile) {
+  _write_xsil_header(_outfile);
+''')
+        if not caller in VFFSL(SL,"outputFilesTruncated",True): # generated from line 129, col 3
+            write(u'''  ''')
+            _v = VFFSL(SL,"truncateOutputFiles",False)(filename) # u'${truncateOutputFiles(filename), autoIndent=True}' on line 130, col 3
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${truncateOutputFiles(filename), autoIndent=True}')) # from line 130, col 3.
+            VFN(VFFSL(SL,"outputFilesTruncated",True),"add",False)(caller)
+        write(u'''}
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeOutTearDown(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def writeOutTearDown at line 136, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''_write_xsil_footer(_outfile);
+_close_xsil_file(_outfile);
+free(_xsilFilename);
+_xsilFilename = NULL;
+_outfile = NULL;
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def truncateOutputFiles(self, baseFilename, **KWS):
+
+
+
+        ## CHEETAH: generated from @def truncateOutputFiles($baseFilename) at line 144, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeOutFunctionImplementationBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def writeOutFunctionImplementationBegin($dict) at line 147, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        fp = dict['fp']
+        xsilElementName = dict['xsilElementName']
+        field = dict['field']
+        basis = dict['basis']
+        numIndependentVariables = len(VFFSL(SL,"field.dimensions",True))
+        # 
+        dependentVariables = dict['dependentVariables']
+        componentCount = 0
+        for variable in VFFSL(SL,"dependentVariables",True): # generated from line 157, col 3
+            componentCount += len(VFFSL(SL,"variable.vector.components",True))
+            if VFFSL(SL,"variable.vector.type",True) == 'complex': # generated from line 159, col 5
+                componentCount += len(VFFSL(SL,"variable.vector.components",True))
+        # 
+        write(u'''if (''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 164, col 5
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 164, col 5.
+        write(u''') {
+  fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 165, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 165, col 11.
+        write(u''', "\\n");
+  fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 166, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 166, col 11.
+        write(u''', "<XSIL Name=\\"''')
+        _v = VFFSL(SL,"xsilElementName",True) # u'${xsilElementName}' on line 166, col 30
+        if _v is not None: write(_filter(_v, rawExpr=u'${xsilElementName}')) # from line 166, col 30.
+        write(u'''\\">\\n");
+  fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 167, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 167, col 11.
+        write(u''', "  <Param Name=\\"n_independent\\">''')
+        _v = VFFSL(SL,"numIndependentVariables",True) # u'${numIndependentVariables}' on line 167, col 49
+        if _v is not None: write(_filter(_v, rawExpr=u'${numIndependentVariables}')) # from line 167, col 49.
+        write(u'''</Param>\\n");
+  fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 168, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 168, col 11.
+        write(u''', "  <Array Name=\\"variables\\" Type=\\"Text\\">\\n");
+  fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 169, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 169, col 11.
+        write(u''', "    <Dim>''')
+        _v = VFFSL(SL,"numIndependentVariables",True) + componentCount # u'${numIndependentVariables + componentCount}' on line 169, col 26
+        if _v is not None: write(_filter(_v, rawExpr=u'${numIndependentVariables + componentCount}')) # from line 169, col 26.
+        write(u'''</Dim>\\n");
+  fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 170, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 170, col 11.
+        write(u''', "    <Stream><Metalink Format=\\"Text\\" Delimiter=\\" \\\\n\\"/>\\n");
+  fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 171, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 171, col 11.
+        write(u''', "''')
+        #  First loop over the dimensions (the independent variables)
+        for dimension in VFFSL(SL,"field.dimensions",True): # generated from line 173, col 3
+            _v = VFN(VFN(VFFSL(SL,"dimension",True),"inBasis",False)(basis),"name",True) # u'${dimension.inBasis(basis).name}' on line 174, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimension.inBasis(basis).name}')) # from line 174, col 1.
+            write(u''' ''')
+        # 
+        #  Now loop over the dependent variables
+        for variable in VFFSL(SL,"dependentVariables",True): # generated from line 178, col 3
+            for componentName in VFFSL(SL,"variable.components",True): # generated from line 179, col 5
+                if VFFSL(SL,"variable.vector.type",True) == 'real': # generated from line 180, col 7
+                    _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 181, col 1
+                    if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 181, col 1.
+                    write(u''' ''')
+                else: # generated from line 182, col 7
+                    _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 183, col 1
+                    if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 183, col 1.
+                    write(u'''R ''')
+                    _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 183, col 19
+                    if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 183, col 19.
+                    write(u'''I ''')
+        write(u'''\\n");
+  fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 188, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 188, col 11.
+        write(u''', "    </Stream>\\n");
+  fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 189, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 189, col 11.
+        write(u''', "  </Array>\\n");
+  fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 190, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 190, col 11.
+        write(u''', "  <Array Name=\\"data\\" Type=\\"''')
+        _v = VFFSL(SL,"precision",True) # u'${precision}' on line 190, col 47
+        if _v is not None: write(_filter(_v, rawExpr=u'${precision}')) # from line 190, col 47.
+        write(u'''\\">\\n");
+''')
+        # 
+        #  Now loop over the dimensions
+        for dimension in VFFSL(SL,"field.dimensions",True): # generated from line 193, col 3
+            write(u'''  fprintf(''')
+            _v = VFFSL(SL,"fp",True) # u'$fp' on line 194, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 194, col 11.
+            write(u''', "    <Dim>%i</Dim>\\n", ''')
+            _v = VFN(VFN(VFFSL(SL,"dimension",True),"inBasis",False)(basis),"globalLattice",True) # u'$dimension.inBasis(basis).globalLattice' on line 194, col 39
+            if _v is not None: write(_filter(_v, rawExpr=u'$dimension.inBasis(basis).globalLattice')) # from line 194, col 39.
+            write(u''');
+''')
+        #  Now the variables dimension
+        write(u'''  fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 197, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 197, col 11.
+        write(u''', "    <Dim>''')
+        _v = VFFSL(SL,"numIndependentVariables",True) + componentCount # u'${numIndependentVariables + componentCount}' on line 197, col 26
+        if _v is not None: write(_filter(_v, rawExpr=u'${numIndependentVariables + componentCount}')) # from line 197, col 26.
+        write(u'''</Dim>\\n");
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeOutFunctionImplementationEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def writeOutFunctionImplementationEnd($dict) at line 202, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        fp = dict['fp']
+        # 
+        write(u'''if (''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 206, col 5
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 206, col 5.
+        write(u''') {
+  fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 207, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 207, col 11.
+        write(u''', "  </Array>\\n");
+  fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 208, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 208, col 11.
+        write(u''', "</XSIL>\\n");
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # OutputFormat.tmpl
+        # 
+        # Created by Graham Dennis on 2009-01-24.
+        # 
+        # Copyright (c) 2009-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    outputFormatClasses = {}
+
+    outputFormat = False
+
+    mpiSafe = False
+
+    outputFilesTruncated = set()
+
+    _mainCheetahMethod_for_OutputFormat= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(OutputFormat, '_initCheetahAttributes'):
+    templateAPIClass = getattr(OutputFormat, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(OutputFormat)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=OutputFormat()).run()
+
+
diff --git a/xpdeint/Features/OutputFormat.tmpl b/xpdeint/Features/OutputFormat.tmpl
new file mode 100644
index 0000000..5872e97
--- /dev/null
+++ b/xpdeint/Features/OutputFormat.tmpl
@@ -0,0 +1,212 @@
+@*
+OutputFormat.tmpl
+
+Created by Graham Dennis on 2009-01-24.
+
+Copyright (c) 2009-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.ScriptElement.ScriptElement
+ at from xpdeint.PrintfSafeFilter import PrintfSafeFilter
+ at from xpdeint.CallOnceGuards import callOnceGuard, callOncePerInstanceGuard
+
+ at def description: Unnamed Output Format
+ at attr $outputFormatClasses = {}
+ at attr $outputFormat = False
+ at attr $mpiSafe = False
+ at attr $outputFilesTruncated = set()
+
+@@callOnceGuard
+ at def functionPrototypes
+  @#
+  @super
+  @#
+FILE* _open_xsil_file(const char* _filename);
+void _close_xsil_file(FILE*& fp);
+void _write_xsil_header(FILE* fp);
+void _write_xsil_footer(FILE* fp);
+  @#
+ at end def
+
+@@callOnceGuard
+ at def functionImplementations
+  @#
+  @super
+  @#
+
+FILE* _open_xsil_file(const char* _filename)
+{
+  @set $featureOrdering = ['Driver']
+  ${insertCodeForFeatures('openXSILFile', featureOrdering), autoIndent=True}@slurp
+  
+  FILE* fp = fopen(_filename, "w");
+  
+  if (fp == NULL)
+    // _LOG will cause the simulation to exit
+    _LOG(_ERROR_LOG_LEVEL, "Unable to open output file '%s'.\n"
+                           "Exiting.\n", _filename);
+  
+  return fp;
+}
+
+void _close_xsil_file(FILE*& fp)
+{
+  if (fp)
+    fclose(fp);
+  fp = NULL;
+  
+  ${insertCodeForFeaturesInReverseOrder('closeXSILFile', featureOrdering), autoIndent=True}@slurp
+}
+
+${writeXSILHeaderFunctionImplementation}@slurp
+
+${writeXSILFooterFunctionImplementation}@slurp
+  @#
+ at end def
+
+ at def writeXSILHeaderFunctionImplementation
+void _write_xsil_header(FILE* fp)
+{
+  if (!fp)
+    return;
+  @# The input script may contain entity references to other documents.  The content of the XSIL is the full, expanded simulation
+  @# so that a simulation can be re-run even if the external references have changed.
+  @set $expandedInputScript = $xmlDocument.toxml()
+  @# Find the end tag in a case-insensitive way
+  @set $indexForEndTag = $expandedInputScript.lower().rfind('</simulation>')
+  @set $xsilOutputHeader = $expandedInputScript[0:$indexForEndTag]
+  @filter $PrintfSafeFilter
+    @for $line in $xsilOutputHeader.splitlines()
+  fprintf(fp, "${line}\n");
+    @end for
+  
+  fprintf(fp, "\n<info>\n");
+  fprintf(fp, "Script compiled with XMDS2 version ${xmds.versionString} (${xmds.subversionRevision})\n");
+  fprintf(fp, "See http://www.xmds.org for more information.\n");
+  @end filter
+  @#
+  @set $featureOrderingXSILInfo = ['Arguments', 'Stochastic']
+  ${insertCodeForFeatures('xsilOutputInfo', $featureOrderingXSILInfo, {'fp': 'fp'}), autoIndent=True}@slurp
+  fprintf(fp, "</info>\n");
+  
+}
+ at end def
+
+ at def writeXSILFooterFunctionImplementation
+  @#
+// In addition to writing the footer (if 'fp' is not NULL)
+// this function closes the fp file pointer.
+void _write_xsil_footer(FILE* fp)
+{
+  if (fp) {
+    fprintf(fp, "</simulation>\n");
+  }
+}
+  @#
+ at end def
+
+ at def writeOutSetup($filename, $caller)
+char *_xsilFilename = (char*)malloc(256);
+snprintf(_xsilFilename, 256, "%s.xsil", $filename);
+
+FILE* _outfile = _open_xsil_file(_xsilFilename);
+
+if (_outfile) {
+  _write_xsil_header(_outfile);
+  @if not caller in $outputFilesTruncated
+  ${truncateOutputFiles(filename), autoIndent=True}@slurp
+    @silent $outputFilesTruncated.add(caller)
+  @end if
+}
+ at end def
+
+ at def writeOutTearDown
+_write_xsil_footer(_outfile);
+_close_xsil_file(_outfile);
+free(_xsilFilename);
+_xsilFilename = NULL;
+_outfile = NULL;
+ at end def
+
+ at def truncateOutputFiles($baseFilename)
+ at end def
+
+ at def writeOutFunctionImplementationBegin($dict)
+  @#
+  @set $fp = dict['fp']
+  @set $xsilElementName = dict['xsilElementName']
+  @set $field = dict['field']
+  @set $basis = dict['basis']
+  @set $numIndependentVariables = len($field.dimensions)
+  @#
+  @set $dependentVariables = dict['dependentVariables']
+  @set $componentCount = 0
+  @for $variable in $dependentVariables
+    @set $componentCount += len($variable.vector.components)
+    @if $variable.vector.type == 'complex'
+      @set $componentCount += len($variable.vector.components)
+    @end if
+  @end for
+  @#
+if ($fp) {
+  fprintf($fp, "\n");
+  fprintf($fp, "<XSIL Name=\"${xsilElementName}\">\n");
+  fprintf($fp, "  <Param Name=\"n_independent\">${numIndependentVariables}</Param>\n");
+  fprintf($fp, "  <Array Name=\"variables\" Type=\"Text\">\n");
+  fprintf($fp, "    <Dim>${numIndependentVariables + componentCount}</Dim>\n");
+  fprintf($fp, "    <Stream><Metalink Format=\"Text\" Delimiter=\" \\n\"/>\n");
+  fprintf($fp, "@slurp
+  @# First loop over the dimensions (the independent variables)
+  @for $dimension in $field.dimensions
+${dimension.inBasis(basis).name} @slurp
+  @end for
+  @#
+  @# Now loop over the dependent variables
+  @for $variable in $dependentVariables
+    @for $componentName in $variable.components
+      @if $variable.vector.type == 'real'
+${componentName} @slurp
+      @else
+${componentName}R ${componentName}I @slurp
+      @end if
+    @end for
+  @end for
+\n");
+  fprintf($fp, "    </Stream>\n");
+  fprintf($fp, "  </Array>\n");
+  fprintf($fp, "  <Array Name=\"data\" Type=\"${precision}\">\n");
+  @#
+  @# Now loop over the dimensions
+  @for $dimension in $field.dimensions
+  fprintf($fp, "    <Dim>%i</Dim>\n", $dimension.inBasis(basis).globalLattice);
+  @end for
+  @# Now the variables dimension
+  fprintf($fp, "    <Dim>${numIndependentVariables + componentCount}</Dim>\n");
+}
+  @#
+ at end def
+
+ at def writeOutFunctionImplementationEnd($dict)
+  @#
+  @set $fp = dict['fp']
+  @#
+if ($fp) {
+  fprintf($fp, "  </Array>\n");
+  fprintf($fp, "</XSIL>\n");
+}
+  @#
+ at end def
+
diff --git a/xpdeint/Features/Stochastic.py b/xpdeint/Features/Stochastic.py
new file mode 100644
index 0000000..0d4a022
--- /dev/null
+++ b/xpdeint/Features/Stochastic.py
@@ -0,0 +1,786 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features._Stochastic import _Stochastic
+from xpdeint.Operators.DeltaAOperator import DeltaAOperator
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.398146
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/Stochastic.tmpl'
+__CHEETAH_srcLastModified__ = 'Wed Aug 28 15:52:21 2013'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class Stochastic(_Stochastic):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(Stochastic, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Stochastic at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Stochastic''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def globals at line 33, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(Stochastic, self).globals()
+        if _v is not None: write(_filter(_v))
+        # 
+        for integrator in self.adaptiveIntegratorsWithNoises() : # generated from line 37, col 3
+            write(u'''// ********************************************************
+// struct used to store step size and noise vector to ensure
+// stochastic convergence
+struct _dtdWstore_segment''')
+            _v = VFFSL(SL,"integrator.segmentNumber",True) # u'${integrator.segmentNumber}' on line 41, col 26
+            if _v is not None: write(_filter(_v, rawExpr=u'${integrator.segmentNumber}')) # from line 41, col 26.
+            write(u''' {
+  real _step;
+''')
+            # 
+            for noiseVector in integrator.dynamicNoiseVectors: # generated from line 44, col 5
+                write(u'''  ''')
+                _v = VFFSL(SL,"noiseVector.type",True) # u'$noiseVector.type' on line 45, col 3
+                if _v is not None: write(_filter(_v, rawExpr=u'$noiseVector.type')) # from line 45, col 3.
+                write(u'''* _''')
+                _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 45, col 23
+                if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 45, col 23.
+                write(u''';
+''')
+            write(u'''  
+  _dtdWstore_segment''')
+            _v = VFFSL(SL,"integrator.segmentNumber",True) # u'${integrator.segmentNumber}' on line 48, col 21
+            if _v is not None: write(_filter(_v, rawExpr=u'${integrator.segmentNumber}')) # from line 48, col 21.
+            write(u'''() {
+  _step = 0;
+''')
+            # 
+            for noiseVector in integrator.dynamicNoiseVectors: # generated from line 51, col 5
+                write(u'''  _''')
+                _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 52, col 4
+                if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 52, col 4.
+                write(u''' = NULL;
+''')
+            write(u'''  }
+  ~_dtdWstore_segment''')
+            _v = VFFSL(SL,"integrator.segmentNumber",True) # u'${integrator.segmentNumber}' on line 55, col 22
+            if _v is not None: write(_filter(_v, rawExpr=u'${integrator.segmentNumber}')) # from line 55, col 22.
+            write(u'''() {
+''')
+            # 
+            for noiseVector in integrator.dynamicNoiseVectors: # generated from line 57, col 5
+                write(u'''    if (_''')
+                _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 58, col 10
+                if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 58, col 10.
+                write(u''')
+      xmds_free(_''')
+                _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 59, col 18
+                if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 59, col 18.
+                write(u''');
+''')
+            write(u'''  }
+};
+''')
+        # 
+        for dimRep in self.nonUniformDimRepsNeededForGaussianNoise: # generated from line 65, col 3
+            _v = VFFSL(SL,"dimRep.type",True) # u'${dimRep.type}' on line 66, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.type}')) # from line 66, col 1.
+            write(u'''* ''')
+            _v = VFFSL(SL,"dimRep.stepSizeArrayName",True) # u'${dimRep.stepSizeArrayName}' on line 66, col 17
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.stepSizeArrayName}')) # from line 66, col 17.
+            write(u'''_invsqrt = (''')
+            _v = VFFSL(SL,"dimRep.type",True) # u'${dimRep.type}' on line 66, col 56
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.type}')) # from line 66, col 56.
+            write(u'''*) xmds_malloc(sizeof(''')
+            _v = VFFSL(SL,"dimRep.type",True) # u'${dimRep.type}' on line 66, col 92
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.type}')) # from line 66, col 92.
+            write(u''') * (''')
+            _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 66, col 111
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 66, col 111.
+            write(u'''));
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def mainBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def mainBegin($dict) at line 71, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        for dimRep in self.nonUniformDimRepsNeededForGaussianNoise: # generated from line 73, col 3
+            write(u'''for (long ''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 74, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 74, col 11.
+            write(u''' = 0; ''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 74, col 36
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 74, col 36.
+            write(u''' < ''')
+            _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 74, col 58
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 74, col 58.
+            write(u'''; ''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 74, col 83
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 74, col 83.
+            write(u'''++) {
+  ''')
+            _v = VFFSL(SL,"dimRep.stepSizeArrayName",True) # u'${dimRep.stepSizeArrayName}' on line 75, col 3
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.stepSizeArrayName}')) # from line 75, col 3.
+            write(u'''_invsqrt[''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 75, col 39
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 75, col 39.
+            write(u'''] = (real)1.0/sqrt(''')
+            _v = VFFSL(SL,"dimRep.stepSizeArrayName",True) # u'${dimRep.stepSizeArrayName}' on line 75, col 77
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.stepSizeArrayName}')) # from line 75, col 77.
+            write(u'''[''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 75, col 105
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 75, col 105.
+            write(u'''] * (''')
+            _v = VFFSL(SL,"dimRep.volumePrefactor",True) # u'${dimRep.volumePrefactor}' on line 75, col 129
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.volumePrefactor}')) # from line 75, col 129.
+            write(u'''));
+}
+''')
+        write(u'''
+''')
+        for noiseVector in VFFSL(SL,"noiseVectors",True): # generated from line 79, col 3
+            _v = VFFSL(SL,"noiseVector.initialiseGlobalSeeds",True) # u'${noiseVector.initialiseGlobalSeeds}' on line 80, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.initialiseGlobalSeeds}')) # from line 80, col 1.
+            write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def topLevelSequenceBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def topLevelSequenceBegin($dict) at line 86, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        for noiseVector in VFFSL(SL,"noiseVectors",True): # generated from line 88, col 3
+            _v = VFFSL(SL,"noiseVector.initialiseLocalSeeds",True) # u'${noiseVector.initialiseLocalSeeds}' on line 89, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.initialiseLocalSeeds}')) # from line 89, col 1.
+            write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def integrateAdaptiveStepBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def integrateAdaptiveStepBegin($dict) at line 95, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        integrator = dict['caller']
+        # 
+        if not integrator.dynamicNoiseVectors: # generated from line 99, col 3
+            return
+        # 
+        write(u'''typedef _dtdWstore_segment''')
+        _v = VFFSL(SL,"integrator.segmentNumber",True) # u'${integrator.segmentNumber}' on line 103, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'${integrator.segmentNumber}')) # from line 103, col 27.
+        write(u''' _dtdWstore;
+list<_dtdWstore> _noise_list;
+list<_dtdWstore>::iterator _active_node;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def integrateAdaptiveStepEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def integrateAdaptiveStepEnd($dict) at line 109, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        integrator = dict['caller']
+        # 
+        if not integrator.dynamicNoiseVectors: # generated from line 113, col 3
+            return
+        # 
+        for noiseVector in integrator.dynamicNoiseVectors: # generated from line 117, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 118, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 118, col 9.
+            write(u''' = _''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 118, col 30
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 118, col 30.
+            write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def integrateFixedStepInnerLoopBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def integrateFixedStepInnerLoopBegin(dict) at line 123, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        integrator = dict['caller']
+        # 
+        if not integrator.dynamicNoiseVectors: # generated from line 127, col 3
+            return
+        # 
+        for noiseVector in integrator.dynamicNoiseVectors: # generated from line 131, col 3
+            write(u'''
+_active_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 133, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 133, col 9.
+            write(u''' = _''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 133, col 30
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 133, col 30.
+            write(u''';
+''')
+            _v = VFN(VFN(VFFSL(SL,"noiseVector",True),"functions",True)['evaluate'],"call",False)(_step = '_noiseStep') # u"${noiseVector.functions['evaluate'].call(_step = '_noiseStep')}" on line 134, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u"${noiseVector.functions['evaluate'].call(_step = '_noiseStep')}")) # from line 134, col 1.
+            write(u'''
+''')
+        # 
+        if 'ErrorCheck' in VFFSL(SL,"features",True): # generated from line 137, col 3
+            write(u'''
+if (!_half_step) { // For the full step we average the two noises.
+''')
+            for noiseVector in integrator.dynamicNoiseVectors: # generated from line 140, col 5
+                # 
+                write(u'''  _active_''')
+                _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 142, col 11
+                if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 142, col 11.
+                write(u''' = _''')
+                _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 142, col 32
+                if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 142, col 32.
+                write(u'''2;
+  ''')
+                _v = VFN(VFN(VFFSL(SL,"noiseVector",True),"functions",True)['evaluate'],"call",False)(_step = '_noiseStep') # u"${noiseVector.functions['evaluate'].call(_step = '_noiseStep'), autoIndent=True}" on line 143, col 3
+                if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${noiseVector.functions['evaluate'].call(_step = '_noiseStep'), autoIndent=True}")) # from line 143, col 3.
+                write(u'''
+  ''')
+                _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)([noiseVector],
+  """_${vector.id}[$index] = 0.5*(_${vector.id}[$index] + _${vector.id}2[$index]);
+  """, basis = noiseVector.initialBasis)
+                if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${loopOverVectorsWithInnerContentTemplate([noiseVector],\n  """_${vector.id}[$index] = 0.5*(_${vector.id}[$index] + _${vector.id}2[$index]);\n  """, basis = noiseVector.initialBasis), autoIndent=True}')) # from line 144, col 3.
+                write(u'''  _active_''')
+                _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 147, col 11
+                if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 147, col 11.
+                write(u''' = _''')
+                _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 147, col 32
+                if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 147, col 32.
+                write(u''';
+''')
+            write(u'''}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def integrateAdaptiveStepInnerLoopBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def integrateAdaptiveStepInnerLoopBegin(dict) at line 154, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        integrator = dict['caller']
+        # 
+        if not integrator.dynamicNoiseVectors: # generated from line 158, col 3
+            return
+        # 
+        write(u'''if (_noise_list.empty()) {
+  // Noise list empty so start afresh
+  _noise_list.push_front(_dtdWstore());
+  _active_node = _noise_list.begin();
+  _active_node->_step = _step;
+''')
+        for noiseVector in integrator.dynamicNoiseVectors: # generated from line 167, col 3
+            write(u'''  
+  _active_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 169, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 169, col 11.
+            write(u''' =  (''')
+            _v = VFFSL(SL,"noiseVector.type",True) # u'${noiseVector.type}' on line 169, col 33
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.type}')) # from line 169, col 33.
+            write(u'''*) xmds_malloc(sizeof(''')
+            _v = VFFSL(SL,"noiseVector.type",True) # u'${noiseVector.type}' on line 169, col 74
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.type}')) # from line 169, col 74.
+            write(u''') * MAX(''')
+            _v = VFFSL(SL,"noiseVector.allocSize",True) # u'${noiseVector.allocSize}' on line 169, col 101
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.allocSize}')) # from line 169, col 101.
+            write(u''',1));
+  _active_node->_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 170, col 18
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 170, col 18.
+            write(u''' = _active_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 170, col 46
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 170, col 46.
+            write(u''';
+  ''')
+            _v = VFN(VFN(VFFSL(SL,"noiseVector",True),"functions",True)['evaluate'],"call",False)(_step = '_step') # u"${noiseVector.functions['evaluate'].call(_step = '_step')}" on line 171, col 3
+            if _v is not None: write(_filter(_v, rawExpr=u"${noiseVector.functions['evaluate'].call(_step = '_step')}")) # from line 171, col 3.
+            write(u'''
+''')
+        write(u'''} else if (_step*(1.0 + _EPSILON) < _noise_list.begin()->_step) {
+  // Create new smallest time step
+  
+  // If the step is greater than 50% of the current smallest step size
+  // then we should just use half the step size because we are going to have
+  // to do the other half at some point too.
+  
+  const real _old_smallest_step = _noise_list.begin()->_step;
+  
+  if (_step > 0.5*_old_smallest_step*(1.0 + _EPSILON))
+    _step = 0.5*_old_smallest_step;
+  
+''')
+        for noiseVector in integrator.dynamicNoiseVectors: # generated from line 185, col 3
+            #  It is necessary to transform the noise vector back to its original basis, as it may have been transformed in the mean time.
+            write(u'''  ''')
+            _v = VFFSL(SL,"transformVectorsToBasis",False)([noiseVector], noiseVector.initialBasis) # u'${transformVectorsToBasis([noiseVector], noiseVector.initialBasis), autoIndent=True}' on line 187, col 3
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${transformVectorsToBasis([noiseVector], noiseVector.initialBasis), autoIndent=True}')) # from line 187, col 3.
+            write(u'''  _active_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 188, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 188, col 11.
+            write(u''' = (''')
+            _v = VFFSL(SL,"noiseVector.type",True) # u'${noiseVector.type}' on line 188, col 32
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.type}')) # from line 188, col 32.
+            write(u'''*) xmds_malloc(sizeof(''')
+            _v = VFFSL(SL,"noiseVector.type",True) # u'${noiseVector.type}' on line 188, col 73
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.type}')) # from line 188, col 73.
+            write(u''') * MAX(''')
+            _v = VFFSL(SL,"noiseVector.allocSize",True) # u'${noiseVector.allocSize}' on line 188, col 100
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.allocSize}')) # from line 188, col 100.
+            write(u''',1));
+  ''')
+            _v = VFN(VFN(VFFSL(SL,"noiseVector",True),"functions",True)['split'],"call",False)(_new_step = '_step', _old_step = '_old_smallest_step', _old_array = '_noise_list.begin()->_' + noiseVector.id) # u"${noiseVector.functions['split'].call(_new_step = '_step', _old_step = '_old_smallest_step', _old_array = '_noise_list.begin()->_' + noiseVector.id)}" on line 189, col 3
+            if _v is not None: write(_filter(_v, rawExpr=u"${noiseVector.functions['split'].call(_new_step = '_step', _old_step = '_old_smallest_step', _old_array = '_noise_list.begin()->_' + noiseVector.id)}")) # from line 189, col 3.
+            write(u'''
+  
+''')
+        # 
+        write(u'''  _noise_list.push_front(_dtdWstore());
+  _active_node = _noise_list.begin();
+  _active_node->_step = _step;
+''')
+        for noiseVector in integrator.dynamicNoiseVectors: # generated from line 196, col 3
+            write(u'''  _active_node->_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 197, col 18
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 197, col 18.
+            write(u''' = _active_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 197, col 46
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 197, col 46.
+            write(u''';
+''')
+        write(u'''} else {
+  // Use step already attempted
+  for (_active_node = _noise_list.begin(); (_active_node != _noise_list.end()) && (_active_node->_step <= _step*(1.0 + _EPSILON)); _active_node++)
+    ;
+  
+  _active_node--;
+  _step = _active_node->_step;
+''')
+        for noiseVector in integrator.dynamicNoiseVectors: # generated from line 206, col 3
+            write(u'''  _active_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 207, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 207, col 11.
+            write(u''' = _active_node->_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 207, col 46
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 207, col 46.
+            write(u''';
+''')
+            if noiseVector.needsTransforms: # generated from line 208, col 5
+                write(u'''  _''')
+                _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 209, col 4
+                if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 209, col 4.
+                write(u'''_basis = ''')
+                _v = VFFSL(SL,"basisIndexForBasis",False)(noiseVector.initialBasis) # u'${basisIndexForBasis(noiseVector.initialBasis)}' on line 209, col 30
+                if _v is not None: write(_filter(_v, rawExpr=u'${basisIndexForBasis(noiseVector.initialBasis)}')) # from line 209, col 30.
+                write(u''';
+''')
+        write(u'''  
+  if ( _break_next && !((_''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 213, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 213, col 27.
+        write(u'''_local + _step)*(1.0 + _EPSILON) >= _''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 213, col 87
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 213, col 87.
+        write(u'''_break_next))
+    _break_next = false;
+} 
+
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def adaptiveStepSucceeded(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def adaptiveStepSucceeded(dict) at line 220, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        integrator = dict['caller']
+        # 
+        if not integrator.dynamicNoiseVectors: # generated from line 224, col 3
+            return
+        # 
+        write(u'''
+// Trim dtdW tree
+_active_node++;
+if (_active_node == _noise_list.end())
+  _noise_list.clear();
+else {
+  for (list<_dtdWstore>::iterator _temp_iter = _active_node; _temp_iter != _noise_list.end(); _temp_iter++) {
+    _temp_iter->_step -= _step;
+    real _temp_step = _temp_iter->_step;
+    
+''')
+        for noiseVector in integrator.dynamicNoiseVectors: # generated from line 238, col 3
+            #  The noise vector must be transformed back to its initial basis in case it has been transformed during the integration step.
+            write(u'''    ''')
+            _v = VFFSL(SL,"transformVectorsToBasis",False)([noiseVector], noiseVector.initialBasis) # u'${transformVectorsToBasis([noiseVector], noiseVector.initialBasis), autoIndent = True}' on line 240, col 5
+            if _v is not None: write(_filter(_v, autoIndent = True, rawExpr=u'${transformVectorsToBasis([noiseVector], noiseVector.initialBasis), autoIndent = True}')) # from line 240, col 5.
+            write(u'''    ''')
+            _v = VFFSL(SL,"noiseVector.type",True) # u'${noiseVector.type}' on line 241, col 5
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.type}')) # from line 241, col 5.
+            write(u'''* _temp_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 241, col 32
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 241, col 32.
+            write(u''' = _temp_iter->_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 241, col 65
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 241, col 65.
+            write(u''';
+    ''')
+            _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)([VFFSL(SL,"noiseVector",True)],
+"""_temp_${vector.id}[$index] = (_temp_${vector.id}[$index]*(_temp_step + _step) - _active_${vector.id}[$index]*_step)/_temp_step;
+""")
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${loopOverVectorsWithInnerContentTemplate([$noiseVector],\n"""_temp_${vector.id}[$index] = (_temp_${vector.id}[$index]*(_temp_step + _step) - _active_${vector.id}[$index]*_step)/_temp_step;\n"""), autoIndent=True}')) # from line 242, col 5.
+        write(u'''  }
+  
+  _noise_list.erase(_noise_list.begin(), _active_node);
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # Stochastic.tmpl
+        # 
+        # Created by Graham Dennis on 2007-12-11.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis and Joe Hope
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+''')
+        # 
+        #   Globals
+        write(u'''
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    featureName = 'Stochastic'
+
+    uselib = ['randomisation_seeding']
+
+    _mainCheetahMethod_for_Stochastic= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(Stochastic, '_initCheetahAttributes'):
+    templateAPIClass = getattr(Stochastic, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(Stochastic)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=Stochastic()).run()
+
+
diff --git a/xpdeint/Features/Stochastic.tmpl b/xpdeint/Features/Stochastic.tmpl
new file mode 100644
index 0000000..163e1bd
--- /dev/null
+++ b/xpdeint/Features/Stochastic.tmpl
@@ -0,0 +1,252 @@
+@*
+Stochastic.tmpl
+
+Created by Graham Dennis on 2007-12-11.
+
+Copyright (c) 2007-2012, Graham Dennis and Joe Hope
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features._Stochastic
+
+ at from xpdeint.Operators.DeltaAOperator import DeltaAOperator
+
+ at def description: Stochastic
+ at attr featureName = 'Stochastic'
+ at attr $uselib = ['randomisation_seeding']
+
+@*
+  Globals
+*@
+ at def globals
+  @#
+  @super
+  @#
+  @for integrator in self.adaptiveIntegratorsWithNoises() 
+// ********************************************************
+// struct used to store step size and noise vector to ensure
+// stochastic convergence
+struct _dtdWstore_segment${integrator.segmentNumber} {
+  real _step;
+    @#
+    @for noiseVector in integrator.dynamicNoiseVectors
+  $noiseVector.type* _${noiseVector.id};
+    @end for
+  
+  _dtdWstore_segment${integrator.segmentNumber}() {
+  _step = 0;
+    @#
+    @for noiseVector in integrator.dynamicNoiseVectors
+  _${noiseVector.id} = NULL;
+    @end for
+  }
+  ~_dtdWstore_segment${integrator.segmentNumber}() {
+    @#
+    @for noiseVector in integrator.dynamicNoiseVectors
+    if (_${noiseVector.id})
+      xmds_free(_${noiseVector.id});
+    @end for
+  }
+};
+  @end for
+  @#
+  @for dimRep in self.nonUniformDimRepsNeededForGaussianNoise
+${dimRep.type}* ${dimRep.stepSizeArrayName}_invsqrt = (${dimRep.type}*) xmds_malloc(sizeof(${dimRep.type}) * (${dimRep.globalLattice}));
+  @end for
+  @#
+ at end def
+
+ at def mainBegin($dict)
+  @#
+  @for dimRep in self.nonUniformDimRepsNeededForGaussianNoise
+for (long ${dimRep.loopIndex} = 0; ${dimRep.loopIndex} < ${dimRep.globalLattice}; ${dimRep.loopIndex}++) {
+  ${dimRep.stepSizeArrayName}_invsqrt[${dimRep.loopIndex}] = (real)1.0/sqrt(${dimRep.stepSizeArrayName}[${dimRep.loopIndex}] * (${dimRep.volumePrefactor}));
+}
+  @end for
+
+  @for noiseVector in $noiseVectors
+${noiseVector.initialiseGlobalSeeds}@slurp
+
+  @end for
+  @#
+ at end def
+
+ at def topLevelSequenceBegin($dict)
+  @#
+  @for noiseVector in $noiseVectors
+${noiseVector.initialiseLocalSeeds}@slurp
+
+  @end for
+  @#
+ at end def
+
+ at def integrateAdaptiveStepBegin($dict)
+  @#
+  @set $integrator = dict['caller']
+  @#
+  @if not integrator.dynamicNoiseVectors
+    @return
+  @end if
+  @#
+typedef _dtdWstore_segment${integrator.segmentNumber} _dtdWstore;
+list<_dtdWstore> _noise_list;
+list<_dtdWstore>::iterator _active_node;
+  @#
+ at end def
+
+ at def integrateAdaptiveStepEnd($dict)
+  @#
+  @set $integrator = dict['caller']
+  @#
+  @if not integrator.dynamicNoiseVectors
+    @return
+  @end if
+  @#
+  @for noiseVector in integrator.dynamicNoiseVectors
+_active_${noiseVector.id} = _${noiseVector.id};
+  @end for
+  @#
+ at end def
+
+ at def integrateFixedStepInnerLoopBegin(dict)
+  @#
+  @set $integrator = dict['caller']
+  @#
+  @if not integrator.dynamicNoiseVectors
+    @return
+  @end if
+  @#
+  @for noiseVector in integrator.dynamicNoiseVectors
+
+_active_${noiseVector.id} = _${noiseVector.id};
+${noiseVector.functions['evaluate'].call(_step = '_noiseStep')}
+  @end for
+  @#
+  @if 'ErrorCheck' in $features
+
+if (!_half_step) { // For the full step we average the two noises.
+    @for noiseVector in integrator.dynamicNoiseVectors
+      @#
+  _active_${noiseVector.id} = _${noiseVector.id}2;
+  ${noiseVector.functions['evaluate'].call(_step = '_noiseStep'), autoIndent=True}
+  ${loopOverVectorsWithInnerContentTemplate([noiseVector],
+  """_${vector.id}[$index] = 0.5*(_${vector.id}[$index] + _${vector.id}2[$index]);
+  """, basis = noiseVector.initialBasis), autoIndent=True}@slurp
+  _active_${noiseVector.id} = _${noiseVector.id};
+    @end for
+}
+  @end if
+  @#
+ at end def
+
+ at def integrateAdaptiveStepInnerLoopBegin(dict)
+  @#
+  @set $integrator = dict['caller']
+  @#
+  @if not integrator.dynamicNoiseVectors
+    @return
+  @end if
+  @#
+if (_noise_list.empty()) {
+  // Noise list empty so start afresh
+  _noise_list.push_front(_dtdWstore());
+  _active_node = _noise_list.begin();
+  _active_node->_step = _step;
+  @for noiseVector in integrator.dynamicNoiseVectors
+  
+  _active_${noiseVector.id} =  (${noiseVector.type}*) xmds_malloc(sizeof(${noiseVector.type}) * MAX(${noiseVector.allocSize},1));
+  _active_node->_${noiseVector.id} = _active_${noiseVector.id};
+  ${noiseVector.functions['evaluate'].call(_step = '_step')}
+  @end for
+} else if (_step*(1.0 + _EPSILON) < _noise_list.begin()->_step) {
+  // Create new smallest time step
+  
+  // If the step is greater than 50% of the current smallest step size
+  // then we should just use half the step size because we are going to have
+  // to do the other half at some point too.
+  
+  const real _old_smallest_step = _noise_list.begin()->_step;
+  
+  if (_step > 0.5*_old_smallest_step*(1.0 + _EPSILON))
+    _step = 0.5*_old_smallest_step;
+  
+  @for noiseVector in integrator.dynamicNoiseVectors
+    @# It is necessary to transform the noise vector back to its original basis, as it may have been transformed in the mean time.
+  ${transformVectorsToBasis([noiseVector], noiseVector.initialBasis), autoIndent=True}@slurp
+  _active_${noiseVector.id} = (${noiseVector.type}*) xmds_malloc(sizeof(${noiseVector.type}) * MAX(${noiseVector.allocSize},1));
+  ${noiseVector.functions['split'].call(_new_step = '_step', _old_step = '_old_smallest_step', _old_array = '_noise_list.begin()->_' + noiseVector.id)}
+  
+  @end for
+  @#
+  _noise_list.push_front(_dtdWstore());
+  _active_node = _noise_list.begin();
+  _active_node->_step = _step;
+  @for noiseVector in integrator.dynamicNoiseVectors
+  _active_node->_${noiseVector.id} = _active_${noiseVector.id};
+  @end for
+} else {
+  // Use step already attempted
+  for (_active_node = _noise_list.begin(); (_active_node != _noise_list.end()) && (_active_node->_step <= _step*(1.0 + _EPSILON)); _active_node++)
+    ;
+  
+  _active_node--;
+  _step = _active_node->_step;
+  @for noiseVector in integrator.dynamicNoiseVectors
+  _active_${noiseVector.id} = _active_node->_${noiseVector.id};
+    @if noiseVector.needsTransforms
+  _${noiseVector.id}_basis = ${basisIndexForBasis(noiseVector.initialBasis)};
+    @end if
+  @end for
+  
+  if ( _break_next && !((_${propagationDimension}_local + _step)*(1.0 + _EPSILON) >= _${propagationDimension}_break_next))
+    _break_next = false;
+} 
+
+  @#
+ at end def
+
+ at def adaptiveStepSucceeded(dict)
+  @#
+  @set $integrator = dict['caller']
+  @#
+  @if not integrator.dynamicNoiseVectors
+    @return
+  @end if
+  @#
+
+// Trim dtdW tree
+_active_node++;
+if (_active_node == _noise_list.end())
+  _noise_list.clear();
+else {
+  for (list<_dtdWstore>::iterator _temp_iter = _active_node; _temp_iter != _noise_list.end(); _temp_iter++) {
+    _temp_iter->_step -= _step;
+    real _temp_step = _temp_iter->_step;
+    
+  @for noiseVector in integrator.dynamicNoiseVectors
+    @# The noise vector must be transformed back to its initial basis in case it has been transformed during the integration step.
+    ${transformVectorsToBasis([noiseVector], noiseVector.initialBasis), autoIndent = True}@slurp
+    ${noiseVector.type}* _temp_${noiseVector.id} = _temp_iter->_${noiseVector.id};
+    ${loopOverVectorsWithInnerContentTemplate([$noiseVector],
+"""_temp_${vector.id}[$index] = (_temp_${vector.id}[$index]*(_temp_step + _step) - _active_${vector.id}[$index]*_step)/_temp_step;
+"""), autoIndent=True}@slurp
+  @end for
+  }
+  
+  _noise_list.erase(_noise_list.begin(), _active_node);
+}
+  @#
+ at end def
+
diff --git a/xpdeint/Features/Transforms/Basis.py b/xpdeint/Features/Transforms/Basis.py
new file mode 100644
index 0000000..1c50eda
--- /dev/null
+++ b/xpdeint/Features/Transforms/Basis.py
@@ -0,0 +1,538 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.ScriptElement import ScriptElement
+import operator
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.263763
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/Transforms/Basis.tmpl'
+__CHEETAH_srcLastModified__ = 'Fri Jul  5 16:29:35 2013'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class Basis(ScriptElement):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(Basis, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def costEstimate(self, basisReps, **KWS):
+
+
+
+        ## CHEETAH: generated from @def costEstimate(basisReps) at line 28, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        costMultiplier = 4 if VFFSL(SL,"matrixType",True) == 'complex' else 1
+        return reduce(operator.mul, [rep.latticeEstimate for rep in basisReps]) * costMultiplier
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def transformMatricesForDimReps(self, forwardDimRep, backwardDimRep, **KWS):
+
+
+
+        ## CHEETAH: generated from @def transformMatricesForDimReps($forwardDimRep, $backwardDimRep) at line 33, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''_mmt_matrix_forward  = (''')
+        _v = VFFSL(SL,"matrixType",True) # u'$matrixType' on line 34, col 25
+        if _v is not None: write(_filter(_v, rawExpr=u'$matrixType')) # from line 34, col 25.
+        write(u''' *)xmds_malloc(sizeof(''')
+        _v = VFFSL(SL,"matrixType",True) # u'$matrixType' on line 34, col 58
+        if _v is not None: write(_filter(_v, rawExpr=u'$matrixType')) # from line 34, col 58.
+        write(u''') * ''')
+        _v = VFFSL(SL,"forwardDimRep.globalLattice",True) # u'${forwardDimRep.globalLattice}' on line 34, col 73
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.globalLattice}')) # from line 34, col 73.
+        write(u''' * ''')
+        _v = VFFSL(SL,"backwardDimRep.globalLattice",True) # u'${backwardDimRep.globalLattice}' on line 34, col 106
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardDimRep.globalLattice}')) # from line 34, col 106.
+        write(u''');
+_mmt_matrix_backward = (''')
+        _v = VFFSL(SL,"matrixType",True) # u'$matrixType' on line 35, col 25
+        if _v is not None: write(_filter(_v, rawExpr=u'$matrixType')) # from line 35, col 25.
+        write(u''' *)xmds_malloc(sizeof(''')
+        _v = VFFSL(SL,"matrixType",True) # u'$matrixType' on line 35, col 58
+        if _v is not None: write(_filter(_v, rawExpr=u'$matrixType')) # from line 35, col 58.
+        write(u''') * ''')
+        _v = VFFSL(SL,"backwardDimRep.globalLattice",True) # u'${backwardDimRep.globalLattice}' on line 35, col 73
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardDimRep.globalLattice}')) # from line 35, col 73.
+        write(u''' * ''')
+        _v = VFFSL(SL,"forwardDimRep.globalLattice",True) # u'${forwardDimRep.globalLattice}' on line 35, col 107
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.globalLattice}')) # from line 35, col 107.
+        write(u''');
+for (long _i0 = 0; _i0 < ''')
+        _v = VFFSL(SL,"forwardDimRep.globalLattice",True) # u'${forwardDimRep.globalLattice}' on line 36, col 26
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.globalLattice}')) # from line 36, col 26.
+        write(u'''; _i0++) {
+  ''')
+        _v = VFFSL(SL,"transformMatricesForwardDimConstantsAtIndex",False)(forwardDimRep, backwardDimRep, '_i0') # u"${transformMatricesForwardDimConstantsAtIndex(forwardDimRep, backwardDimRep, '_i0'), autoIndent=True}" on line 37, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${transformMatricesForwardDimConstantsAtIndex(forwardDimRep, backwardDimRep, '_i0'), autoIndent=True}")) # from line 37, col 3.
+        write(u'''  for (long _i1 = 0; _i1 < ''')
+        _v = VFFSL(SL,"backwardDimRep.globalLattice",True) # u'${backwardDimRep.globalLattice}' on line 38, col 28
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardDimRep.globalLattice}')) # from line 38, col 28.
+        write(u'''; _i1++) {
+    ''')
+        _v = VFFSL(SL,"transformMatricesForDimRepsAtIndices",False)(forwardDimRep, backwardDimRep, '_i0', '_i1') # u"${transformMatricesForDimRepsAtIndices(forwardDimRep, backwardDimRep, '_i0', '_i1'), autoIndent=True}" on line 39, col 5
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${transformMatricesForDimRepsAtIndices(forwardDimRep, backwardDimRep, '_i0', '_i1'), autoIndent=True}")) # from line 39, col 5.
+        write(u'''  }
+}
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def transformMatricesForwardDimConstantsAtIndex(self, forwardDimRep, backwardDimRep, index, **KWS):
+
+
+
+        ## CHEETAH: generated from @def transformMatricesForwardDimConstantsAtIndex($forwardDimRep, $backwardDimRep, $index) at line 44, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def transformMatricesForDimRepsAtIndices(self, forwardDimRep, backwardDimRep, forwardIndex, backwardIndex, **KWS):
+
+
+
+        ## CHEETAH: generated from @def transformMatricesForDimRepsAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex) at line 47, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''_mmt_matrix_forward [''')
+        _v = VFFSL(SL,"backwardIndex",True) # u'${backwardIndex}' on line 49, col 22
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardIndex}')) # from line 49, col 22.
+        write(u''' * ''')
+        _v = VFFSL(SL,"forwardDimRep.globalLattice",True) # u'${forwardDimRep.globalLattice}' on line 49, col 41
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.globalLattice}')) # from line 49, col 41.
+        write(u''' + ''')
+        _v = VFFSL(SL,"forwardIndex",True) # u'${forwardIndex}' on line 49, col 74
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardIndex}')) # from line 49, col 74.
+        write(u'''] = \\
+  ''')
+        _v = VFFSL(SL,"forwardMatrixForDimAtIndices",False)(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex) # u'${forwardMatrixForDimAtIndices(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex)}' on line 50, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardMatrixForDimAtIndices(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex)}')) # from line 50, col 3.
+        write(u''';
+_mmt_matrix_backward[''')
+        _v = VFFSL(SL,"forwardIndex",True) # u'${forwardIndex}' on line 51, col 22
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardIndex}')) # from line 51, col 22.
+        write(u''' * ''')
+        _v = VFFSL(SL,"backwardDimRep.globalLattice",True) # u'${backwardDimRep.globalLattice}' on line 51, col 40
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardDimRep.globalLattice}')) # from line 51, col 40.
+        write(u''' + ''')
+        _v = VFFSL(SL,"backwardIndex",True) # u'${backwardIndex}' on line 51, col 74
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardIndex}')) # from line 51, col 74.
+        write(u'''] = \\
+  ''')
+        _v = VFFSL(SL,"backwardMatrixForDimAtIndices",False)(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex) # u'${backwardMatrixForDimAtIndices(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex)}' on line 52, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardMatrixForDimAtIndices(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex)}')) # from line 52, col 3.
+        write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def performTransform(self, sourceDimRep, destDimRep, dir=None, **KWS):
+
+
+
+        ## CHEETAH: generated from @def performTransform($sourceDimRep, $destDimRep, $dir = None) at line 56, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        blasTypeChar = {'real': {'single': 's', 'double': 'd'}, 'complex': {'single': 'c', 'double': 'z'}}[self.matrixType][VFFSL(SL,"precision",True)]
+        matMultFunction = 'cblas_%sgemm' % blasTypeChar
+        alphaBetaPrefix = {'real': '', 'complex': '&'}[self.matrixType]
+        write(u'''const ''')
+        _v = VFFSL(SL,"matrixType",True) # u'${matrixType}' on line 61, col 7
+        if _v is not None: write(_filter(_v, rawExpr=u'${matrixType}')) # from line 61, col 7.
+        write(u''' alpha = 1.0;
+const ''')
+        _v = VFFSL(SL,"matrixType",True) # u'${matrixType}' on line 62, col 7
+        if _v is not None: write(_filter(_v, rawExpr=u'${matrixType}')) # from line 62, col 7.
+        write(u''' beta = 0.0;
+''')
+        _v = VFFSL(SL,"matMultFunction",True) # u'${matMultFunction}' on line 63, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${matMultFunction}')) # from line 63, col 1.
+        write(u'''(
+  CblasRowMajor, CblasNoTrans, CblasNoTrans,
+  ''')
+        _v = VFFSL(SL,"destDimRep.globalLattice",True) # u'${destDimRep.globalLattice}' on line 65, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${destDimRep.globalLattice}')) # from line 65, col 3.
+        write(u''',
+  /* nelem */ innerLoopSize,
+  ''')
+        _v = VFFSL(SL,"sourceDimRep.globalLattice",True) # u'${sourceDimRep.globalLattice}' on line 67, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${sourceDimRep.globalLattice}')) # from line 67, col 3.
+        write(u''',
+  /* alpha */ ''')
+        _v = VFFSL(SL,"alphaBetaPrefix",True) # u'${alphaBetaPrefix}' on line 68, col 15
+        if _v is not None: write(_filter(_v, rawExpr=u'${alphaBetaPrefix}')) # from line 68, col 15.
+        write(u'''alpha,
+  /* A */ _mmt_matrix_''')
+        _v = VFFSL(SL,"dir",True) # u'${dir}' on line 69, col 23
+        if _v is not None: write(_filter(_v, rawExpr=u'${dir}')) # from line 69, col 23.
+        write(u''', ''')
+        _v = VFFSL(SL,"sourceDimRep.globalLattice",True) # u'${sourceDimRep.globalLattice}' on line 69, col 31
+        if _v is not None: write(_filter(_v, rawExpr=u'${sourceDimRep.globalLattice}')) # from line 69, col 31.
+        write(u''',
+  /* B */ source_data + _i0 * innerLoopSize * ''')
+        _v = VFFSL(SL,"sourceDimRep.globalLattice",True) # u'${sourceDimRep.globalLattice}' on line 70, col 47
+        if _v is not None: write(_filter(_v, rawExpr=u'${sourceDimRep.globalLattice}')) # from line 70, col 47.
+        write(u''',
+          innerLoopSize,
+  /* beta */ ''')
+        _v = VFFSL(SL,"alphaBetaPrefix",True) # u'${alphaBetaPrefix}' on line 72, col 14
+        if _v is not None: write(_filter(_v, rawExpr=u'${alphaBetaPrefix}')) # from line 72, col 14.
+        write(u'''beta,
+  /* C */ dest_data + _i0 * innerLoopSize * ''')
+        _v = VFFSL(SL,"destDimRep.globalLattice",True) # u'${destDimRep.globalLattice}' on line 73, col 45
+        if _v is not None: write(_filter(_v, rawExpr=u'${destDimRep.globalLattice}')) # from line 73, col 45.
+        write(u''',
+  innerLoopSize
+);
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def transformFunctionStart(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def transformFunctionStart at line 79, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''static ''')
+        _v = VFFSL(SL,"matrixType",True) # u'$matrixType' on line 80, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'$matrixType')) # from line 80, col 8.
+        write(u''' *_mmt_matrix_forward = NULL;
+static ''')
+        _v = VFFSL(SL,"matrixType",True) # u'$matrixType' on line 81, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'$matrixType')) # from line 81, col 8.
+        write(u''' *_mmt_matrix_backward = NULL;
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def transformFunction(self, transformID, transformDict, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def transformFunction(transformID, transformDict, function) at line 84, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        transformPair = transformDict['transformPair']
+        forwardDimRep = transformPair[0][0]
+        backwardDimRep = transformPair[1][0]
+        write(u'''static bool _initialised = false;
+''')
+        _v = VFFSL(SL,"transformFunctionStart",True) # u'${transformFunctionStart}' on line 90, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformFunctionStart}')) # from line 90, col 1.
+        write(u'''ptrdiff_t innerLoopSize = _postfix_lattice;
+''')
+        _v = VFFSL(SL,"matrixType",True) # u'${matrixType}' on line 92, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${matrixType}')) # from line 92, col 1.
+        write(u'''* const __restrict__ source_data = reinterpret_cast<''')
+        _v = VFFSL(SL,"matrixType",True) # u'${matrixType}' on line 92, col 66
+        if _v is not None: write(_filter(_v, rawExpr=u'${matrixType}')) # from line 92, col 66.
+        write(u'''* const>(_data_in);
+''')
+        _v = VFFSL(SL,"matrixType",True) # u'${matrixType}' on line 93, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${matrixType}')) # from line 93, col 1.
+        write(u'''* const __restrict__ dest_data = reinterpret_cast<''')
+        _v = VFFSL(SL,"matrixType",True) # u'${matrixType}' on line 93, col 64
+        if _v is not None: write(_filter(_v, rawExpr=u'${matrixType}')) # from line 93, col 64.
+        write(u'''* const>(_data_out);
+
+if (!_initialised) {
+  _LOG(_SIMULATION_LOG_LEVEL, "Building matrices for ''')
+        _v = VFFSL(SL,"function.description",True) # u'${function.description}' on line 96, col 54
+        if _v is not None: write(_filter(_v, rawExpr=u'${function.description}')) # from line 96, col 54.
+        write(u'''...");
+  
+  ''')
+        _v = VFFSL(SL,"transformMatricesForDimReps",False)(VFFSL(SL,"forwardDimRep",True), VFFSL(SL,"backwardDimRep",True)) # u'${transformMatricesForDimReps($forwardDimRep, $backwardDimRep), autoIndent=True}' on line 98, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${transformMatricesForDimReps($forwardDimRep, $backwardDimRep), autoIndent=True}')) # from line 98, col 3.
+        write(u'''  
+  _LOG(_SIMULATION_LOG_LEVEL, " done.\\n");
+  _initialised = true;
+}
+
+if (_forward) {
+  for (long _i0 = 0; _i0 < _prefix_lattice; _i0++) {
+    ''')
+        _v = VFFSL(SL,"performTransform",False)(forwardDimRep, backwardDimRep, dir='forward') # u"${performTransform(forwardDimRep, backwardDimRep, dir='forward'), autoIndent=True}" on line 106, col 5
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${performTransform(forwardDimRep, backwardDimRep, dir='forward'), autoIndent=True}")) # from line 106, col 5.
+        write(u'''  }
+} else {
+  for (long _i0 = 0; _i0 < _prefix_lattice; _i0++) {
+    ''')
+        _v = VFFSL(SL,"performTransform",False)(backwardDimRep, forwardDimRep, dir='backward') # u"${performTransform(backwardDimRep, forwardDimRep, dir='backward'), autoIndent=True}" on line 110, col 5
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${performTransform(backwardDimRep, forwardDimRep, dir='backward'), autoIndent=True}")) # from line 110, col 5.
+        write(u'''  }
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # Basis.tmpl
+        # 
+        # Created by Graham Dennis on 2008-12-14.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    matrixType = 'real'
+
+    supportsInPlaceOperation = False
+
+    _mainCheetahMethod_for_Basis= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(Basis, '_initCheetahAttributes'):
+    templateAPIClass = getattr(Basis, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(Basis)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=Basis()).run()
+
+
diff --git a/xpdeint/Features/Transforms/Basis.tmpl b/xpdeint/Features/Transforms/Basis.tmpl
new file mode 100644
index 0000000..1117e6d
--- /dev/null
+++ b/xpdeint/Features/Transforms/Basis.tmpl
@@ -0,0 +1,114 @@
+@*
+Basis.tmpl
+
+Created by Graham Dennis on 2008-12-14.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.ScriptElement
+ at import operator
+
+ at attr $matrixType = 'real'
+ at attr $supportsInPlaceOperation = False
+
+ at def costEstimate(basisReps)
+  @set costMultiplier = 4 if $matrixType == 'complex' else 1
+  @return reduce(operator.mul, [rep.latticeEstimate for rep in basisReps]) * costMultiplier
+ at end def
+
+ at def transformMatricesForDimReps($forwardDimRep, $backwardDimRep)
+_mmt_matrix_forward  = ($matrixType *)xmds_malloc(sizeof($matrixType) * ${forwardDimRep.globalLattice} * ${backwardDimRep.globalLattice});
+_mmt_matrix_backward = ($matrixType *)xmds_malloc(sizeof($matrixType) * ${backwardDimRep.globalLattice} * ${forwardDimRep.globalLattice});
+for (long _i0 = 0; _i0 < ${forwardDimRep.globalLattice}; _i0++) {
+  ${transformMatricesForwardDimConstantsAtIndex(forwardDimRep, backwardDimRep, '_i0'), autoIndent=True}@slurp
+  for (long _i1 = 0; _i1 < ${backwardDimRep.globalLattice}; _i1++) {
+    ${transformMatricesForDimRepsAtIndices(forwardDimRep, backwardDimRep, '_i0', '_i1'), autoIndent=True}@slurp
+  }
+}
+ at end def
+
+ at def transformMatricesForwardDimConstantsAtIndex($forwardDimRep, $backwardDimRep, $index)
+ at end def
+
+ at def transformMatricesForDimRepsAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex)
+  @#
+_mmt_matrix_forward [${backwardIndex} * ${forwardDimRep.globalLattice} + ${forwardIndex}] = \
+  ${forwardMatrixForDimAtIndices(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex)};
+_mmt_matrix_backward[${forwardIndex} * ${backwardDimRep.globalLattice} + ${backwardIndex}] = \
+  ${backwardMatrixForDimAtIndices(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex)};
+  @#
+ at end def
+
+ at def performTransform($sourceDimRep, $destDimRep, $dir = None)
+  @#
+  @set $blasTypeChar = {'real': {'single': 's', 'double': 'd'}, 'complex': {'single': 'c', 'double': 'z'}}[self.matrixType][$precision]
+  @set $matMultFunction = 'cblas_%sgemm' % blasTypeChar
+  @set $alphaBetaPrefix = {'real': '', 'complex': '&'}[self.matrixType]
+const ${matrixType} alpha = 1.0;
+const ${matrixType} beta = 0.0;
+${matMultFunction}(
+  CblasRowMajor, CblasNoTrans, CblasNoTrans,
+  ${destDimRep.globalLattice},
+  /* nelem */ innerLoopSize,
+  ${sourceDimRep.globalLattice},
+  /* alpha */ ${alphaBetaPrefix}alpha,
+  /* A */ _mmt_matrix_${dir}, ${sourceDimRep.globalLattice},
+  /* B */ source_data + _i0 * innerLoopSize * ${sourceDimRep.globalLattice},
+          innerLoopSize,
+  /* beta */ ${alphaBetaPrefix}beta,
+  /* C */ dest_data + _i0 * innerLoopSize * ${destDimRep.globalLattice},
+  innerLoopSize
+);
+  @#
+ at end def
+
+ at def transformFunctionStart
+static $matrixType *_mmt_matrix_forward = NULL;
+static $matrixType *_mmt_matrix_backward = NULL;
+ at end def
+
+ at def transformFunction(transformID, transformDict, function)
+  @#
+  @set $transformPair = transformDict['transformPair']
+  @set $forwardDimRep = transformPair[0][0]
+  @set $backwardDimRep = transformPair[1][0]
+static bool _initialised = false;
+${transformFunctionStart}@slurp
+ptrdiff_t innerLoopSize = _postfix_lattice;
+${matrixType}* const __restrict__ source_data = reinterpret_cast<${matrixType}* const>(_data_in);
+${matrixType}* const __restrict__ dest_data = reinterpret_cast<${matrixType}* const>(_data_out);
+
+if (!_initialised) {
+  _LOG(_SIMULATION_LOG_LEVEL, "Building matrices for ${function.description}...");
+  
+  ${transformMatricesForDimReps($forwardDimRep, $backwardDimRep), autoIndent=True}@slurp
+  
+  _LOG(_SIMULATION_LOG_LEVEL, " done.\n");
+  _initialised = true;
+}
+
+if (_forward) {
+  for (long _i0 = 0; _i0 < _prefix_lattice; _i0++) {
+    ${performTransform(forwardDimRep, backwardDimRep, dir='forward'), autoIndent=True}@slurp
+  }
+} else {
+  for (long _i0 = 0; _i0 < _prefix_lattice; _i0++) {
+    ${performTransform(backwardDimRep, forwardDimRep, dir='backward'), autoIndent=True}@slurp
+  }
+}
+  @#
+ at end def
diff --git a/xpdeint/Features/Transforms/BesselBasis.py b/xpdeint/Features/Transforms/BesselBasis.py
new file mode 100644
index 0000000..73f6d1e
--- /dev/null
+++ b/xpdeint/Features/Transforms/BesselBasis.py
@@ -0,0 +1,286 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features.Transforms.Basis import Basis
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.310537
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/Transforms/BesselBasis.tmpl'
+__CHEETAH_srcLastModified__ = 'Fri Sep 14 16:04:46 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class BesselBasis(Basis):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(BesselBasis, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Bessel function basis at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Bessel function basis''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def transformMatricesForDimRepsAtIndices(self, forwardDimRep, backwardDimRep, forwardIndex, backwardIndex, **KWS):
+
+
+
+        ## CHEETAH: generated from @def transformMatricesForDimRepsAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex) at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        order = forwardDimRep._order
+        write(u'''const real besselFactor = ''')
+        _v = VFN(VFFSL(SL,"forwardDimRep",True),"besselJFunctionCall",False)(VFFSL(SL,"order",True), ''.join([u'_normbesseljzeros_',str(VFFSL(SL,"forwardDimRep.parent.name",True)),u'[',str(VFFSL(SL,"forwardIndex",True)),u'] * _normbesseljzeros_',str(VFFSL(SL,"forwardDimRep.parent.name",True)),u'[',str(VFFSL(SL,"backwardIndex",True)),u'] * _besseljnorm_',str(VFFSL(SL,"forwardDimRep.parent.name",True))])) # u"${forwardDimRep.besselJFunctionCall($order, c'_normbesseljzeros_${forwardDimRep.p [...]
+        if _v is not None: write(_filter(_v, rawExpr=u"${forwardDimRep.besselJFunctionCall($order, c'_normbesseljzeros_${forwardDimRep.parent.name}[${forwardIndex}] * _normbesseljzeros_${forwardDimRep.parent.name}[${backwardIndex}] * _besseljnorm_${forwardDimRep.parent.name}')}")) # from line 29, col 27.
+        write(u''';
+''')
+        # 
+        _v = super(BesselBasis, self).transformMatricesForDimRepsAtIndices(forwardDimRep,backwardDimRep,forwardIndex,backwardIndex)
+        if _v is not None: write(_filter(_v))
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def forwardMatrixForDimAtIndices(self, forwardDimRep, backwardDimRep, forwardIndex, backwardIndex, **KWS):
+
+
+
+        ## CHEETAH: generated from @def forwardMatrixForDimAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex) at line 35, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''besselFactor * ''')
+        _v = VFFSL(SL,"forwardDimRep.stepSizeArrayName",True) # u'${forwardDimRep.stepSizeArrayName}' on line 36, col 16
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.stepSizeArrayName}')) # from line 36, col 16.
+        write(u'''[''')
+        _v = VFFSL(SL,"forwardIndex",True) # u'$forwardIndex' on line 36, col 51
+        if _v is not None: write(_filter(_v, rawExpr=u'$forwardIndex')) # from line 36, col 51.
+        write(u''']''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def backwardMatrixForDimAtIndices(self, forwardDimRep, backwardDimRep, forwardIndex, backwardIndex, **KWS):
+
+
+
+        ## CHEETAH: generated from @def backwardMatrixForDimAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex) at line 39, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''besselFactor * ''')
+        _v = VFFSL(SL,"backwardDimRep.stepSizeArrayName",True) # u'${backwardDimRep.stepSizeArrayName}' on line 40, col 16
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardDimRep.stepSizeArrayName}')) # from line 40, col 16.
+        write(u'''[''')
+        _v = VFFSL(SL,"backwardIndex",True) # u'$backwardIndex' on line 40, col 52
+        if _v is not None: write(_filter(_v, rawExpr=u'$backwardIndex')) # from line 40, col 52.
+        write(u''']''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # BesselBasis.tmpl
+        # 
+        # Created by Graham Dennis on 2008-12-14.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_BesselBasis= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(BesselBasis, '_initCheetahAttributes'):
+    templateAPIClass = getattr(BesselBasis, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(BesselBasis)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=BesselBasis()).run()
+
+
diff --git a/xpdeint/Features/Transforms/BesselBasis.tmpl b/xpdeint/Features/Transforms/BesselBasis.tmpl
new file mode 100644
index 0000000..b9f0cfd
--- /dev/null
+++ b/xpdeint/Features/Transforms/BesselBasis.tmpl
@@ -0,0 +1,42 @@
+@*
+BesselBasis.tmpl
+
+Created by Graham Dennis on 2008-12-14.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features.Transforms.Basis
+
+ at def description: Bessel function basis
+
+ at def transformMatricesForDimRepsAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex)
+  @#
+  @set $order = forwardDimRep._order
+const real besselFactor = ${forwardDimRep.besselJFunctionCall($order, c'_normbesseljzeros_${forwardDimRep.parent.name}[${forwardIndex}] * _normbesseljzeros_${forwardDimRep.parent.name}[${backwardIndex}] * _besseljnorm_${forwardDimRep.parent.name}')};
+  @#
+  @super(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex)
+  @#
+ at end def
+
+ at def forwardMatrixForDimAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex)
+besselFactor * ${forwardDimRep.stepSizeArrayName}[$forwardIndex]@slurp
+ at end def
+
+ at def backwardMatrixForDimAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex)
+besselFactor * ${backwardDimRep.stepSizeArrayName}[$backwardIndex]@slurp
+ at end def
+
diff --git a/xpdeint/Features/Transforms/EPBasis.py b/xpdeint/Features/Transforms/EPBasis.py
new file mode 100644
index 0000000..1def642
--- /dev/null
+++ b/xpdeint/Features/Transforms/EPBasis.py
@@ -0,0 +1,804 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features.Transforms.Basis import Basis
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.438919
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/Transforms/EPBasis.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class EPBasis(Basis):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(EPBasis, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def transformFunctionStart(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def transformFunctionStart at line 28, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''static ''')
+        _v = VFFSL(SL,"matrixType",True) # u'${matrixType}' on line 29, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${matrixType}')) # from line 29, col 8.
+        write(u''' *_mmt_matrix_forward_even = NULL;
+static ''')
+        _v = VFFSL(SL,"matrixType",True) # u'${matrixType}' on line 30, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${matrixType}')) # from line 30, col 8.
+        write(u''' *_mmt_matrix_forward_odd  = NULL;
+static ''')
+        _v = VFFSL(SL,"matrixType",True) # u'${matrixType}' on line 31, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${matrixType}')) # from line 31, col 8.
+        write(u''' *_mmt_matrix_backward_even = NULL;
+static ''')
+        _v = VFFSL(SL,"matrixType",True) # u'${matrixType}' on line 32, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${matrixType}')) # from line 32, col 8.
+        write(u''' *_mmt_matrix_backward_odd  = NULL;
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def transformMatricesForDimReps(self, forwardDimRep, backwardDimRep, **KWS):
+
+
+
+        ## CHEETAH: generated from @def transformMatricesForDimReps($forwardDimRep, $backwardDimRep) at line 36, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''long _even_''')
+        _v = VFFSL(SL,"forwardDimRep.name",True) # u'${forwardDimRep.name}' on line 37, col 12
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.name}')) # from line 37, col 12.
+        write(u''' = (''')
+        _v = VFFSL(SL,"forwardDimRep.globalLattice",True) # u'${forwardDimRep.globalLattice}' on line 37, col 37
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.globalLattice}')) # from line 37, col 37.
+        write(u''' + 1)/2;
+long _odd_''')
+        _v = VFFSL(SL,"forwardDimRep.name",True) # u'${forwardDimRep.name}' on line 38, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.name}')) # from line 38, col 11.
+        write(u''' = ''')
+        _v = VFFSL(SL,"forwardDimRep.globalLattice",True) # u'${forwardDimRep.globalLattice}' on line 38, col 35
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.globalLattice}')) # from line 38, col 35.
+        write(u'''/2;
+long _even_''')
+        _v = VFFSL(SL,"backwardDimRep.name",True) # u'${backwardDimRep.name}' on line 39, col 12
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardDimRep.name}')) # from line 39, col 12.
+        write(u''' = (''')
+        _v = VFFSL(SL,"backwardDimRep.globalLattice",True) # u'${backwardDimRep.globalLattice}' on line 39, col 38
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardDimRep.globalLattice}')) # from line 39, col 38.
+        write(u''' + 1)/2;
+long _odd_''')
+        _v = VFFSL(SL,"backwardDimRep.name",True) # u'${backwardDimRep.name}' on line 40, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardDimRep.name}')) # from line 40, col 11.
+        write(u''' = ''')
+        _v = VFFSL(SL,"backwardDimRep.globalLattice",True) # u'${backwardDimRep.globalLattice}' on line 40, col 36
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardDimRep.globalLattice}')) # from line 40, col 36.
+        write(u'''/2;
+_mmt_matrix_forward_even = (''')
+        _v = VFFSL(SL,"matrixType",True) # u'$matrixType' on line 41, col 29
+        if _v is not None: write(_filter(_v, rawExpr=u'$matrixType')) # from line 41, col 29.
+        write(u''' *)xmds_malloc(sizeof(''')
+        _v = VFFSL(SL,"matrixType",True) # u'$matrixType' on line 41, col 62
+        if _v is not None: write(_filter(_v, rawExpr=u'$matrixType')) # from line 41, col 62.
+        write(u''') * _even_''')
+        _v = VFFSL(SL,"forwardDimRep.name",True) # u'${forwardDimRep.name}' on line 41, col 83
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.name}')) # from line 41, col 83.
+        write(u''' * _even_''')
+        _v = VFFSL(SL,"backwardDimRep.name",True) # u'${backwardDimRep.name}' on line 41, col 113
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardDimRep.name}')) # from line 41, col 113.
+        write(u''');
+_mmt_matrix_forward_odd  = (''')
+        _v = VFFSL(SL,"matrixType",True) # u'$matrixType' on line 42, col 29
+        if _v is not None: write(_filter(_v, rawExpr=u'$matrixType')) # from line 42, col 29.
+        write(u''' *)xmds_malloc(sizeof(''')
+        _v = VFFSL(SL,"matrixType",True) # u'$matrixType' on line 42, col 62
+        if _v is not None: write(_filter(_v, rawExpr=u'$matrixType')) # from line 42, col 62.
+        write(u''') * _odd_''')
+        _v = VFFSL(SL,"forwardDimRep.name",True) # u'${forwardDimRep.name}' on line 42, col 82
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.name}')) # from line 42, col 82.
+        write(u''' * _odd_''')
+        _v = VFFSL(SL,"backwardDimRep.name",True) # u'${backwardDimRep.name}' on line 42, col 111
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardDimRep.name}')) # from line 42, col 111.
+        write(u''');
+_mmt_matrix_backward_even = (''')
+        _v = VFFSL(SL,"matrixType",True) # u'$matrixType' on line 43, col 30
+        if _v is not None: write(_filter(_v, rawExpr=u'$matrixType')) # from line 43, col 30.
+        write(u''' *)xmds_malloc(sizeof(''')
+        _v = VFFSL(SL,"matrixType",True) # u'$matrixType' on line 43, col 63
+        if _v is not None: write(_filter(_v, rawExpr=u'$matrixType')) # from line 43, col 63.
+        write(u''') * _even_''')
+        _v = VFFSL(SL,"backwardDimRep.name",True) # u'${backwardDimRep.name}' on line 43, col 84
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardDimRep.name}')) # from line 43, col 84.
+        write(u''' * _even_''')
+        _v = VFFSL(SL,"forwardDimRep.name",True) # u'${forwardDimRep.name}' on line 43, col 115
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.name}')) # from line 43, col 115.
+        write(u''');
+_mmt_matrix_backward_odd  = (''')
+        _v = VFFSL(SL,"matrixType",True) # u'$matrixType' on line 44, col 30
+        if _v is not None: write(_filter(_v, rawExpr=u'$matrixType')) # from line 44, col 30.
+        write(u''' *)xmds_malloc(sizeof(''')
+        _v = VFFSL(SL,"matrixType",True) # u'$matrixType' on line 44, col 63
+        if _v is not None: write(_filter(_v, rawExpr=u'$matrixType')) # from line 44, col 63.
+        write(u''') * _odd_''')
+        _v = VFFSL(SL,"backwardDimRep.name",True) # u'${backwardDimRep.name}' on line 44, col 83
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardDimRep.name}')) # from line 44, col 83.
+        write(u''' * _odd_''')
+        _v = VFFSL(SL,"forwardDimRep.name",True) # u'${forwardDimRep.name}' on line 44, col 113
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.name}')) # from line 44, col 113.
+        write(u''');
+
+for (long _i0 = 0; _i0 < _even_''')
+        _v = VFFSL(SL,"forwardDimRep.name",True) # u'${forwardDimRep.name}' on line 46, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.name}')) # from line 46, col 32.
+        write(u'''; _i0++) {
+  long __i0 = ''')
+        _v = VFFSL(SL,"forwardDimRep.globalLattice",True) # u'${forwardDimRep.globalLattice}' on line 47, col 15
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.globalLattice}')) # from line 47, col 15.
+        write(u''' - 1 - _i0;
+  ''')
+        _v = VFFSL(SL,"transformMatricesForwardDimConstantsAtIndex",False)(forwardDimRep, backwardDimRep, '__i0') # u"${transformMatricesForwardDimConstantsAtIndex(forwardDimRep, backwardDimRep, '__i0'), autoIndent=True}" on line 48, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${transformMatricesForwardDimConstantsAtIndex(forwardDimRep, backwardDimRep, '__i0'), autoIndent=True}")) # from line 48, col 3.
+        write(u'''  for (long _i1 = 0; _i1 < ''')
+        _v = VFFSL(SL,"backwardDimRep.globalLattice",True) # u'${backwardDimRep.globalLattice}' on line 49, col 28
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardDimRep.globalLattice}')) # from line 49, col 28.
+        write(u'''; _i1++) {
+    ''')
+        _v = VFFSL(SL,"transformMatricesForDimRepsAtIndices",False)(forwardDimRep, backwardDimRep, '_i0', '_i1') # u"${transformMatricesForDimRepsAtIndices(forwardDimRep, backwardDimRep, '_i0', '_i1'), autoIndent=True}" on line 50, col 5
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${transformMatricesForDimRepsAtIndices(forwardDimRep, backwardDimRep, '_i0', '_i1'), autoIndent=True}")) # from line 50, col 5.
+        write(u'''  }
+}
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def transformMatricesForDimRepsAtIndices(self, forwardDimRep, backwardDimRep, forwardIndex, backwardIndex, **KWS):
+
+
+
+        ## CHEETAH: generated from @def transformMatricesForDimRepsAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex) at line 55, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''if (''')
+        _v = VFFSL(SL,"backwardIndex",True) # u'${backwardIndex}' on line 57, col 5
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardIndex}')) # from line 57, col 5.
+        write(u''' & 1) {
+  // ''')
+        _v = VFFSL(SL,"backwardIndex",True) # u'${backwardIndex}' on line 58, col 6
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardIndex}')) # from line 58, col 6.
+        write(u''' is odd
+  if (''')
+        _v = VFFSL(SL,"forwardIndex",True) # u'${forwardIndex}' on line 59, col 7
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardIndex}')) # from line 59, col 7.
+        write(u''' < _odd_''')
+        _v = VFFSL(SL,"forwardDimRep.name",True) # u'${forwardDimRep.name}' on line 59, col 30
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.name}')) # from line 59, col 30.
+        write(u''') {
+    ''')
+        _v = VFFSL(SL,"transformMatricesForDimRepsAtIndicesOfKind",False)(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex, 'odd') # u"${transformMatricesForDimRepsAtIndicesOfKind(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex, 'odd'), autoIndent=True}" on line 60, col 5
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${transformMatricesForDimRepsAtIndicesOfKind(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex, 'odd'), autoIndent=True}")) # from line 60, col 5.
+        write(u'''  }
+} else {
+  // ''')
+        _v = VFFSL(SL,"backwardIndex",True) # u'${backwardIndex}' on line 63, col 6
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardIndex}')) # from line 63, col 6.
+        write(u''' is even
+  ''')
+        _v = VFFSL(SL,"transformMatricesForDimRepsAtIndicesOfKind",False)(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex, 'even') # u"${transformMatricesForDimRepsAtIndicesOfKind(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex, 'even'), autoIndent=True}" on line 64, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${transformMatricesForDimRepsAtIndicesOfKind(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex, 'even'), autoIndent=True}")) # from line 64, col 3.
+        write(u'''}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def transformMatricesForDimRepsAtIndicesOfKind(self, forwardDimRep, backwardDimRep, forwardIndex, backwardIndex, kind, **KWS):
+
+
+
+        ## CHEETAH: generated from @def transformMatricesForDimRepsAtIndicesOfKind($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex, $kind) at line 69, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        logicalForwardIndex = '_' + forwardIndex
+        logicalBackwardIndex = backwardIndex
+        actualBackwardIndex = '_' + backwardIndex
+        if kind == 'even': # generated from line 74, col 3
+            actualForwardIndex = forwardIndex
+        else: # generated from line 76, col 3
+            actualForwardIndex = ''.join([u'(_odd_',str(VFFSL(SL,"forwardDimRep.name",True)),u' -1 - ',str(VFFSL(SL,"forwardIndex",True)),u')'])
+        write(u'''long ''')
+        _v = VFFSL(SL,"actualBackwardIndex",True) # u'${actualBackwardIndex}' on line 79, col 6
+        if _v is not None: write(_filter(_v, rawExpr=u'${actualBackwardIndex}')) # from line 79, col 6.
+        write(u''' = ''')
+        _v = VFFSL(SL,"backwardIndex",True) # u'${backwardIndex}' on line 79, col 31
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardIndex}')) # from line 79, col 31.
+        write(u'''/2;
+_mmt_matrix_forward_''')
+        _v = VFFSL(SL,"kind",True) # u'${kind}' on line 80, col 21
+        if _v is not None: write(_filter(_v, rawExpr=u'${kind}')) # from line 80, col 21.
+        write(u'''[''')
+        _v = VFFSL(SL,"actualBackwardIndex",True) # u'${actualBackwardIndex}' on line 80, col 29
+        if _v is not None: write(_filter(_v, rawExpr=u'${actualBackwardIndex}')) # from line 80, col 29.
+        write(u''' * _''')
+        _v = VFFSL(SL,"kind",True) # u'${kind}' on line 80, col 55
+        if _v is not None: write(_filter(_v, rawExpr=u'${kind}')) # from line 80, col 55.
+        write(u'''_''')
+        _v = VFFSL(SL,"forwardDimRep.name",True) # u'${forwardDimRep.name}' on line 80, col 63
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.name}')) # from line 80, col 63.
+        write(u''' + ''')
+        _v = VFFSL(SL,"actualForwardIndex",True) # u'${actualForwardIndex}' on line 80, col 87
+        if _v is not None: write(_filter(_v, rawExpr=u'${actualForwardIndex}')) # from line 80, col 87.
+        write(u'''] = \\
+  ''')
+        _v = VFFSL(SL,"forwardMatrixForDimAtIndices",False)(forwardDimRep, backwardDimRep, logicalForwardIndex, logicalBackwardIndex) # u'${forwardMatrixForDimAtIndices(forwardDimRep, backwardDimRep, logicalForwardIndex, logicalBackwardIndex)}' on line 81, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardMatrixForDimAtIndices(forwardDimRep, backwardDimRep, logicalForwardIndex, logicalBackwardIndex)}')) # from line 81, col 3.
+        write(u''';
+_mmt_matrix_backward_''')
+        _v = VFFSL(SL,"kind",True) # u'${kind}' on line 82, col 22
+        if _v is not None: write(_filter(_v, rawExpr=u'${kind}')) # from line 82, col 22.
+        write(u'''[''')
+        _v = VFFSL(SL,"actualForwardIndex",True) # u'${actualForwardIndex}' on line 82, col 30
+        if _v is not None: write(_filter(_v, rawExpr=u'${actualForwardIndex}')) # from line 82, col 30.
+        write(u''' * _''')
+        _v = VFFSL(SL,"kind",True) # u'${kind}' on line 82, col 55
+        if _v is not None: write(_filter(_v, rawExpr=u'${kind}')) # from line 82, col 55.
+        write(u'''_''')
+        _v = VFFSL(SL,"backwardDimRep.name",True) # u'${backwardDimRep.name}' on line 82, col 63
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardDimRep.name}')) # from line 82, col 63.
+        write(u''' + ''')
+        _v = VFFSL(SL,"actualBackwardIndex",True) # u'${actualBackwardIndex}' on line 82, col 88
+        if _v is not None: write(_filter(_v, rawExpr=u'${actualBackwardIndex}')) # from line 82, col 88.
+        write(u'''] = \\
+  ''')
+        _v = VFFSL(SL,"backwardMatrixForDimAtIndices",False)(forwardDimRep, backwardDimRep, logicalForwardIndex, logicalBackwardIndex) # u'${backwardMatrixForDimAtIndices(forwardDimRep, backwardDimRep, logicalForwardIndex, logicalBackwardIndex)}' on line 83, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardMatrixForDimAtIndices(forwardDimRep, backwardDimRep, logicalForwardIndex, logicalBackwardIndex)}')) # from line 83, col 3.
+        write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def performTransform(self, sourceDimRep, destDimRep, dir=None, **KWS):
+
+
+
+        ## CHEETAH: generated from @def performTransform($sourceDimRep, $destDimRep, $dir = None) at line 87, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        if dir == 'forward': # generated from line 89, col 3
+            _v = VFFSL(SL,"performForwardTransform",False)(sourceDimRep, destDimRep) # u'${performForwardTransform(sourceDimRep, destDimRep)}' on line 90, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${performForwardTransform(sourceDimRep, destDimRep)}')) # from line 90, col 1.
+        else: # generated from line 91, col 3
+            _v = VFFSL(SL,"performBackwardTransform",False)(sourceDimRep, destDimRep) # u'${performBackwardTransform(sourceDimRep, destDimRep)}' on line 92, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${performBackwardTransform(sourceDimRep, destDimRep)}')) # from line 92, col 1.
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def performForwardTransform(self, sourceDimRep, destDimRep, **KWS):
+
+
+
+        ## CHEETAH: generated from @def performForwardTransform($sourceDimRep, $destDimRep) at line 96, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        blasTypeChar = {'real': {'single': 's', 'double': 'd'}, 'complex': {'single': 'c', 'double': 'z'}}[self.matrixType][VFFSL(SL,"precision",True)]
+        alphaBetaPrefix = {'real': '', 'complex': '&'}[self.matrixType]
+        matMultFunction = 'cblas_%sgemm' % blasTypeChar
+        write(u'''// Loop to create symmetric and antisymmetric components.
+''')
+        _v = VFFSL(SL,"matrixType",True) # u'${matrixType}' on line 102, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${matrixType}')) # from line 102, col 1.
+        write(u''' _temp;
+long outerOffset = _i0 * innerLoopSize * ''')
+        _v = VFFSL(SL,"sourceDimRep.globalLattice",True) # u'${sourceDimRep.globalLattice}' on line 103, col 42
+        if _v is not None: write(_filter(_v, rawExpr=u'${sourceDimRep.globalLattice}')) # from line 103, col 42.
+        write(u''';
+for (long _i1 = 0; _i1 < ''')
+        _v = VFFSL(SL,"sourceDimRep.globalLattice",True) # u'${sourceDimRep.globalLattice}' on line 104, col 26
+        if _v is not None: write(_filter(_v, rawExpr=u'${sourceDimRep.globalLattice}')) # from line 104, col 26.
+        write(u'''/2; _i1++) {
+  ''')
+        _v = VFFSL(SL,"matrixType",True) # u'${matrixType}' on line 105, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${matrixType}')) # from line 105, col 3.
+        write(u'''* __restrict__ _low = &source_data[outerOffset + _i1 * innerLoopSize];
+  ''')
+        _v = VFFSL(SL,"matrixType",True) # u'${matrixType}' on line 106, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${matrixType}')) # from line 106, col 3.
+        write(u'''* __restrict__ _high = &source_data[outerOffset + (''')
+        _v = VFFSL(SL,"sourceDimRep.globalLattice",True) # u'${sourceDimRep.globalLattice}' on line 106, col 67
+        if _v is not None: write(_filter(_v, rawExpr=u'${sourceDimRep.globalLattice}')) # from line 106, col 67.
+        write(u''' - 1 - _i1) * innerLoopSize];
+  for (long _i2 = 0; _i2 < innerLoopSize; _i2++) {
+    _temp = _low[_i2];
+    _low[_i2] += _high[_i2];  // _low stores the symmetric component
+    _high[_i2] -= _temp; // _high stores the antisymmetric component
+  }
+}
+const ''')
+        _v = VFFSL(SL,"matrixType",True) # u'${matrixType}' on line 113, col 7
+        if _v is not None: write(_filter(_v, rawExpr=u'${matrixType}')) # from line 113, col 7.
+        write(u''' alpha = 1.0;
+const ''')
+        _v = VFFSL(SL,"matrixType",True) # u'${matrixType}' on line 114, col 7
+        if _v is not None: write(_filter(_v, rawExpr=u'${matrixType}')) # from line 114, col 7.
+        write(u''' beta = 0.0;
+
+// Symmetric component of the transform
+''')
+        _v = VFFSL(SL,"matMultFunction",True) # u'${matMultFunction}' on line 117, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${matMultFunction}')) # from line 117, col 1.
+        write(u'''(CblasRowMajor, CblasNoTrans, CblasNoTrans,
+            (''')
+        _v = VFFSL(SL,"destDimRep.globalLattice",True) # u'${destDimRep.globalLattice}' on line 118, col 14
+        if _v is not None: write(_filter(_v, rawExpr=u'${destDimRep.globalLattice}')) # from line 118, col 14.
+        write(u'''+1)/2,
+            /* nelem */ innerLoopSize,
+            (''')
+        _v = VFFSL(SL,"sourceDimRep.globalLattice",True) # u'${sourceDimRep.globalLattice}' on line 120, col 14
+        if _v is not None: write(_filter(_v, rawExpr=u'${sourceDimRep.globalLattice}')) # from line 120, col 14.
+        write(u'''+1)/2,
+            /* alpha */ ''')
+        _v = VFFSL(SL,"alphaBetaPrefix",True) # u'${alphaBetaPrefix}' on line 121, col 25
+        if _v is not None: write(_filter(_v, rawExpr=u'${alphaBetaPrefix}')) # from line 121, col 25.
+        write(u'''alpha,
+            /* A */ _mmt_matrix_forward_even, (''')
+        _v = VFFSL(SL,"sourceDimRep.globalLattice",True) # u'${sourceDimRep.globalLattice}' on line 122, col 48
+        if _v is not None: write(_filter(_v, rawExpr=u'${sourceDimRep.globalLattice}')) # from line 122, col 48.
+        write(u'''+1)/2,
+            /* B */ source_data + _i0 * ''')
+        _v = VFFSL(SL,"sourceDimRep.globalLattice",True) # u'${sourceDimRep.globalLattice}' on line 123, col 41
+        if _v is not None: write(_filter(_v, rawExpr=u'${sourceDimRep.globalLattice}')) # from line 123, col 41.
+        write(u''' * innerLoopSize,
+                    innerLoopSize,
+            /* beta */ ''')
+        _v = VFFSL(SL,"alphaBetaPrefix",True) # u'${alphaBetaPrefix}' on line 125, col 24
+        if _v is not None: write(_filter(_v, rawExpr=u'${alphaBetaPrefix}')) # from line 125, col 24.
+        write(u'''beta,
+            /* C */ dest_data + _i0 * ''')
+        _v = VFFSL(SL,"destDimRep.globalLattice",True) # u'${destDimRep.globalLattice}' on line 126, col 39
+        if _v is not None: write(_filter(_v, rawExpr=u'${destDimRep.globalLattice}')) # from line 126, col 39.
+        write(u''' * innerLoopSize,
+            2 * innerLoopSize);
+// Antisymmetric component of the transform
+''')
+        _v = VFFSL(SL,"matMultFunction",True) # u'${matMultFunction}' on line 129, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${matMultFunction}')) # from line 129, col 1.
+        write(u'''(CblasRowMajor, CblasNoTrans, CblasNoTrans,
+            ''')
+        _v = VFFSL(SL,"destDimRep.globalLattice",True) # u'${destDimRep.globalLattice}' on line 130, col 13
+        if _v is not None: write(_filter(_v, rawExpr=u'${destDimRep.globalLattice}')) # from line 130, col 13.
+        write(u'''/2,
+            /* nelem */ innerLoopSize,
+            ''')
+        _v = VFFSL(SL,"sourceDimRep.globalLattice",True) # u'${sourceDimRep.globalLattice}' on line 132, col 13
+        if _v is not None: write(_filter(_v, rawExpr=u'${sourceDimRep.globalLattice}')) # from line 132, col 13.
+        write(u'''/2,
+            /* alpha */ ''')
+        _v = VFFSL(SL,"alphaBetaPrefix",True) # u'${alphaBetaPrefix}' on line 133, col 25
+        if _v is not None: write(_filter(_v, rawExpr=u'${alphaBetaPrefix}')) # from line 133, col 25.
+        write(u'''alpha,
+            /* A */ _mmt_matrix_forward_odd, ''')
+        _v = VFFSL(SL,"sourceDimRep.globalLattice",True) # u'${sourceDimRep.globalLattice}' on line 134, col 46
+        if _v is not None: write(_filter(_v, rawExpr=u'${sourceDimRep.globalLattice}')) # from line 134, col 46.
+        write(u'''/2,
+            /* B */ source_data + (_i0 * ''')
+        _v = VFFSL(SL,"sourceDimRep.globalLattice",True) # u'${sourceDimRep.globalLattice}' on line 135, col 42
+        if _v is not None: write(_filter(_v, rawExpr=u'${sourceDimRep.globalLattice}')) # from line 135, col 42.
+        write(u''' + (''')
+        _v = VFFSL(SL,"sourceDimRep.globalLattice",True) # u'${sourceDimRep.globalLattice}' on line 135, col 75
+        if _v is not None: write(_filter(_v, rawExpr=u'${sourceDimRep.globalLattice}')) # from line 135, col 75.
+        write(u'''+1)/2) * innerLoopSize,
+                    innerLoopSize,
+            /* beta */ ''')
+        _v = VFFSL(SL,"alphaBetaPrefix",True) # u'${alphaBetaPrefix}' on line 137, col 24
+        if _v is not None: write(_filter(_v, rawExpr=u'${alphaBetaPrefix}')) # from line 137, col 24.
+        write(u'''beta,
+            /* C */ dest_data + (_i0 * ''')
+        _v = VFFSL(SL,"destDimRep.globalLattice",True) # u'${destDimRep.globalLattice}' on line 138, col 40
+        if _v is not None: write(_filter(_v, rawExpr=u'${destDimRep.globalLattice}')) # from line 138, col 40.
+        write(u''' + 1) * innerLoopSize,
+            2 * innerLoopSize);
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def performBackwardTransform(self, sourceDimRep, destDimRep, **KWS):
+
+
+
+        ## CHEETAH: generated from @def performBackwardTransform($sourceDimRep, $destDimRep) at line 143, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        blasTypeChar = {'real': {'single': 's', 'double': 'd'}, 'complex': {'single': 'c', 'double': 'z'}}[self.matrixType][VFFSL(SL,"precision",True)]
+        alphaBetaPrefix = {'real': '', 'complex': '&'}[self.matrixType]
+        matMultFunction = 'cblas_%sgemm' % blasTypeChar
+        write(u'''const ''')
+        _v = VFFSL(SL,"matrixType",True) # u'${matrixType}' on line 148, col 7
+        if _v is not None: write(_filter(_v, rawExpr=u'${matrixType}')) # from line 148, col 7.
+        write(u''' alpha = 1.0;
+const ''')
+        _v = VFFSL(SL,"matrixType",True) # u'${matrixType}' on line 149, col 7
+        if _v is not None: write(_filter(_v, rawExpr=u'${matrixType}')) # from line 149, col 7.
+        write(u''' beta = 0.0;
+
+// Symmetric component of the transform
+''')
+        _v = VFFSL(SL,"matMultFunction",True) # u'${matMultFunction}' on line 152, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${matMultFunction}')) # from line 152, col 1.
+        write(u'''(CblasRowMajor, CblasNoTrans, CblasNoTrans,
+            (''')
+        _v = VFFSL(SL,"destDimRep.globalLattice",True) # u'${destDimRep.globalLattice}' on line 153, col 14
+        if _v is not None: write(_filter(_v, rawExpr=u'${destDimRep.globalLattice}')) # from line 153, col 14.
+        write(u'''+1)/2,
+            /* nelem */ innerLoopSize,
+            (''')
+        _v = VFFSL(SL,"sourceDimRep.globalLattice",True) # u'${sourceDimRep.globalLattice}' on line 155, col 14
+        if _v is not None: write(_filter(_v, rawExpr=u'${sourceDimRep.globalLattice}')) # from line 155, col 14.
+        write(u'''+1)/2,
+            /* alpha */ ''')
+        _v = VFFSL(SL,"alphaBetaPrefix",True) # u'${alphaBetaPrefix}' on line 156, col 25
+        if _v is not None: write(_filter(_v, rawExpr=u'${alphaBetaPrefix}')) # from line 156, col 25.
+        write(u'''alpha,
+            /* A */ _mmt_matrix_backward_even, (''')
+        _v = VFFSL(SL,"sourceDimRep.globalLattice",True) # u'${sourceDimRep.globalLattice}' on line 157, col 49
+        if _v is not None: write(_filter(_v, rawExpr=u'${sourceDimRep.globalLattice}')) # from line 157, col 49.
+        write(u'''+1)/2,
+            /* B */ source_data + _i0 * ''')
+        _v = VFFSL(SL,"sourceDimRep.globalLattice",True) # u'${sourceDimRep.globalLattice}' on line 158, col 41
+        if _v is not None: write(_filter(_v, rawExpr=u'${sourceDimRep.globalLattice}')) # from line 158, col 41.
+        write(u''' * innerLoopSize,
+                    2 * innerLoopSize,
+            /* beta */ ''')
+        _v = VFFSL(SL,"alphaBetaPrefix",True) # u'${alphaBetaPrefix}' on line 160, col 24
+        if _v is not None: write(_filter(_v, rawExpr=u'${alphaBetaPrefix}')) # from line 160, col 24.
+        write(u'''beta,
+            /* C */ dest_data + _i0 * ''')
+        _v = VFFSL(SL,"destDimRep.globalLattice",True) # u'${destDimRep.globalLattice}' on line 161, col 39
+        if _v is not None: write(_filter(_v, rawExpr=u'${destDimRep.globalLattice}')) # from line 161, col 39.
+        write(u''' * innerLoopSize,
+            innerLoopSize);
+// Antisymmetric component of the transform
+''')
+        _v = VFFSL(SL,"matMultFunction",True) # u'${matMultFunction}' on line 164, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${matMultFunction}')) # from line 164, col 1.
+        write(u'''(CblasRowMajor, CblasNoTrans, CblasNoTrans,
+            ''')
+        _v = VFFSL(SL,"destDimRep.globalLattice",True) # u'${destDimRep.globalLattice}' on line 165, col 13
+        if _v is not None: write(_filter(_v, rawExpr=u'${destDimRep.globalLattice}')) # from line 165, col 13.
+        write(u'''/2,
+            /* nelem */ innerLoopSize,
+            ''')
+        _v = VFFSL(SL,"sourceDimRep.globalLattice",True) # u'${sourceDimRep.globalLattice}' on line 167, col 13
+        if _v is not None: write(_filter(_v, rawExpr=u'${sourceDimRep.globalLattice}')) # from line 167, col 13.
+        write(u'''/2,
+            /* alpha */ ''')
+        _v = VFFSL(SL,"alphaBetaPrefix",True) # u'${alphaBetaPrefix}' on line 168, col 25
+        if _v is not None: write(_filter(_v, rawExpr=u'${alphaBetaPrefix}')) # from line 168, col 25.
+        write(u'''alpha,
+            /* A */ _mmt_matrix_backward_odd, ''')
+        _v = VFFSL(SL,"sourceDimRep.globalLattice",True) # u'${sourceDimRep.globalLattice}' on line 169, col 47
+        if _v is not None: write(_filter(_v, rawExpr=u'${sourceDimRep.globalLattice}')) # from line 169, col 47.
+        write(u'''/2,
+            /* B */ source_data + (_i0 * ''')
+        _v = VFFSL(SL,"sourceDimRep.globalLattice",True) # u'${sourceDimRep.globalLattice}' on line 170, col 42
+        if _v is not None: write(_filter(_v, rawExpr=u'${sourceDimRep.globalLattice}')) # from line 170, col 42.
+        write(u''' + 1) * innerLoopSize,
+                    2 * innerLoopSize,
+            /* beta */ ''')
+        _v = VFFSL(SL,"alphaBetaPrefix",True) # u'${alphaBetaPrefix}' on line 172, col 24
+        if _v is not None: write(_filter(_v, rawExpr=u'${alphaBetaPrefix}')) # from line 172, col 24.
+        write(u'''beta,
+            /* C */ dest_data + (_i0 * ''')
+        _v = VFFSL(SL,"destDimRep.globalLattice",True) # u'${destDimRep.globalLattice}' on line 173, col 40
+        if _v is not None: write(_filter(_v, rawExpr=u'${destDimRep.globalLattice}')) # from line 173, col 40.
+        write(u''' + (''')
+        _v = VFFSL(SL,"destDimRep.globalLattice",True) # u'${destDimRep.globalLattice}' on line 173, col 71
+        if _v is not None: write(_filter(_v, rawExpr=u'${destDimRep.globalLattice}')) # from line 173, col 71.
+        write(u'''+1)/2) * innerLoopSize,
+            innerLoopSize);
+// Loop to unravel symmetric and antisymmetric components.
+''')
+        _v = VFFSL(SL,"matrixType",True) # u'${matrixType}' on line 176, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${matrixType}')) # from line 176, col 1.
+        write(u''' _temp;
+long outerOffset = _i0 * innerLoopSize * ''')
+        _v = VFFSL(SL,"destDimRep.globalLattice",True) # u'${destDimRep.globalLattice}' on line 177, col 42
+        if _v is not None: write(_filter(_v, rawExpr=u'${destDimRep.globalLattice}')) # from line 177, col 42.
+        write(u''';
+for (long _i1 = 0; _i1 < ''')
+        _v = VFFSL(SL,"destDimRep.globalLattice",True) # u'${destDimRep.globalLattice}' on line 178, col 26
+        if _v is not None: write(_filter(_v, rawExpr=u'${destDimRep.globalLattice}')) # from line 178, col 26.
+        write(u'''/2; _i1++) {
+  // _low stored the symmetric component
+  ''')
+        _v = VFFSL(SL,"matrixType",True) # u'${matrixType}' on line 180, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${matrixType}')) # from line 180, col 3.
+        write(u'''* __restrict__ _low = &dest_data[outerOffset + _i1 * innerLoopSize];
+  // _high stored the antisymmetric component
+  ''')
+        _v = VFFSL(SL,"matrixType",True) # u'${matrixType}' on line 182, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${matrixType}')) # from line 182, col 3.
+        write(u'''* __restrict__ _high = &dest_data[outerOffset + (''')
+        _v = VFFSL(SL,"destDimRep.globalLattice",True) # u'${destDimRep.globalLattice}' on line 182, col 65
+        if _v is not None: write(_filter(_v, rawExpr=u'${destDimRep.globalLattice}')) # from line 182, col 65.
+        write(u''' - 1 - _i1) * innerLoopSize];
+  for (long _i2 = 0; _i2 < innerLoopSize; _i2++) {
+    _temp = _low[_i2];
+    // _low is the negative domain
+    _low[_i2] -= _high[_i2];
+    // _high is the positive domain
+    _high[_i2] += _temp;
+  }
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # EPBasis.tmpl
+        # 
+        # Base class for a Basis where each basis function has definite parity
+        # and the parity alternates between successive basis functions.
+        # Bases inheriting from this class will use the faster Parity Matrix Multiplication Transform (PMMT).
+        # 
+        # Created by Graham Dennis on 2008-12-27.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_EPBasis= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(EPBasis, '_initCheetahAttributes'):
+    templateAPIClass = getattr(EPBasis, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(EPBasis)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=EPBasis()).run()
+
+
diff --git a/xpdeint/Features/Transforms/EPBasis.tmpl b/xpdeint/Features/Transforms/EPBasis.tmpl
new file mode 100644
index 0000000..c158417
--- /dev/null
+++ b/xpdeint/Features/Transforms/EPBasis.tmpl
@@ -0,0 +1,193 @@
+@*
+EPBasis.tmpl
+
+Base class for a Basis where each basis function has definite parity
+and the parity alternates between successive basis functions.
+Bases inheriting from this class will use the faster Parity Matrix Multiplication Transform (PMMT).
+
+Created by Graham Dennis on 2008-12-27.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features.Transforms.Basis
+
+ at def transformFunctionStart
+static ${matrixType} *_mmt_matrix_forward_even = NULL;
+static ${matrixType} *_mmt_matrix_forward_odd  = NULL;
+static ${matrixType} *_mmt_matrix_backward_even = NULL;
+static ${matrixType} *_mmt_matrix_backward_odd  = NULL;
+ at end def
+
+
+ at def transformMatricesForDimReps($forwardDimRep, $backwardDimRep)
+long _even_${forwardDimRep.name} = (${forwardDimRep.globalLattice} + 1)/2;
+long _odd_${forwardDimRep.name} = ${forwardDimRep.globalLattice}/2;
+long _even_${backwardDimRep.name} = (${backwardDimRep.globalLattice} + 1)/2;
+long _odd_${backwardDimRep.name} = ${backwardDimRep.globalLattice}/2;
+_mmt_matrix_forward_even = ($matrixType *)xmds_malloc(sizeof($matrixType) * _even_${forwardDimRep.name} * _even_${backwardDimRep.name});
+_mmt_matrix_forward_odd  = ($matrixType *)xmds_malloc(sizeof($matrixType) * _odd_${forwardDimRep.name} * _odd_${backwardDimRep.name});
+_mmt_matrix_backward_even = ($matrixType *)xmds_malloc(sizeof($matrixType) * _even_${backwardDimRep.name} * _even_${forwardDimRep.name});
+_mmt_matrix_backward_odd  = ($matrixType *)xmds_malloc(sizeof($matrixType) * _odd_${backwardDimRep.name} * _odd_${forwardDimRep.name});
+
+for (long _i0 = 0; _i0 < _even_${forwardDimRep.name}; _i0++) {
+  long __i0 = ${forwardDimRep.globalLattice} - 1 - _i0;
+  ${transformMatricesForwardDimConstantsAtIndex(forwardDimRep, backwardDimRep, '__i0'), autoIndent=True}@slurp
+  for (long _i1 = 0; _i1 < ${backwardDimRep.globalLattice}; _i1++) {
+    ${transformMatricesForDimRepsAtIndices(forwardDimRep, backwardDimRep, '_i0', '_i1'), autoIndent=True}@slurp
+  }
+}
+ at end def
+
+ at def transformMatricesForDimRepsAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex)
+  @#
+if (${backwardIndex} & 1) {
+  // ${backwardIndex} is odd
+  if (${forwardIndex} < _odd_${forwardDimRep.name}) {
+    ${transformMatricesForDimRepsAtIndicesOfKind(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex, 'odd'), autoIndent=True}@slurp
+  }
+} else {
+  // ${backwardIndex} is even
+  ${transformMatricesForDimRepsAtIndicesOfKind(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex, 'even'), autoIndent=True}@slurp
+}
+  @#
+ at end def
+
+ at def transformMatricesForDimRepsAtIndicesOfKind($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex, $kind)
+  @#
+  @set $logicalForwardIndex = '_' + forwardIndex
+  @set $logicalBackwardIndex = backwardIndex
+  @set $actualBackwardIndex = '_' + backwardIndex
+  @if kind == 'even'
+    @set $actualForwardIndex = forwardIndex
+  @else
+    @set $actualForwardIndex = c'(_odd_${forwardDimRep.name} -1 - $forwardIndex)'
+  @end if
+long ${actualBackwardIndex} = ${backwardIndex}/2;
+_mmt_matrix_forward_${kind}[${actualBackwardIndex} * _${kind}_${forwardDimRep.name} + ${actualForwardIndex}] = \
+  ${forwardMatrixForDimAtIndices(forwardDimRep, backwardDimRep, logicalForwardIndex, logicalBackwardIndex)};
+_mmt_matrix_backward_${kind}[${actualForwardIndex} * _${kind}_${backwardDimRep.name} + ${actualBackwardIndex}] = \
+  ${backwardMatrixForDimAtIndices(forwardDimRep, backwardDimRep, logicalForwardIndex, logicalBackwardIndex)};
+  @#
+ at end def
+
+ at def performTransform($sourceDimRep, $destDimRep, $dir = None)
+  @#
+  @if dir == 'forward'
+${performForwardTransform(sourceDimRep, destDimRep)}@slurp
+  @else
+${performBackwardTransform(sourceDimRep, destDimRep)}@slurp
+  @end if
+ at end def
+
+ at def performForwardTransform($sourceDimRep, $destDimRep)
+  @#
+  @set $blasTypeChar = {'real': {'single': 's', 'double': 'd'}, 'complex': {'single': 'c', 'double': 'z'}}[self.matrixType][$precision]
+  @set $alphaBetaPrefix = {'real': '', 'complex': '&'}[self.matrixType]
+  @set $matMultFunction = 'cblas_%sgemm' % blasTypeChar
+// Loop to create symmetric and antisymmetric components.
+${matrixType} _temp;
+long outerOffset = _i0 * innerLoopSize * ${sourceDimRep.globalLattice};
+for (long _i1 = 0; _i1 < ${sourceDimRep.globalLattice}/2; _i1++) {
+  ${matrixType}* __restrict__ _low = &source_data[outerOffset + _i1 * innerLoopSize];
+  ${matrixType}* __restrict__ _high = &source_data[outerOffset + (${sourceDimRep.globalLattice} - 1 - _i1) * innerLoopSize];
+  for (long _i2 = 0; _i2 < innerLoopSize; _i2++) {
+    _temp = _low[_i2];
+    _low[_i2] += _high[_i2];  // _low stores the symmetric component
+    _high[_i2] -= _temp; // _high stores the antisymmetric component
+  }
+}
+const ${matrixType} alpha = 1.0;
+const ${matrixType} beta = 0.0;
+
+// Symmetric component of the transform
+${matMultFunction}(CblasRowMajor, CblasNoTrans, CblasNoTrans,
+            (${destDimRep.globalLattice}+1)/2,
+            /* nelem */ innerLoopSize,
+            (${sourceDimRep.globalLattice}+1)/2,
+            /* alpha */ ${alphaBetaPrefix}alpha,
+            /* A */ _mmt_matrix_forward_even, (${sourceDimRep.globalLattice}+1)/2,
+            /* B */ source_data + _i0 * ${sourceDimRep.globalLattice} * innerLoopSize,
+                    innerLoopSize,
+            /* beta */ ${alphaBetaPrefix}beta,
+            /* C */ dest_data + _i0 * ${destDimRep.globalLattice} * innerLoopSize,
+            2 * innerLoopSize);
+// Antisymmetric component of the transform
+${matMultFunction}(CblasRowMajor, CblasNoTrans, CblasNoTrans,
+            ${destDimRep.globalLattice}/2,
+            /* nelem */ innerLoopSize,
+            ${sourceDimRep.globalLattice}/2,
+            /* alpha */ ${alphaBetaPrefix}alpha,
+            /* A */ _mmt_matrix_forward_odd, ${sourceDimRep.globalLattice}/2,
+            /* B */ source_data + (_i0 * ${sourceDimRep.globalLattice} + (${sourceDimRep.globalLattice}+1)/2) * innerLoopSize,
+                    innerLoopSize,
+            /* beta */ ${alphaBetaPrefix}beta,
+            /* C */ dest_data + (_i0 * ${destDimRep.globalLattice} + 1) * innerLoopSize,
+            2 * innerLoopSize);
+  @#
+ at end def
+
+ at def performBackwardTransform($sourceDimRep, $destDimRep)
+  @#
+  @set $blasTypeChar = {'real': {'single': 's', 'double': 'd'}, 'complex': {'single': 'c', 'double': 'z'}}[self.matrixType][$precision]
+  @set $alphaBetaPrefix = {'real': '', 'complex': '&'}[self.matrixType]
+  @set $matMultFunction = 'cblas_%sgemm' % blasTypeChar
+const ${matrixType} alpha = 1.0;
+const ${matrixType} beta = 0.0;
+
+// Symmetric component of the transform
+${matMultFunction}(CblasRowMajor, CblasNoTrans, CblasNoTrans,
+            (${destDimRep.globalLattice}+1)/2,
+            /* nelem */ innerLoopSize,
+            (${sourceDimRep.globalLattice}+1)/2,
+            /* alpha */ ${alphaBetaPrefix}alpha,
+            /* A */ _mmt_matrix_backward_even, (${sourceDimRep.globalLattice}+1)/2,
+            /* B */ source_data + _i0 * ${sourceDimRep.globalLattice} * innerLoopSize,
+                    2 * innerLoopSize,
+            /* beta */ ${alphaBetaPrefix}beta,
+            /* C */ dest_data + _i0 * ${destDimRep.globalLattice} * innerLoopSize,
+            innerLoopSize);
+// Antisymmetric component of the transform
+${matMultFunction}(CblasRowMajor, CblasNoTrans, CblasNoTrans,
+            ${destDimRep.globalLattice}/2,
+            /* nelem */ innerLoopSize,
+            ${sourceDimRep.globalLattice}/2,
+            /* alpha */ ${alphaBetaPrefix}alpha,
+            /* A */ _mmt_matrix_backward_odd, ${sourceDimRep.globalLattice}/2,
+            /* B */ source_data + (_i0 * ${sourceDimRep.globalLattice} + 1) * innerLoopSize,
+                    2 * innerLoopSize,
+            /* beta */ ${alphaBetaPrefix}beta,
+            /* C */ dest_data + (_i0 * ${destDimRep.globalLattice} + (${destDimRep.globalLattice}+1)/2) * innerLoopSize,
+            innerLoopSize);
+// Loop to unravel symmetric and antisymmetric components.
+${matrixType} _temp;
+long outerOffset = _i0 * innerLoopSize * ${destDimRep.globalLattice};
+for (long _i1 = 0; _i1 < ${destDimRep.globalLattice}/2; _i1++) {
+  // _low stored the symmetric component
+  ${matrixType}* __restrict__ _low = &dest_data[outerOffset + _i1 * innerLoopSize];
+  // _high stored the antisymmetric component
+  ${matrixType}* __restrict__ _high = &dest_data[outerOffset + (${destDimRep.globalLattice} - 1 - _i1) * innerLoopSize];
+  for (long _i2 = 0; _i2 < innerLoopSize; _i2++) {
+    _temp = _low[_i2];
+    // _low is the negative domain
+    _low[_i2] -= _high[_i2];
+    // _high is the positive domain
+    _high[_i2] += _temp;
+  }
+}
+  @#
+ at end def
+
diff --git a/xpdeint/Features/Transforms/FourierTransformFFTW3.py b/xpdeint/Features/Transforms/FourierTransformFFTW3.py
new file mode 100644
index 0000000..946dd93
--- /dev/null
+++ b/xpdeint/Features/Transforms/FourierTransformFFTW3.py
@@ -0,0 +1,777 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features.Transforms._FourierTransformFFTW3 import _FourierTransformFFTW3
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.420053
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/Transforms/FourierTransformFFTW3.tmpl'
+__CHEETAH_srcLastModified__ = 'Fri Jul  5 16:29:35 2013'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class FourierTransformFFTW3(_FourierTransformFFTW3):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(FourierTransformFFTW3, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: FFTW3 at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''FFTW3''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def includes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def includes at line 29, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(FourierTransformFFTW3, self).includes()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''#if (CFG_COMPILER == CFG_COMPILER_MSVC)
+  #define FFTW_DLL
+#endif
+
+#include <fftw3.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#define _xmds_malloc ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 41, col 22
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 41, col 22.
+        write(u'''_malloc
+#define xmds_free ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 42, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 42, col 19.
+        write(u'''_free
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def globals(self, **KWS):
+
+
+        """
+        Return the string defining the globals needed by FFTW3.
+        """
+
+        ## CHEETAH: generated from @def globals at line 45, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''const real _inverse_sqrt_2pi = 1.0 / sqrt(2.0 * M_PI); 
+string _fftwWisdomPath;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def transformFunction(self, transformID, transformDict, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def transformFunction(transformID, transformDict, function) at line 55, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        runtimePrefix, prefixLattice, postfixLattice, runtimePostfix = transformDict['transformSpecifier']
+        write(u'''// _prefix_lattice should be ''')
+        _v = VFFSL(SL,"prefixLattice",True) # u'${prefixLattice}' on line 58, col 30
+        if _v is not None: write(_filter(_v, rawExpr=u'${prefixLattice}')) # from line 58, col 30.
+        _v = ''.join([' * ' + runtimeLattice for runtimeLattice in runtimePrefix]) # u"${''.join([' * ' + runtimeLattice for runtimeLattice in runtimePrefix])}" on line 58, col 46
+        if _v is not None: write(_filter(_v, rawExpr=u"${''.join([' * ' + runtimeLattice for runtimeLattice in runtimePrefix])}")) # from line 58, col 46.
+        write(u'''
+// _postfix_lattice should be ''')
+        _v = VFFSL(SL,"postfixLattice",True) # u'${postfixLattice}' on line 59, col 31
+        if _v is not None: write(_filter(_v, rawExpr=u'${postfixLattice}')) # from line 59, col 31.
+        _v = ''.join([' * ' + runtimeLattice for runtimeLattice in runtimePostfix]) # u"${''.join([' * ' + runtimeLattice for runtimeLattice in runtimePostfix])}" on line 59, col 48
+        if _v is not None: write(_filter(_v, rawExpr=u"${''.join([' * ' + runtimeLattice for runtimeLattice in runtimePostfix])}")) # from line 59, col 48.
+        write(u'''
+static ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 60, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 60, col 8.
+        write(u'''_plan _fftw_forward_plan = NULL;
+static ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 61, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 61, col 8.
+        write(u'''_plan _fftw_backward_plan = NULL;
+
+if (!_fftw_forward_plan) {
+  _LOG(_SIMULATION_LOG_LEVEL, "Planning for ''')
+        _v = VFFSL(SL,"function.description",True) # u'${function.description}' on line 64, col 45
+        if _v is not None: write(_filter(_v, rawExpr=u'${function.description}')) # from line 64, col 45.
+        write(u'''...");
+  
+''')
+        transformPair = transformDict['transformPair']
+        dimensionsBeingTransformed = len(transformPair[0])
+        transformType = transformDict['transformType']
+        write(u'''  ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 69, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 69, col 3.
+        write(u'''_iodim _transform_sizes[''')
+        _v = VFFSL(SL,"dimensionsBeingTransformed",True) # u'${dimensionsBeingTransformed}' on line 69, col 40
+        if _v is not None: write(_filter(_v, rawExpr=u'${dimensionsBeingTransformed}')) # from line 69, col 40.
+        write(u'''], _loop_sizes[2];
+''')
+        if transformType == 'real': # generated from line 70, col 3
+            write(u'''  ''')
+            _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 71, col 3
+            if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 71, col 3.
+            write(u'''_r2r_kind _r2r_kinds[''')
+            _v = VFFSL(SL,"dimensionsBeingTransformed",True) # u'${dimensionsBeingTransformed}' on line 71, col 37
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimensionsBeingTransformed}')) # from line 71, col 37.
+            write(u'''];
+''')
+        write(u'''  ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 73, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 73, col 3.
+        write(u'''_iodim *_iodim_ptr = NULL;
+  
+  int _transform_sizes_index = 0, _loop_sizes_index = 0;
+  
+  if (_prefix_lattice > 1) {
+    _iodim_ptr = &_loop_sizes[_loop_sizes_index++];
+    _iodim_ptr->n = _prefix_lattice;
+    _iodim_ptr->is = _iodim_ptr->os = _postfix_lattice * ''')
+        _v = ' * '.join([dimRep.globalLattice for dimRep in transformPair[0]]) # u"${' * '.join([dimRep.globalLattice for dimRep in transformPair[0]])}" on line 80, col 58
+        if _v is not None: write(_filter(_v, rawExpr=u"${' * '.join([dimRep.globalLattice for dimRep in transformPair[0]])}")) # from line 80, col 58.
+        write(u''';
+  }
+  if (_postfix_lattice > 1) {
+    _iodim_ptr = &_loop_sizes[_loop_sizes_index++];
+    _iodim_ptr->n = _postfix_lattice;
+    _iodim_ptr->is = _iodim_ptr->os = 1;
+  }
+''')
+        # 
+        for dimID, dimRep in enumerate(transformPair[0]): # generated from line 88, col 3
+            write(u'''  _iodim_ptr = &_transform_sizes[_transform_sizes_index++];
+  _iodim_ptr->n = ''')
+            _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 90, col 19
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 90, col 19.
+            write(u''';
+  _iodim_ptr->is = _iodim_ptr->os = _postfix_lattice''')
+            _v = ''.join(''.join([u' * ',str(VFFSL(SL,"dr.globalLattice",True))]) for dr in transformPair[0][dimID+1:]) # u"${''.join(c' * ${dr.globalLattice}' for dr in transformPair[0][dimID+1:])}" on line 91, col 53
+            if _v is not None: write(_filter(_v, rawExpr=u"${''.join(c' * ${dr.globalLattice}' for dr in transformPair[0][dimID+1:])}")) # from line 91, col 53.
+            write(u''';
+  
+''')
+        # 
+        if transformType == 'complex': # generated from line 95, col 3
+            guruPlanFunction = self.createGuruDFTPlanInDirection
+            executeSuffix = 'dft'
+            reinterpretType = VFFSL(SL,"fftwPrefix",True) + '_complex'
+        else: # generated from line 99, col 3
+            guruPlanFunction = self.createGuruR2RPlanInDirection
+            executeSuffix = 'r2r'
+            reinterpretType = 'real'
+        # 
+        dataOut = '_data_out' if transformDict.get('outOfPlace', False) else '_data_in'
+        flags = ' | FFTW_DESTROY_INPUT' if transformDict.get('outOfPlace', False) else ''
+        # 
+        write(u'''  
+  ''')
+        _v = VFFSL(SL,"guruPlanFunction",False)(transformDict, 'forward', dataOut, flags) # u"${guruPlanFunction(transformDict, 'forward', dataOut, flags), autoIndent=True}" on line 109, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${guruPlanFunction(transformDict, 'forward', dataOut, flags), autoIndent=True}")) # from line 109, col 3.
+        write(u'''  ''')
+        _v = VFFSL(SL,"guruPlanFunction",False)(transformDict, 'backward', dataOut, flags) # u"${guruPlanFunction(transformDict, 'backward', dataOut, flags), autoIndent=True}" on line 110, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${guruPlanFunction(transformDict, 'backward', dataOut, flags), autoIndent=True}")) # from line 110, col 3.
+        write(u'''  
+  _LOG(_SIMULATION_LOG_LEVEL, " done.\\n");
+}
+
+if (_forward) {
+  ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 116, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 116, col 3.
+        write(u'''_execute_''')
+        _v = VFFSL(SL,"executeSuffix",True) # u'${executeSuffix}' on line 116, col 25
+        if _v is not None: write(_filter(_v, rawExpr=u'${executeSuffix}')) # from line 116, col 25.
+        write(u'''(
+    _fftw_forward_plan,
+    reinterpret_cast<''')
+        _v = VFFSL(SL,"reinterpretType",True) # u'${reinterpretType}' on line 118, col 22
+        if _v is not None: write(_filter(_v, rawExpr=u'${reinterpretType}')) # from line 118, col 22.
+        write(u'''*>(_data_in),
+    reinterpret_cast<''')
+        _v = VFFSL(SL,"reinterpretType",True) # u'${reinterpretType}' on line 119, col 22
+        if _v is not None: write(_filter(_v, rawExpr=u'${reinterpretType}')) # from line 119, col 22.
+        write(u'''*>(''')
+        _v = VFFSL(SL,"dataOut",True) # u'${dataOut}' on line 119, col 43
+        if _v is not None: write(_filter(_v, rawExpr=u'${dataOut}')) # from line 119, col 43.
+        write(u''')
+  );
+} else {
+  ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 122, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 122, col 3.
+        write(u'''_execute_''')
+        _v = VFFSL(SL,"executeSuffix",True) # u'${executeSuffix}' on line 122, col 25
+        if _v is not None: write(_filter(_v, rawExpr=u'${executeSuffix}')) # from line 122, col 25.
+        write(u'''(
+    _fftw_backward_plan,
+    reinterpret_cast<''')
+        _v = VFFSL(SL,"reinterpretType",True) # u'${reinterpretType}' on line 124, col 22
+        if _v is not None: write(_filter(_v, rawExpr=u'${reinterpretType}')) # from line 124, col 22.
+        write(u'''*>(_data_in),
+    reinterpret_cast<''')
+        _v = VFFSL(SL,"reinterpretType",True) # u'${reinterpretType}' on line 125, col 22
+        if _v is not None: write(_filter(_v, rawExpr=u'${reinterpretType}')) # from line 125, col 22.
+        write(u'''*>(''')
+        _v = VFFSL(SL,"dataOut",True) # u'${dataOut}' on line 125, col 43
+        if _v is not None: write(_filter(_v, rawExpr=u'${dataOut}')) # from line 125, col 43.
+        write(u''')
+  );
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def createGuruDFTPlanInDirection(self, transformDict, direction, dataOut, flags, **KWS):
+
+
+
+        ## CHEETAH: generated from @def createGuruDFTPlanInDirection($transformDict, $direction, $dataOut, $flags) at line 131, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''_fftw_''')
+        _v = VFFSL(SL,"direction",True) # u'${direction}' on line 133, col 7
+        if _v is not None: write(_filter(_v, rawExpr=u'${direction}')) # from line 133, col 7.
+        write(u'''_plan = ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 133, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 133, col 27.
+        write(u'''_plan_guru_dft(
+  _transform_sizes_index, _transform_sizes,
+  _loop_sizes_index, _loop_sizes,
+  reinterpret_cast<''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 136, col 20
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 136, col 20.
+        write(u'''_complex*>(_data_in), reinterpret_cast<''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 136, col 72
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 136, col 72.
+        write(u'''_complex*>(''')
+        _v = VFFSL(SL,"dataOut",True) # u'$dataOut' on line 136, col 96
+        if _v is not None: write(_filter(_v, rawExpr=u'$dataOut')) # from line 136, col 96.
+        write(u'''),
+  FFTW_''')
+        _v = VFN(VFFSL(SL,"direction",True),"upper",False)() # u'${direction.upper()}' on line 137, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${direction.upper()}')) # from line 137, col 8.
+        write(u''', ''')
+        _v = VFFSL(SL,"planType",True) # u'${planType}' on line 137, col 30
+        if _v is not None: write(_filter(_v, rawExpr=u'${planType}')) # from line 137, col 30.
+        _v = VFFSL(SL,"flags",True) # u'${flags}' on line 137, col 41
+        if _v is not None: write(_filter(_v, rawExpr=u'${flags}')) # from line 137, col 41.
+        write(u'''
+);
+if (!_fftw_''')
+        _v = VFFSL(SL,"direction",True) # u'${direction}' on line 139, col 12
+        if _v is not None: write(_filter(_v, rawExpr=u'${direction}')) # from line 139, col 12.
+        write(u'''_plan)
+  _LOG(_ERROR_LOG_LEVEL, "(%s: %i) Unable to create ''')
+        _v = VFFSL(SL,"direction",True) # u'${direction}' on line 140, col 53
+        if _v is not None: write(_filter(_v, rawExpr=u'${direction}')) # from line 140, col 53.
+        write(u''' dft plan.\\n", __FILE__, __LINE__);
+
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def createGuruR2RPlanInDirection(self, transformDict, direction, dataOut, flags, **KWS):
+
+
+
+        ## CHEETAH: generated from @def createGuruR2RPlanInDirection($transformDict, $direction, $dataOut, $flags) at line 145, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        for idx, dimRep in enumerate(transformDict['transformPair'][0]): # generated from line 147, col 3
+            write(u'''_r2r_kinds[''')
+            _v = VFFSL(SL,"idx",True) # u'${idx}' on line 148, col 12
+            if _v is not None: write(_filter(_v, rawExpr=u'${idx}')) # from line 148, col 12.
+            write(u'''] = ''')
+            _v = VFFSL(SL,"r2rKindForDimensionAndDirection",False)(dimRep.name, direction) # u'${r2rKindForDimensionAndDirection(dimRep.name, direction)}' on line 148, col 22
+            if _v is not None: write(_filter(_v, rawExpr=u'${r2rKindForDimensionAndDirection(dimRep.name, direction)}')) # from line 148, col 22.
+            write(u''';
+''')
+        write(u'''
+_fftw_''')
+        _v = VFFSL(SL,"direction",True) # u'${direction}' on line 151, col 7
+        if _v is not None: write(_filter(_v, rawExpr=u'${direction}')) # from line 151, col 7.
+        write(u'''_plan = ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 151, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 151, col 27.
+        write(u'''_plan_guru_r2r(
+  _transform_sizes_index, _transform_sizes,
+  _loop_sizes_index, _loop_sizes,
+  reinterpret_cast<real*>(_data_in), reinterpret_cast<real*>(''')
+        _v = VFFSL(SL,"dataOut",True) # u'$dataOut' on line 154, col 62
+        if _v is not None: write(_filter(_v, rawExpr=u'$dataOut')) # from line 154, col 62.
+        write(u'''),
+  _r2r_kinds, ''')
+        _v = VFFSL(SL,"planType",True) # u'${planType}' on line 155, col 15
+        if _v is not None: write(_filter(_v, rawExpr=u'${planType}')) # from line 155, col 15.
+        _v = VFFSL(SL,"flags",True) # u'${flags}' on line 155, col 26
+        if _v is not None: write(_filter(_v, rawExpr=u'${flags}')) # from line 155, col 26.
+        write(u'''
+);
+if (!_fftw_''')
+        _v = VFFSL(SL,"direction",True) # u'${direction}' on line 157, col 12
+        if _v is not None: write(_filter(_v, rawExpr=u'${direction}')) # from line 157, col 12.
+        write(u'''_plan)
+  _LOG(_ERROR_LOG_LEVEL, "(%s: %i) Unable to create ''')
+        _v = VFFSL(SL,"direction",True) # u'${direction}' on line 158, col 53
+        if _v is not None: write(_filter(_v, rawExpr=u'${direction}')) # from line 158, col 53.
+        write(u''' r2r plan.\\n", __FILE__, __LINE__);
+
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def mainBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def mainBegin($dict) at line 163, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u"""// load wisdom
+#if CFG_OSAPI == CFG_OSAPI_POSIX // Don't load wisdom on windows
+""")
+        _v = VFFSL(SL,"loadWisdom",True) # u'${loadWisdom}' on line 166, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${loadWisdom}')) # from line 166, col 1.
+        write(u'''#endif // POSIX
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def loadWisdom(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def loadWisdom at line 171, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''{
+  char _hostName[256];
+  gethostname(_hostName, 256);
+  _hostName[255] = \'\\0\'; // just in case
+  
+  string _pathToWisdom = getenv("HOME");
+  _pathToWisdom += "/.xmds/wisdom/";
+  
+  string _wisdomFileName = _hostName;
+  _wisdomFileName += ".wisdom";
+  _wisdomFileName += "''')
+        _v = VFFSL(SL,"wisdomExtension",True) # u'${wisdomExtension}' on line 183, col 23
+        if _v is not None: write(_filter(_v, rawExpr=u'${wisdomExtension}')) # from line 183, col 23.
+        write(u'''";
+  
+  FILE *_fp = NULL;
+  
+  _fp = fopen(_pathToWisdom.c_str(), "r");
+  if (_fp) {
+    fclose(_fp);
+  } else {
+    int _result = mkdir((string(getenv("HOME")) + "/.xmds").c_str(), S_IRWXU);
+    if (mkdir(_pathToWisdom.c_str(), S_IRWXU)) {
+      // We failed to create the ~/.xmds/wisdom directory
+      _LOG(_WARNING_LOG_LEVEL, "Warning: Cannot find enlightenment, the path to wisdom ~/.xmds/wisdom doesn\'t seem to exist and we couldn\'t create it.\\n"
+                               "         I\'ll use the current path instead.\\n");
+      _pathToWisdom = ""; // present directory
+    }
+    
+  }
+  
+  _fftwWisdomPath = _pathToWisdom + _wisdomFileName;
+  
+  FILE *_wisdomFile = NULL;
+  if ( (_wisdomFile = fopen(_fftwWisdomPath.c_str(), "r")) != NULL) {
+    _LOG(_SIMULATION_LOG_LEVEL, "Found enlightenment... (Importing wisdom)\\n");
+    ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 206, col 5
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 206, col 5.
+        write(u'''_import_wisdom_from_file(_wisdomFile);
+    fclose(_wisdomFile);
+  }
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def saveWisdom(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def saveWisdom at line 214, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''{
+  FILE *_wisdomFile = NULL;
+  if ( (_wisdomFile = fopen(_fftwWisdomPath.c_str(), "w")) != NULL) {
+    ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 219, col 5
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 219, col 5.
+        write(u'''_export_wisdom_to_file(_wisdomFile);
+    fclose(_wisdomFile);
+  }
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def mainEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def mainEnd($dict) at line 227, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''
+// Save wisdom
+#if CFG_OSAPI == CFG_OSAPI_POSIX
+''')
+        _v = VFFSL(SL,"saveWisdom",True) # u'${saveWisdom, autoIndent=True}' on line 232, col 1
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${saveWisdom, autoIndent=True}')) # from line 232, col 1.
+        write(u'''#endif // POSIX
+
+''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 235, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 235, col 1.
+        write(u'''_cleanup();
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # FourierTransformFFTW3.tmpl
+        # 
+        # Created by Graham Dennis on 2007-08-23.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    planType = "FFTW_MEASURE"
+
+    supportsInPlaceOperation = True
+
+    _mainCheetahMethod_for_FourierTransformFFTW3= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(FourierTransformFFTW3, '_initCheetahAttributes'):
+    templateAPIClass = getattr(FourierTransformFFTW3, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(FourierTransformFFTW3)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=FourierTransformFFTW3()).run()
+
+
diff --git a/xpdeint/Features/Transforms/FourierTransformFFTW3.tmpl b/xpdeint/Features/Transforms/FourierTransformFFTW3.tmpl
new file mode 100644
index 0000000..ab09463
--- /dev/null
+++ b/xpdeint/Features/Transforms/FourierTransformFFTW3.tmpl
@@ -0,0 +1,238 @@
+@*
+FourierTransformFFTW3.tmpl
+
+Created by Graham Dennis on 2007-08-23.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features.Transforms._FourierTransformFFTW3
+
+ at def description: FFTW3
+
+ at attr $planType = "FFTW_MEASURE"
+ at attr $supportsInPlaceOperation = True
+
+ at def includes
+  @#
+  @super
+  @#
+#if (CFG_COMPILER == CFG_COMPILER_MSVC)
+  #define FFTW_DLL
+#endif
+
+#include <fftw3.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#define _xmds_malloc ${fftwPrefix}_malloc
+#define xmds_free ${fftwPrefix}_free
+ at end def
+
+ at def globals
+@*doc:
+Return the string defining the globals needed by FFTW3.
+*@
+  @#
+const real _inverse_sqrt_2pi = 1.0 / sqrt(2.0 * M_PI); 
+string _fftwWisdomPath;
+  @#
+ at end def
+
+ at def transformFunction(transformID, transformDict, function)
+  @#
+  @set runtimePrefix, prefixLattice, postfixLattice, runtimePostfix = transformDict['transformSpecifier']
+// _prefix_lattice should be ${prefixLattice}${''.join([' * ' + runtimeLattice for runtimeLattice in runtimePrefix])}
+// _postfix_lattice should be ${postfixLattice}${''.join([' * ' + runtimeLattice for runtimeLattice in runtimePostfix])}
+static ${fftwPrefix}_plan _fftw_forward_plan = NULL;
+static ${fftwPrefix}_plan _fftw_backward_plan = NULL;
+
+if (!_fftw_forward_plan) {
+  _LOG(_SIMULATION_LOG_LEVEL, "Planning for ${function.description}...");
+  
+  @set $transformPair = transformDict['transformPair']
+  @set $dimensionsBeingTransformed = len(transformPair[0])
+  @set $transformType = transformDict['transformType']
+  ${fftwPrefix}_iodim _transform_sizes[${dimensionsBeingTransformed}], _loop_sizes[2];
+  @if transformType == 'real'
+  ${fftwPrefix}_r2r_kind _r2r_kinds[${dimensionsBeingTransformed}];
+  @end if
+  ${fftwPrefix}_iodim *_iodim_ptr = NULL;
+  
+  int _transform_sizes_index = 0, _loop_sizes_index = 0;
+  
+  if (_prefix_lattice > 1) {
+    _iodim_ptr = &_loop_sizes[_loop_sizes_index++];
+    _iodim_ptr->n = _prefix_lattice;
+    _iodim_ptr->is = _iodim_ptr->os = _postfix_lattice * ${' * '.join([dimRep.globalLattice for dimRep in transformPair[0]])};
+  }
+  if (_postfix_lattice > 1) {
+    _iodim_ptr = &_loop_sizes[_loop_sizes_index++];
+    _iodim_ptr->n = _postfix_lattice;
+    _iodim_ptr->is = _iodim_ptr->os = 1;
+  }
+  @#
+  @for dimID, dimRep in enumerate(transformPair[0])
+  _iodim_ptr = &_transform_sizes[_transform_sizes_index++];
+  _iodim_ptr->n = ${dimRep.globalLattice};
+  _iodim_ptr->is = _iodim_ptr->os = _postfix_lattice${''.join(c' * ${dr.globalLattice}' for dr in transformPair[0][dimID+1:])};
+  
+  @end for
+  @#
+  @if transformType == 'complex'
+    @set $guruPlanFunction = self.createGuruDFTPlanInDirection
+    @set $executeSuffix = 'dft'
+    @set $reinterpretType = $fftwPrefix + '_complex'
+  @else
+    @set $guruPlanFunction = self.createGuruR2RPlanInDirection
+    @set $executeSuffix = 'r2r'
+    @set $reinterpretType = 'real'
+  @end if
+  @#
+  @set $dataOut = '_data_out' if transformDict.get('outOfPlace', False) else '_data_in'
+  @set $flags = ' | FFTW_DESTROY_INPUT' if transformDict.get('outOfPlace', False) else ''
+  @#
+  
+  ${guruPlanFunction(transformDict, 'forward', dataOut, flags), autoIndent=True}@slurp
+  ${guruPlanFunction(transformDict, 'backward', dataOut, flags), autoIndent=True}@slurp
+  
+  _LOG(_SIMULATION_LOG_LEVEL, " done.\n");
+}
+
+if (_forward) {
+  ${fftwPrefix}_execute_${executeSuffix}(
+    _fftw_forward_plan,
+    reinterpret_cast<${reinterpretType}*>(_data_in),
+    reinterpret_cast<${reinterpretType}*>(${dataOut})
+  );
+} else {
+  ${fftwPrefix}_execute_${executeSuffix}(
+    _fftw_backward_plan,
+    reinterpret_cast<${reinterpretType}*>(_data_in),
+    reinterpret_cast<${reinterpretType}*>(${dataOut})
+  );
+}
+  @#
+ at end def
+
+ at def createGuruDFTPlanInDirection($transformDict, $direction, $dataOut, $flags)
+  @#
+_fftw_${direction}_plan = ${fftwPrefix}_plan_guru_dft(
+  _transform_sizes_index, _transform_sizes,
+  _loop_sizes_index, _loop_sizes,
+  reinterpret_cast<${fftwPrefix}_complex*>(_data_in), reinterpret_cast<${fftwPrefix}_complex*>($dataOut),
+  FFTW_${direction.upper()}, ${planType}${flags}
+);
+if (!_fftw_${direction}_plan)
+  _LOG(_ERROR_LOG_LEVEL, "(%s: %i) Unable to create ${direction} dft plan.\n", __FILE__, __LINE__);
+
+  @#
+ at end def
+
+ at def createGuruR2RPlanInDirection($transformDict, $direction, $dataOut, $flags)
+  @#
+  @for idx, dimRep in enumerate(transformDict['transformPair'][0])
+_r2r_kinds[${idx}] = ${r2rKindForDimensionAndDirection(dimRep.name, direction)};
+  @end for
+
+_fftw_${direction}_plan = ${fftwPrefix}_plan_guru_r2r(
+  _transform_sizes_index, _transform_sizes,
+  _loop_sizes_index, _loop_sizes,
+  reinterpret_cast<real*>(_data_in), reinterpret_cast<real*>($dataOut),
+  _r2r_kinds, ${planType}${flags}
+);
+if (!_fftw_${direction}_plan)
+  _LOG(_ERROR_LOG_LEVEL, "(%s: %i) Unable to create ${direction} r2r plan.\n", __FILE__, __LINE__);
+
+  @#
+ at end def
+
+ at def mainBegin($dict)
+// load wisdom
+#if CFG_OSAPI == CFG_OSAPI_POSIX // Don't load wisdom on windows
+${loadWisdom}@slurp
+#endif // POSIX
+ at end def
+
+
+ at def loadWisdom
+  @#
+{
+  char _hostName[256];
+  gethostname(_hostName, 256);
+  _hostName[255] = '\0'; // just in case
+  
+  string _pathToWisdom = getenv("HOME");
+  _pathToWisdom += "/.xmds/wisdom/";
+  
+  string _wisdomFileName = _hostName;
+  _wisdomFileName += ".wisdom";
+  _wisdomFileName += "${wisdomExtension}";
+  
+  FILE *_fp = NULL;
+  
+  _fp = fopen(_pathToWisdom.c_str(), "r");
+  if (_fp) {
+    fclose(_fp);
+  } else {
+    int _result = mkdir((string(getenv("HOME")) + "/.xmds").c_str(), S_IRWXU);
+    if (mkdir(_pathToWisdom.c_str(), S_IRWXU)) {
+      // We failed to create the ~/.xmds/wisdom directory
+      _LOG(_WARNING_LOG_LEVEL, "Warning: Cannot find enlightenment, the path to wisdom ~/.xmds/wisdom doesn't seem to exist and we couldn't create it.\n"
+                               "         I'll use the current path instead.\n");
+      _pathToWisdom = ""; // present directory
+    }
+    
+  }
+  
+  _fftwWisdomPath = _pathToWisdom + _wisdomFileName;
+  
+  FILE *_wisdomFile = NULL;
+  if ( (_wisdomFile = fopen(_fftwWisdomPath.c_str(), "r")) != NULL) {
+    _LOG(_SIMULATION_LOG_LEVEL, "Found enlightenment... (Importing wisdom)\n");
+    ${fftwPrefix}_import_wisdom_from_file(_wisdomFile);
+    fclose(_wisdomFile);
+  }
+}
+  @#
+ at end def
+
+
+ at def saveWisdom
+  @#
+{
+  FILE *_wisdomFile = NULL;
+  if ( (_wisdomFile = fopen(_fftwWisdomPath.c_str(), "w")) != NULL) {
+    ${fftwPrefix}_export_wisdom_to_file(_wisdomFile);
+    fclose(_wisdomFile);
+  }
+}
+  @#
+ at end def
+
+
+ at def mainEnd($dict)
+  @#
+
+// Save wisdom
+#if CFG_OSAPI == CFG_OSAPI_POSIX
+${saveWisdom, autoIndent=True}@slurp
+#endif // POSIX
+
+${fftwPrefix}_cleanup();
+  @#
+ at end def
+
diff --git a/xpdeint/Features/Transforms/FourierTransformFFTW3MPI.py b/xpdeint/Features/Transforms/FourierTransformFFTW3MPI.py
new file mode 100644
index 0000000..25aaec5
--- /dev/null
+++ b/xpdeint/Features/Transforms/FourierTransformFFTW3MPI.py
@@ -0,0 +1,1296 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features.Transforms._FourierTransformFFTW3MPI import _FourierTransformFFTW3MPI
+import operator
+from xpdeint.Geometry.UniformDimensionRepresentation import UniformDimensionRepresentation
+from xpdeint.Geometry.SplitUniformDimensionRepresentation import SplitUniformDimensionRepresentation
+from xpdeint.Utilities import permutations
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.647409
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/Transforms/FourierTransformFFTW3MPI.tmpl'
+__CHEETAH_srcLastModified__ = 'Tue May 22 16:27:12 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class FourierTransformFFTW3MPI(_FourierTransformFFTW3MPI):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(FourierTransformFFTW3MPI, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: FFTW3 with MPI at line 29, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''FFTW3 with MPI''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def includes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def includes at line 32, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(FourierTransformFFTW3MPI, self).includes()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''#include <fftw3-mpi.h>
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def globals at line 39, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(FourierTransformFFTW3MPI, self).globals()
+        if _v is not None: write(_filter(_v))
+        # 
+        for dimRep in [dimRep for dim in self.mpiDimensions for dimRep in dim.representations if dimRep.hasLocalOffset]: # generated from line 43, col 3
+            write(u'''ptrdiff_t _block_size_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 44, col 23
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 44, col 23.
+            write(u''' = FFTW_MPI_DEFAULT_BLOCK;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def setLocalLatticeAndOffsetVariables(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def setLocalLatticeAndOffsetVariables at line 49, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''// First work out the local lattice and offset for the geometry
+ptrdiff_t _sizes[''')
+        _v = VFFSL(SL,"len",False)(VFFSL(SL,"geometry.dimensions",True)) # u'${len($geometry.dimensions)}' on line 52, col 18
+        if _v is not None: write(_filter(_v, rawExpr=u'${len($geometry.dimensions)}')) # from line 52, col 18.
+        write(u'''];
+''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 53, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 53, col 1.
+        write(u'''_mpi_init();
+''')
+        for firstMPIDimRep, secondMPIDimRep in permutations(*[dim.representations for dim in self.mpiDimensions]): # generated from line 54, col 3
+            if not (firstMPIDimRep.hasLocalOffset and secondMPIDimRep.hasLocalOffset): # generated from line 55, col 5
+                continue
+            write(u'''_sizes[0] = ''')
+            _v = VFFSL(SL,"firstMPIDimRep.globalLattice",True) # u'${firstMPIDimRep.globalLattice}' on line 58, col 13
+            if _v is not None: write(_filter(_v, rawExpr=u'${firstMPIDimRep.globalLattice}')) # from line 58, col 13.
+            write(u'''; _sizes[1] = ''')
+            _v = VFFSL(SL,"secondMPIDimRep.globalLattice",True) # u'${secondMPIDimRep.globalLattice}' on line 58, col 58
+            if _v is not None: write(_filter(_v, rawExpr=u'${secondMPIDimRep.globalLattice}')) # from line 58, col 58.
+            write(u''';
+''')
+            _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 59, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 59, col 1.
+            write(u'''_mpi_local_size_many_transposed(
+  2, _sizes, 1, _block_size_''')
+            _v = VFFSL(SL,"firstMPIDimRep.name",True) # u'${firstMPIDimRep.name}' on line 60, col 29
+            if _v is not None: write(_filter(_v, rawExpr=u'${firstMPIDimRep.name}')) # from line 60, col 29.
+            write(u''', _block_size_''')
+            _v = VFFSL(SL,"secondMPIDimRep.name",True) # u'${secondMPIDimRep.name}' on line 60, col 65
+            if _v is not None: write(_filter(_v, rawExpr=u'${secondMPIDimRep.name}')) # from line 60, col 65.
+            write(u''', MPI_COMM_WORLD,
+  &''')
+            _v = VFFSL(SL,"firstMPIDimRep.localLattice",True) # u'${firstMPIDimRep.localLattice}' on line 61, col 4
+            if _v is not None: write(_filter(_v, rawExpr=u'${firstMPIDimRep.localLattice}')) # from line 61, col 4.
+            write(u''', &''')
+            _v = VFFSL(SL,"firstMPIDimRep.localOffset",True) # u'${firstMPIDimRep.localOffset}' on line 61, col 37
+            if _v is not None: write(_filter(_v, rawExpr=u'${firstMPIDimRep.localOffset}')) # from line 61, col 37.
+            write(u''',
+  &''')
+            _v = VFFSL(SL,"secondMPIDimRep.localLattice",True) # u'${secondMPIDimRep.localLattice}' on line 62, col 4
+            if _v is not None: write(_filter(_v, rawExpr=u'${secondMPIDimRep.localLattice}')) # from line 62, col 4.
+            write(u''', &''')
+            _v = VFFSL(SL,"secondMPIDimRep.localOffset",True) # u'${secondMPIDimRep.localOffset}' on line 62, col 38
+            if _v is not None: write(_filter(_v, rawExpr=u'${secondMPIDimRep.localOffset}')) # from line 62, col 38.
+            write(u'''
+);
+
+if (_rank == 0) {
+  _block_size_''')
+            _v = VFFSL(SL,"firstMPIDimRep.name",True) # u'${firstMPIDimRep.name}' on line 66, col 15
+            if _v is not None: write(_filter(_v, rawExpr=u'${firstMPIDimRep.name}')) # from line 66, col 15.
+            write(u''' = ''')
+            _v = VFFSL(SL,"firstMPIDimRep.localLattice",True) # u'${firstMPIDimRep.localLattice}' on line 66, col 40
+            if _v is not None: write(_filter(_v, rawExpr=u'${firstMPIDimRep.localLattice}')) # from line 66, col 40.
+            write(u''';
+  _block_size_''')
+            _v = VFFSL(SL,"secondMPIDimRep.name",True) # u'${secondMPIDimRep.name}' on line 67, col 15
+            if _v is not None: write(_filter(_v, rawExpr=u'${secondMPIDimRep.name}')) # from line 67, col 15.
+            write(u''' = ''')
+            _v = VFFSL(SL,"secondMPIDimRep.localLattice",True) # u'${secondMPIDimRep.localLattice}' on line 67, col 41
+            if _v is not None: write(_filter(_v, rawExpr=u'${secondMPIDimRep.localLattice}')) # from line 67, col 41.
+            write(u''';
+}
+MPI_Bcast(&_block_size_''')
+            _v = VFFSL(SL,"firstMPIDimRep.name",True) # u'${firstMPIDimRep.name}' on line 69, col 24
+            if _v is not None: write(_filter(_v, rawExpr=u'${firstMPIDimRep.name}')) # from line 69, col 24.
+            write(u''', sizeof(ptrdiff_t), MPI_BYTE, 0, MPI_COMM_WORLD);
+MPI_Bcast(&_block_size_''')
+            _v = VFFSL(SL,"secondMPIDimRep.name",True) # u'${secondMPIDimRep.name}' on line 70, col 24
+            if _v is not None: write(_filter(_v, rawExpr=u'${secondMPIDimRep.name}')) # from line 70, col 24.
+            write(u''', sizeof(ptrdiff_t), MPI_BYTE, 0, MPI_COMM_WORLD);
+
+''')
+        # 
+        firstMPIDim, secondMPIDim = VFFSL(SL,"mpiDimensions",True)
+        for field in VFFSL(SL,"fields",True): # generated from line 75, col 3
+            if field.name == 'geometry' or not field.isDistributed: # generated from line 76, col 5
+                continue
+            # 
+            #  Set the local_lattice and local_offset variables based on the
+            #  values for the geometry's version of these
+            fieldMPIDim1 = field.dimensionWithName(firstMPIDim.name)
+            fieldMPIDim2 = field.dimensionWithName(secondMPIDim.name)
+            for fieldDim, geometryDim in [(fieldMPIDim1, firstMPIDim), (fieldMPIDim2, secondMPIDim)]: # generated from line 84, col 5
+                for fieldRep, geometryRep in zip(fieldDim.representations, geometryDim.representations): # generated from line 85, col 7
+                    if (not fieldRep) or (not fieldRep.hasLocalOffset) or (not fieldRep.parent is fieldDim): # generated from line 86, col 9
+                        continue
+                    write(u"""// Set the local lattice and offset variables for the '""")
+                    _v = VFFSL(SL,"field.name",True) # u'${field.name}' on line 89, col 56
+                    if _v is not None: write(_filter(_v, rawExpr=u'${field.name}')) # from line 89, col 56.
+                    write(u"""' field
+""")
+                    if fieldRep == geometryRep: # generated from line 90, col 9
+                        _v = VFFSL(SL,"fieldRep.localLattice",True) # u'${fieldRep.localLattice}' on line 91, col 1
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localLattice}')) # from line 91, col 1.
+                        write(u''' = ''')
+                        _v = VFFSL(SL,"geometryRep.localLattice",True) # u'${geometryRep.localLattice}' on line 91, col 28
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localLattice}')) # from line 91, col 28.
+                        write(u''';
+''')
+                        _v = VFFSL(SL,"fieldRep.localOffset",True) # u'${fieldRep.localOffset}' on line 92, col 1
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localOffset}')) # from line 92, col 1.
+                        write(u''' = ''')
+                        _v = VFFSL(SL,"geometryRep.localOffset",True) # u'${geometryRep.localOffset}' on line 92, col 27
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localOffset}')) # from line 92, col 27.
+                        write(u''';
+''')
+                    elif fieldRep.reductionMethod == fieldRep.ReductionMethod.fixedRange: # generated from line 93, col 9
+                        #  In this case we are in 'x' space and are subdividing a distributed dimension
+                        #  fixedRange reduction method means we take every nth point.
+                        write(u'''ptrdiff_t _''')
+                        _v = VFFSL(SL,"field.name",True) # u'${field.name}' on line 96, col 12
+                        if _v is not None: write(_filter(_v, rawExpr=u'${field.name}')) # from line 96, col 12.
+                        write(u'''_''')
+                        _v = VFFSL(SL,"fieldRep.name",True) # u'${fieldRep.name}' on line 96, col 26
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.name}')) # from line 96, col 26.
+                        write(u'''_skip_size = ''')
+                        _v = VFFSL(SL,"geometryRep.globalLattice",True) # u'${geometryRep.globalLattice}' on line 96, col 55
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.globalLattice}')) # from line 96, col 55.
+                        write(u'''/''')
+                        _v = VFFSL(SL,"fieldRep.globalLattice",True) # u'${fieldRep.globalLattice}' on line 96, col 84
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.globalLattice}')) # from line 96, col 84.
+                        write(u''';
+if (_rank == 0) {
+  ''')
+                        _v = VFFSL(SL,"fieldRep.localOffset",True) # u'${fieldRep.localOffset}' on line 98, col 3
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localOffset}')) # from line 98, col 3.
+                        write(u'''  = 0;
+  ''')
+                        _v = VFFSL(SL,"fieldRep.localLattice",True) # u'${fieldRep.localLattice}' on line 99, col 3
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localLattice}')) # from line 99, col 3.
+                        write(u''' = (''')
+                        _v = VFFSL(SL,"geometryRep.localLattice",True) # u'${geometryRep.localLattice}' on line 99, col 31
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localLattice}')) # from line 99, col 31.
+                        write(u'''-1)/_''')
+                        _v = VFFSL(SL,"field.name",True) # u'${field.name}' on line 99, col 63
+                        if _v is not None: write(_filter(_v, rawExpr=u'${field.name}')) # from line 99, col 63.
+                        write(u'''_''')
+                        _v = VFFSL(SL,"fieldRep.name",True) # u'${fieldRep.name}' on line 99, col 77
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.name}')) # from line 99, col 77.
+                        write(u'''_skip_size + 1;
+} else {
+  ''')
+                        _v = VFFSL(SL,"fieldRep.localOffset",True) # u'${fieldRep.localOffset}' on line 101, col 3
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localOffset}')) # from line 101, col 3.
+                        write(u'''  = (''')
+                        _v = VFFSL(SL,"geometryRep.localOffset",True) # u'${geometryRep.localOffset}' on line 101, col 31
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localOffset}')) # from line 101, col 31.
+                        write(u'''-1)/_''')
+                        _v = VFFSL(SL,"field.name",True) # u'${field.name}' on line 101, col 62
+                        if _v is not None: write(_filter(_v, rawExpr=u'${field.name}')) # from line 101, col 62.
+                        write(u'''_''')
+                        _v = VFFSL(SL,"fieldRep.name",True) # u'${fieldRep.name}' on line 101, col 76
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.name}')) # from line 101, col 76.
+                        write(u'''_skip_size + 1;
+  ''')
+                        _v = VFFSL(SL,"fieldRep.localLattice",True) # u'${fieldRep.localLattice}' on line 102, col 3
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localLattice}')) # from line 102, col 3.
+                        write(u''' = (''')
+                        _v = VFFSL(SL,"geometryRep.localOffset",True) # u'${geometryRep.localOffset}' on line 102, col 31
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localOffset}')) # from line 102, col 31.
+                        write(u''' + ''')
+                        _v = VFFSL(SL,"geometryRep.localLattice",True) # u'${geometryRep.localLattice}' on line 102, col 60
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localLattice}')) # from line 102, col 60.
+                        write(u''' - 1)/_''')
+                        _v = VFFSL(SL,"field.name",True) # u'${field.name}' on line 102, col 94
+                        if _v is not None: write(_filter(_v, rawExpr=u'${field.name}')) # from line 102, col 94.
+                        write(u'''_''')
+                        _v = VFFSL(SL,"fieldRep.name",True) # u'${fieldRep.name}' on line 102, col 108
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.name}')) # from line 102, col 108.
+                        write(u'''_skip_size
+                             + 1 - ''')
+                        _v = VFFSL(SL,"fieldRep.localOffset",True) # u'${fieldRep.localOffset}' on line 103, col 36
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localOffset}')) # from line 103, col 36.
+                        write(u''';
+}
+''')
+                    elif isinstance(fieldRep, UniformDimensionRepresentation): # generated from line 105, col 9
+                        #  In this case, we are in 'k' space and may be subdividing a UniformDimensionRepresentation (dct/dst)
+                        #  Note that this is a fixedStep reduction method
+                        write(u'''if (''')
+                        _v = VFFSL(SL,"geometryRep.localOffset",True) # u'${geometryRep.localOffset}' on line 108, col 5
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localOffset}')) # from line 108, col 5.
+                        write(u''' >= ''')
+                        _v = VFFSL(SL,"fieldRep.globalLattice",True) # u'${fieldRep.globalLattice}' on line 108, col 35
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.globalLattice}')) # from line 108, col 35.
+                        write(u''') {
+  // No points here
+  ''')
+                        _v = VFFSL(SL,"fieldRep.localOffset",True) # u'${fieldRep.localOffset}' on line 110, col 3
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localOffset}')) # from line 110, col 3.
+                        write(u''' = 0;
+  ''')
+                        _v = VFFSL(SL,"fieldRep.localLattice",True) # u'${fieldRep.localLattice}' on line 111, col 3
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localLattice}')) # from line 111, col 3.
+                        write(u''' = 0;
+} else if (''')
+                        _v = VFFSL(SL,"geometryRep.localOffset",True) # u'${geometryRep.localOffset}' on line 112, col 12
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localOffset}')) # from line 112, col 12.
+                        write(u''' + ''')
+                        _v = VFFSL(SL,"geometryRep.localLattice",True) # u'${geometryRep.localLattice}' on line 112, col 41
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localLattice}')) # from line 112, col 41.
+                        write(u''' > ''')
+                        _v = VFFSL(SL,"fieldRep.globalLattice",True) # u'${fieldRep.globalLattice}' on line 112, col 71
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.globalLattice}')) # from line 112, col 71.
+                        write(u'''){
+  // The upper edge is here
+  ''')
+                        _v = VFFSL(SL,"fieldRep.localOffset",True) # u'${fieldRep.localOffset}' on line 114, col 3
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localOffset}')) # from line 114, col 3.
+                        write(u''' = ''')
+                        _v = VFFSL(SL,"geometryRep.localOffset",True) # u'${geometryRep.localOffset}' on line 114, col 29
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localOffset}')) # from line 114, col 29.
+                        write(u''';
+  ''')
+                        _v = VFFSL(SL,"fieldRep.localLattice",True) # u'${fieldRep.localLattice}' on line 115, col 3
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localLattice}')) # from line 115, col 3.
+                        write(u''' = ''')
+                        _v = VFFSL(SL,"fieldRep.globalLattice",True) # u'${fieldRep.globalLattice}' on line 115, col 30
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.globalLattice}')) # from line 115, col 30.
+                        write(u''' - ''')
+                        _v = VFFSL(SL,"geometryRep.localOffset",True) # u'${geometryRep.localOffset}' on line 115, col 58
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localOffset}')) # from line 115, col 58.
+                        write(u''';
+} else {
+  // somewhere near the start
+  ''')
+                        _v = VFFSL(SL,"fieldRep.localOffset",True) # u'${fieldRep.localOffset}' on line 118, col 3
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localOffset}')) # from line 118, col 3.
+                        write(u''' = ''')
+                        _v = VFFSL(SL,"geometryRep.localOffset",True) # u'${geometryRep.localOffset}' on line 118, col 29
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localOffset}')) # from line 118, col 29.
+                        write(u''';
+  ''')
+                        _v = VFFSL(SL,"fieldRep.localLattice",True) # u'${fieldRep.localLattice}' on line 119, col 3
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localLattice}')) # from line 119, col 3.
+                        write(u''' = ''')
+                        _v = VFFSL(SL,"geometryRep.localLattice",True) # u'${geometryRep.localLattice}' on line 119, col 30
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localLattice}')) # from line 119, col 30.
+                        write(u''';
+}
+''')
+                    elif isinstance(fieldRep, SplitUniformDimensionRepresentation): # generated from line 121, col 9
+                        #  In this case, we are in 'k' space and may be subdividing a SplitUniformDimensionRepresentation (dft)
+                        #  Note that this is a fixedStep reduction method
+                        _v = VFFSL(SL,"fieldRep.localOffset",True) # u'${fieldRep.localOffset}' on line 124, col 1
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localOffset}')) # from line 124, col 1.
+                        write(u''' = -1;
+if (''')
+                        _v = VFFSL(SL,"geometryRep.localOffset",True) # u'${geometryRep.localOffset}' on line 125, col 5
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localOffset}')) # from line 125, col 5.
+                        write(u''' >= (''')
+                        _v = VFFSL(SL,"fieldRep.globalLattice",True) # u'${fieldRep.globalLattice}' on line 125, col 36
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.globalLattice}')) # from line 125, col 36.
+                        write(u"""+1)/2) {
+  // No points due to positive 'k' values.
+} else if (""")
+                        _v = VFFSL(SL,"geometryRep.localOffset",True) # u'${geometryRep.localOffset}' on line 127, col 12
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localOffset}')) # from line 127, col 12.
+                        write(u''' + ''')
+                        _v = VFFSL(SL,"geometryRep.localLattice",True) # u'${geometryRep.localLattice}' on line 127, col 41
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localLattice}')) # from line 127, col 41.
+                        write(u''' > (''')
+                        _v = VFFSL(SL,"fieldRep.globalLattice",True) # u'${fieldRep.globalLattice}' on line 127, col 72
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.globalLattice}')) # from line 127, col 72.
+                        write(u'''+1)/2) {
+  // the upper edge of the positive values are here
+  ''')
+                        _v = VFFSL(SL,"fieldRep.localOffset",True) # u'${fieldRep.localOffset}' on line 129, col 3
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localOffset}')) # from line 129, col 3.
+                        write(u''' = ''')
+                        _v = VFFSL(SL,"geometryRep.localOffset",True) # u'${geometryRep.localOffset}' on line 129, col 29
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localOffset}')) # from line 129, col 29.
+                        write(u''';
+  ''')
+                        _v = VFFSL(SL,"fieldRep.localLattice",True) # u'${fieldRep.localLattice}' on line 130, col 3
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localLattice}')) # from line 130, col 3.
+                        write(u''' = (''')
+                        _v = VFFSL(SL,"fieldRep.globalLattice",True) # u'${fieldRep.globalLattice}' on line 130, col 31
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.globalLattice}')) # from line 130, col 31.
+                        write(u'''+1)/2 - ''')
+                        _v = VFFSL(SL,"geometryRep.localOffset",True) # u'${geometryRep.localOffset}' on line 130, col 64
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localOffset}')) # from line 130, col 64.
+                        write(u''';
+} else if (''')
+                        _v = VFFSL(SL,"geometryRep.localOffset",True) # u'${geometryRep.localOffset}' on line 131, col 12
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localOffset}')) # from line 131, col 12.
+                        write(u''' < (''')
+                        _v = VFFSL(SL,"fieldRep.globalLattice",True) # u'${fieldRep.globalLattice}' on line 131, col 42
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.globalLattice}')) # from line 131, col 42.
+                        write(u'''+1)/2) {
+  // somewhere near the start of the positive values
+  ''')
+                        _v = VFFSL(SL,"fieldRep.localOffset",True) # u'${fieldRep.localOffset}' on line 133, col 3
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localOffset}')) # from line 133, col 3.
+                        write(u''' = ''')
+                        _v = VFFSL(SL,"geometryRep.localOffset",True) # u'${geometryRep.localOffset}' on line 133, col 29
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localOffset}')) # from line 133, col 29.
+                        write(u''';
+  ''')
+                        _v = VFFSL(SL,"fieldRep.localLattice",True) # u'${fieldRep.localLattice}' on line 134, col 3
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localLattice}')) # from line 134, col 3.
+                        write(u''' = ''')
+                        _v = VFFSL(SL,"geometryRep.localLattice",True) # u'${geometryRep.localLattice}' on line 134, col 30
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localLattice}')) # from line 134, col 30.
+                        write(u''';
+}
+
+if (''')
+                        _v = VFFSL(SL,"geometryRep.localOffset",True) # u'${geometryRep.localOffset}' on line 137, col 5
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localOffset}')) # from line 137, col 5.
+                        write(u''' + ''')
+                        _v = VFFSL(SL,"geometryRep.localLattice",True) # u'${geometryRep.localLattice}' on line 137, col 34
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localLattice}')) # from line 137, col 34.
+                        write(u''' <= ''')
+                        _v = VFFSL(SL,"geometryRep.globalLattice",True) # u'${geometryRep.globalLattice}' on line 137, col 65
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.globalLattice}')) # from line 137, col 65.
+                        write(u''' - ''')
+                        _v = VFFSL(SL,"fieldRep.globalLattice",True) # u'${fieldRep.globalLattice}' on line 137, col 96
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.globalLattice}')) # from line 137, col 96.
+                        write(u"""/2) {
+  // No points due to negative 'k' values.
+} else if (""")
+                        _v = VFFSL(SL,"geometryRep.localOffset",True) # u'${geometryRep.localOffset}' on line 139, col 12
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localOffset}')) # from line 139, col 12.
+                        write(u''' < ''')
+                        _v = VFFSL(SL,"geometryRep.globalLattice",True) # u'${geometryRep.globalLattice}' on line 139, col 41
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.globalLattice}')) # from line 139, col 41.
+                        write(u''' - ''')
+                        _v = VFFSL(SL,"fieldRep.globalLattice",True) # u'${fieldRep.globalLattice}' on line 139, col 72
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.globalLattice}')) # from line 139, col 72.
+                        write(u'''/2) {
+  // the lower edge of the negative values are here
+  if (''')
+                        _v = VFFSL(SL,"fieldRep.localOffset",True) # u'${fieldRep.localOffset}' on line 141, col 7
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localOffset}')) # from line 141, col 7.
+                        write(u''' == -1)
+    ''')
+                        _v = VFFSL(SL,"fieldRep.localOffset",True) # u'${fieldRep.localOffset}' on line 142, col 5
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localOffset}')) # from line 142, col 5.
+                        write(u''' = (''')
+                        _v = VFFSL(SL,"fieldRep.globalLattice",True) # u'${fieldRep.globalLattice}' on line 142, col 32
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.globalLattice}')) # from line 142, col 32.
+                        write(u'''+1)/2;
+  ''')
+                        _v = VFFSL(SL,"fieldRep.localLattice",True) # u'${fieldRep.localLattice}' on line 143, col 3
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localLattice}')) # from line 143, col 3.
+                        write(u''' += ''')
+                        _v = VFFSL(SL,"geometryRep.localLattice",True) # u'${geometryRep.localLattice}' on line 143, col 31
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localLattice}')) # from line 143, col 31.
+                        write(u''' - (''')
+                        _v = VFFSL(SL,"geometryRep.globalLattice",True) # u'${geometryRep.globalLattice}' on line 143, col 62
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.globalLattice}')) # from line 143, col 62.
+                        write(u'''-''')
+                        _v = VFFSL(SL,"fieldRep.globalLattice",True) # u'${fieldRep.globalLattice}' on line 143, col 91
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.globalLattice}')) # from line 143, col 91.
+                        write(u'''/2-''')
+                        _v = VFFSL(SL,"geometryRep.localOffset",True) # u'${geometryRep.localOffset}' on line 143, col 119
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localOffset}')) # from line 143, col 119.
+                        write(u''');
+} else if (''')
+                        _v = VFFSL(SL,"geometryRep.localOffset",True) # u'${geometryRep.localOffset}' on line 144, col 12
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localOffset}')) # from line 144, col 12.
+                        write(u''' + ''')
+                        _v = VFFSL(SL,"geometryRep.localLattice",True) # u'${geometryRep.localLattice}' on line 144, col 41
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localLattice}')) # from line 144, col 41.
+                        write(u''' > ''')
+                        _v = VFFSL(SL,"geometryRep.globalLattice",True) # u'${geometryRep.globalLattice}' on line 144, col 71
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.globalLattice}')) # from line 144, col 71.
+                        write(u''' - ''')
+                        _v = VFFSL(SL,"fieldRep.globalLattice",True) # u'${fieldRep.globalLattice}' on line 144, col 102
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.globalLattice}')) # from line 144, col 102.
+                        write(u'''/2) {
+  // somewhere near the end of the negative values
+  ''')
+                        _v = VFFSL(SL,"fieldRep.localOffset",True) # u'${fieldRep.localOffset}' on line 146, col 3
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localOffset}')) # from line 146, col 3.
+                        write(u''' = ''')
+                        _v = VFFSL(SL,"geometryRep.localOffset",True) # u'${geometryRep.localOffset}' on line 146, col 29
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localOffset}')) # from line 146, col 29.
+                        write(u''' - (''')
+                        _v = VFFSL(SL,"geometryRep.globalLattice",True) # u'${geometryRep.globalLattice}' on line 146, col 59
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.globalLattice}')) # from line 146, col 59.
+                        write(u'''-''')
+                        _v = VFFSL(SL,"fieldRep.globalLattice",True) # u'${fieldRep.globalLattice}' on line 146, col 88
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.globalLattice}')) # from line 146, col 88.
+                        write(u''');
+  ''')
+                        _v = VFFSL(SL,"fieldRep.localLattice",True) # u'${fieldRep.localLattice}' on line 147, col 3
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldRep.localLattice}')) # from line 147, col 3.
+                        write(u''' = ''')
+                        _v = VFFSL(SL,"geometryRep.localLattice",True) # u'${geometryRep.localLattice}' on line 147, col 30
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryRep.localLattice}')) # from line 147, col 30.
+                        write(u''';
+}
+''')
+                    else: # generated from line 149, col 9
+                        assert False
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def setVectorAllocSizes(self, vectors, **KWS):
+
+
+
+        ## CHEETAH: generated from @def setVectorAllocSizes($vectors) at line 158, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''ptrdiff_t _local_alloc_size, _tmp;
+''')
+        for tID, transformation in self.transformations: # generated from line 161, col 3
+            if not transformation.get('distributedTransform', False): # generated from line 162, col 5
+                continue
+            untransformedDimRepBasis, transformedDimRepBasis = transformation['transformPair']
+            for dimNum, dimRep in enumerate(untransformedDimRepBasis): # generated from line 166, col 5
+                write(u'''_sizes[''')
+                _v = VFFSL(SL,"dimNum",True) # u'${dimNum}' on line 167, col 8
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimNum}')) # from line 167, col 8.
+                write(u'''] = ''')
+                _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 167, col 21
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 167, col 21.
+                write(u''';
+''')
+            write(u'''_local_alloc_size = ''')
+            _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 169, col 21
+            if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 169, col 21.
+            write(u'''_mpi_local_size_many_transposed(
+  ''')
+            _v = VFFSL(SL,"len",False)(untransformedDimRepBasis) # u'${len(untransformedDimRepBasis)}' on line 170, col 3
+            if _v is not None: write(_filter(_v, rawExpr=u'${len(untransformedDimRepBasis)}')) # from line 170, col 3.
+            write(u''', _sizes,
+  (ptrdiff_t)''')
+            _v = VFFSL(SL,"transformation",True)['postfixLatticeString'] # u"${transformation['postfixLatticeString']}" on line 171, col 14
+            if _v is not None: write(_filter(_v, rawExpr=u"${transformation['postfixLatticeString']}")) # from line 171, col 14.
+            write(u''',
+  _block_size_''')
+            _v = VFN(VFFSL(SL,"untransformedDimRepBasis",True)[0],"name",True) # u'${untransformedDimRepBasis[0].name}' on line 172, col 15
+            if _v is not None: write(_filter(_v, rawExpr=u'${untransformedDimRepBasis[0].name}')) # from line 172, col 15.
+            write(u''', _block_size_''')
+            _v = VFN(VFFSL(SL,"transformedDimRepBasis",True)[0],"name",True) # u'${transformedDimRepBasis[0].name}' on line 172, col 64
+            if _v is not None: write(_filter(_v, rawExpr=u'${transformedDimRepBasis[0].name}')) # from line 172, col 64.
+            write(u''',
+  MPI_COMM_WORLD,
+  &_tmp, &_tmp, &_tmp, &_tmp /* Local lattices and offsets were obtained above */
+);
+''')
+            for vector in transformation['vectors']: # generated from line 176, col 5
+                _v = VFFSL(SL,"vector.allocSize",True) # u'${vector.allocSize}' on line 177, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.allocSize}')) # from line 177, col 1.
+                write(u''' = MAX(''')
+                _v = VFFSL(SL,"vector.allocSize",True) # u'${vector.allocSize}' on line 177, col 27
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.allocSize}')) # from line 177, col 27.
+                write(u''', (_local_alloc_size''')
+                _v = '+1) / 2' if vector.type == 'complex' and transformation.get('transformType', 'real') == 'real' else ')' # u"${'+1) / 2' if vector.type == 'complex' and transformation.get('transformType', 'real') == 'real' else ')'}" on line 177, col 66
+                if _v is not None: write(_filter(_v, rawExpr=u"${'+1) / 2' if vector.type == 'complex' and transformation.get('transformType', 'real') == 'real' else ')'}")) # from line 177, col 66.
+                write(u''');
+''')
+            write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def transposeTransformFunction(self, transformID, transformDict, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def transposeTransformFunction(transformID, transformDict, function) at line 184, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        runtimePrefix, prefixLattice, postfixLattice, runtimePostfix = transformDict['transformSpecifier']
+        flags = ' | FFTW_MPI_TRANSPOSED_IN | FFTW_MPI_TRANSPOSED_OUT' if transformDict['transposedOrder'] else ''
+        flags += ' | FFTW_DESTROY_INPUT' if transformDict.get('outOfPlace', False) else ''
+        write(u'''// _prefix_lattice should be ''')
+        _v = VFFSL(SL,"prefixLattice",True) # u'${prefixLattice}' on line 189, col 30
+        if _v is not None: write(_filter(_v, rawExpr=u'${prefixLattice}')) # from line 189, col 30.
+        write(u'''
+// _postfix_lattice should be ''')
+        _v = VFFSL(SL,"postfixLattice",True) # u'${postfixLattice}' on line 190, col 31
+        if _v is not None: write(_filter(_v, rawExpr=u'${postfixLattice}')) # from line 190, col 31.
+        write(u'''
+static ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 191, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 191, col 8.
+        write(u'''_plan _fftw_forward_plan = NULL;
+static ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 192, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 192, col 8.
+        write(u'''_plan _fftw_backward_plan = NULL;
+
+if (!_fftw_forward_plan) {
+  _LOG(_SIMULATION_LOG_LEVEL, "Planning for ''')
+        _v = VFFSL(SL,"function.description",True) # u'${function.description}' on line 195, col 45
+        if _v is not None: write(_filter(_v, rawExpr=u'${function.description}')) # from line 195, col 45.
+        write(u'''...");
+''')
+        transformPair = transformDict['transformPair']
+        if transformDict['transposedOrder']: # generated from line 197, col 3
+            #  Reverse the order
+            transformPair = transformPair[::-1]
+        dataOut = '_data_out' if transformDict.get('outOfPlace', False) else '_data_in'
+        write(u'''  
+  _fftw_forward_plan = ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 203, col 24
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 203, col 24.
+        write(u'''_mpi_plan_many_transpose(
+    ''')
+        _v = ', '.join(dr.globalLattice for dr in transformPair[0]) # u"${', '.join(dr.globalLattice for dr in transformPair[0])}" on line 204, col 5
+        if _v is not None: write(_filter(_v, rawExpr=u"${', '.join(dr.globalLattice for dr in transformPair[0])}")) # from line 204, col 5.
+        write(u''',
+    _postfix_lattice, _block_size_''')
+        _v = VFN(VFFSL(SL,"transformPair",True)[0][0],"name",True) # u'${transformPair[0][0].name}' on line 205, col 35
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformPair[0][0].name}')) # from line 205, col 35.
+        write(u''', _block_size_''')
+        _v = VFN(VFFSL(SL,"transformPair",True)[1][0],"name",True) # u'${transformPair[1][0].name}' on line 205, col 76
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformPair[1][0].name}')) # from line 205, col 76.
+        write(u''',
+    reinterpret_cast<real*>(_data_in),
+    reinterpret_cast<real*>(''')
+        _v = VFFSL(SL,"dataOut",True) # u'$dataOut' on line 207, col 29
+        if _v is not None: write(_filter(_v, rawExpr=u'$dataOut')) # from line 207, col 29.
+        write(u'''),
+    MPI_COMM_WORLD, ''')
+        _v = VFFSL(SL,"planType",True) # u'${planType}' on line 208, col 21
+        if _v is not None: write(_filter(_v, rawExpr=u'${planType}')) # from line 208, col 21.
+        _v = VFFSL(SL,"flags",True) # u'${flags}' on line 208, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'${flags}')) # from line 208, col 32.
+        write(u'''
+  );
+  
+  if (!_fftw_forward_plan)
+    _LOG(_ERROR_LOG_LEVEL, "(%s: %i) Unable to create forward mpi transform plan.\\n", __FILE__, __LINE__);
+  
+  _fftw_backward_plan = ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 214, col 25
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 214, col 25.
+        write(u'''_mpi_plan_many_transpose(
+    ''')
+        _v = ', '.join(dr.globalLattice for dr in transformPair[1]) # u"${', '.join(dr.globalLattice for dr in transformPair[1])}" on line 215, col 5
+        if _v is not None: write(_filter(_v, rawExpr=u"${', '.join(dr.globalLattice for dr in transformPair[1])}")) # from line 215, col 5.
+        write(u''',
+    _postfix_lattice, _block_size_''')
+        _v = VFN(VFFSL(SL,"transformPair",True)[1][0],"name",True) # u'${transformPair[1][0].name}' on line 216, col 35
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformPair[1][0].name}')) # from line 216, col 35.
+        write(u''', _block_size_''')
+        _v = VFN(VFFSL(SL,"transformPair",True)[0][0],"name",True) # u'${transformPair[0][0].name}' on line 216, col 76
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformPair[0][0].name}')) # from line 216, col 76.
+        write(u''',
+    reinterpret_cast<real*>(_data_in),
+    reinterpret_cast<real*>(''')
+        _v = VFFSL(SL,"dataOut",True) # u'$dataOut' on line 218, col 29
+        if _v is not None: write(_filter(_v, rawExpr=u'$dataOut')) # from line 218, col 29.
+        write(u'''),
+    MPI_COMM_WORLD, ''')
+        _v = VFFSL(SL,"planType",True) # u'${planType}' on line 219, col 21
+        if _v is not None: write(_filter(_v, rawExpr=u'${planType}')) # from line 219, col 21.
+        _v = VFFSL(SL,"flags",True) # u'${flags}' on line 219, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'${flags}')) # from line 219, col 32.
+        write(u'''
+  );
+  
+  if (!_fftw_backward_plan)
+    _LOG(_ERROR_LOG_LEVEL, "(%s: %i) Unable to create backward mpi transform plan.\\n", __FILE__, __LINE__);
+  
+  // Save wisdom
+  #if CFG_OSAPI == CFG_OSAPI_POSIX
+  ''')
+        _v = VFFSL(SL,"saveWisdom",True) # u'${saveWisdom, autoIndent=True}' on line 227, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${saveWisdom, autoIndent=True}')) # from line 227, col 3.
+        write(u'''  #endif // POSIX
+  
+  _LOG(_SIMULATION_LOG_LEVEL, " done.\\n");
+}
+
+if (_forward) {
+  ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 234, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 234, col 3.
+        write(u'''_execute_r2r(
+    _fftw_forward_plan,
+    reinterpret_cast<real*>(_data_in),
+    reinterpret_cast<real*>(''')
+        _v = VFFSL(SL,"dataOut",True) # u'${dataOut}' on line 237, col 29
+        if _v is not None: write(_filter(_v, rawExpr=u'${dataOut}')) # from line 237, col 29.
+        write(u''')
+  );
+} else {
+  ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 240, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 240, col 3.
+        write(u'''_execute_r2r(
+    _fftw_backward_plan,
+    reinterpret_cast<real*>(_data_in),
+    reinterpret_cast<real*>(''')
+        _v = VFFSL(SL,"dataOut",True) # u'${dataOut}' on line 243, col 29
+        if _v is not None: write(_filter(_v, rawExpr=u'${dataOut}')) # from line 243, col 29.
+        write(u''')
+  );
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def distributedTransformFunction(self, transformID, transformDict, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def distributedTransformFunction(transformID, transformDict, function) at line 249, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        runtimePrefix, prefixLattice, postfixLattice, runtimePostfix = transformDict['transformSpecifier']
+        write(u'''// _prefix_lattice should be ''')
+        _v = VFFSL(SL,"prefixLattice",True) # u'${prefixLattice}' on line 252, col 30
+        if _v is not None: write(_filter(_v, rawExpr=u'${prefixLattice}')) # from line 252, col 30.
+        _v = ''.join([' * ' + runtimeLattice for runtimeLattice in runtimePrefix]) # u"${''.join([' * ' + runtimeLattice for runtimeLattice in runtimePrefix])}" on line 252, col 46
+        if _v is not None: write(_filter(_v, rawExpr=u"${''.join([' * ' + runtimeLattice for runtimeLattice in runtimePrefix])}")) # from line 252, col 46.
+        write(u'''
+// _postfix_lattice should be ''')
+        _v = VFFSL(SL,"postfixLattice",True) # u'${postfixLattice}' on line 253, col 31
+        if _v is not None: write(_filter(_v, rawExpr=u'${postfixLattice}')) # from line 253, col 31.
+        _v = ''.join([' * ' + runtimeLattice for runtimeLattice in runtimePostfix]) # u"${''.join([' * ' + runtimeLattice for runtimeLattice in runtimePostfix])}" on line 253, col 48
+        if _v is not None: write(_filter(_v, rawExpr=u"${''.join([' * ' + runtimeLattice for runtimeLattice in runtimePostfix])}")) # from line 253, col 48.
+        write(u'''
+static ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 254, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 254, col 8.
+        write(u'''_plan _fftw_forward_plan = NULL;
+static ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 255, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 255, col 8.
+        write(u'''_plan _fftw_backward_plan = NULL;
+
+if (!_fftw_forward_plan) {
+  _LOG(_SIMULATION_LOG_LEVEL, "Planning for ''')
+        _v = VFFSL(SL,"function.description",True) # u'${function.description}' on line 258, col 45
+        if _v is not None: write(_filter(_v, rawExpr=u'${function.description}')) # from line 258, col 45.
+        write(u'''...");
+''')
+        transformPair = transformDict['transformPair']
+        dimensionsBeingTransformed = len(transformPair[0])
+        transformType = transformDict['transformType']
+        dataOut = '_data_out' if transformDict.get('outOfPlace', False) else '_data_in'
+        flags = ' | FFTW_DESTROY_INPUT' if transformDict.get('outOfPlace', False) else ''
+        write(u'''  ptrdiff_t _transform_sizes[''')
+        _v = VFFSL(SL,"dimensionsBeingTransformed",True) # u'${dimensionsBeingTransformed}' on line 264, col 30
+        if _v is not None: write(_filter(_v, rawExpr=u'${dimensionsBeingTransformed}')) # from line 264, col 30.
+        write(u'''];
+''')
+        if transformType == 'real': # generated from line 265, col 3
+            write(u'''  ''')
+            _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 266, col 3
+            if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 266, col 3.
+            write(u'''_r2r_kind _r2r_kinds[''')
+            _v = VFFSL(SL,"dimensionsBeingTransformed",True) # u'${dimensionsBeingTransformed}' on line 266, col 37
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimensionsBeingTransformed}')) # from line 266, col 37.
+            write(u'''];
+''')
+        write(u'''  
+  int _transform_sizes_index = 0;
+  
+''')
+        # 
+        for dimID, dimRep in enumerate(transformPair[0]): # generated from line 272, col 3
+            write(u'''  _transform_sizes[_transform_sizes_index++] = ''')
+            _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 273, col 48
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 273, col 48.
+            write(u''';
+''')
+        write(u'''  
+''')
+        if transformType == 'complex': # generated from line 276, col 3
+            guruPlanFunction = self.createGuruMPIDFTPlanInDirection
+        else: # generated from line 278, col 3
+            guruPlanFunction = self.createGuruMPIR2RPlanInDirection
+        # 
+        write(u'''  ''')
+        _v = VFFSL(SL,"guruPlanFunction",False)(
+      transformDict, 'forward', dataOut,
+      '_block_size_' + transformPair[0][0].name, '_block_size_' + transformPair[1][0].name, 'FFTW_MPI_TRANSPOSED_OUT', flags
+    )
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${guruPlanFunction(\n      transformDict, 'forward', dataOut,\n      '_block_size_' + transformPair[0][0].name, '_block_size_' + transformPair[1][0].name, 'FFTW_MPI_TRANSPOSED_OUT', flags\n    ), autoIndent=True}")) # from line 282, col 3.
+        write(u'''  ''')
+        _v = VFFSL(SL,"guruPlanFunction",False)(
+      transformDict, 'backward', dataOut,
+      '_block_size_' + transformPair[1][0].name, '_block_size_' + transformPair[0][0].name, 'FFTW_MPI_TRANSPOSED_IN', flags
+    )
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${guruPlanFunction(\n      transformDict, 'backward', dataOut,\n      '_block_size_' + transformPair[1][0].name, '_block_size_' + transformPair[0][0].name, 'FFTW_MPI_TRANSPOSED_IN', flags\n    ), autoIndent=True}")) # from line 286, col 3.
+        write(u'''  
+  // Save wisdom
+  #if CFG_OSAPI == CFG_OSAPI_POSIX
+  ''')
+        _v = VFFSL(SL,"saveWisdom",True) # u'${saveWisdom, autoIndent=True}' on line 293, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${saveWisdom, autoIndent=True}')) # from line 293, col 3.
+        write(u'''  #endif // POSIX
+  
+  _LOG(_SIMULATION_LOG_LEVEL, " done.\\n");
+}
+
+if (_forward) {
+  ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 300, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 300, col 3.
+        write(u'''_execute_r2r(
+    _fftw_forward_plan,
+    reinterpret_cast<real*>(_data_in),
+    reinterpret_cast<real*>(''')
+        _v = VFFSL(SL,"dataOut",True) # u'${dataOut}' on line 303, col 29
+        if _v is not None: write(_filter(_v, rawExpr=u'${dataOut}')) # from line 303, col 29.
+        write(u''')
+  );
+} else {
+  ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 306, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 306, col 3.
+        write(u'''_execute_r2r(
+    _fftw_backward_plan,
+    reinterpret_cast<real*>(_data_in),
+    reinterpret_cast<real*>(''')
+        _v = VFFSL(SL,"dataOut",True) # u'${dataOut}' on line 309, col 29
+        if _v is not None: write(_filter(_v, rawExpr=u'${dataOut}')) # from line 309, col 29.
+        write(u''')
+  );
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def createGuruMPIDFTPlanInDirection(self, transformDict, direction, dataOut, inBlockSize, outBlockSize, transposedState, flags, **KWS):
+
+
+
+        ## CHEETAH: generated from @def createGuruMPIDFTPlanInDirection($transformDict, $direction, $dataOut, $inBlockSize, $outBlockSize, $transposedState, $flags) at line 315, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''_fftw_''')
+        _v = VFFSL(SL,"direction",True) # u'${direction}' on line 317, col 7
+        if _v is not None: write(_filter(_v, rawExpr=u'${direction}')) # from line 317, col 7.
+        write(u'''_plan = ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 317, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 317, col 27.
+        write(u'''_mpi_plan_many_dft(
+  _transform_sizes_index, _transform_sizes, _postfix_lattice,
+  ''')
+        _v = VFFSL(SL,"inBlockSize",True) # u'${inBlockSize}' on line 319, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${inBlockSize}')) # from line 319, col 3.
+        write(u''', ''')
+        _v = VFFSL(SL,"outBlockSize",True) # u'${outBlockSize}' on line 319, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${outBlockSize}')) # from line 319, col 19.
+        write(u''',
+  reinterpret_cast<''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 320, col 20
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 320, col 20.
+        write(u'''_complex*>(_data_in),
+  reinterpret_cast<''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 321, col 20
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 321, col 20.
+        write(u'''_complex*>(''')
+        _v = VFFSL(SL,"dataOut",True) # u'${dataOut}' on line 321, col 44
+        if _v is not None: write(_filter(_v, rawExpr=u'${dataOut}')) # from line 321, col 44.
+        write(u'''),
+  MPI_COMM_WORLD, FFTW_''')
+        _v = VFN(VFFSL(SL,"direction",True),"upper",False)() # u'${direction.upper()}' on line 322, col 24
+        if _v is not None: write(_filter(_v, rawExpr=u'${direction.upper()}')) # from line 322, col 24.
+        write(u''', ''')
+        _v = VFFSL(SL,"planType",True) # u'${planType}' on line 322, col 46
+        if _v is not None: write(_filter(_v, rawExpr=u'${planType}')) # from line 322, col 46.
+        write(u''' | ''')
+        _v = VFFSL(SL,"transposedState",True) # u'${transposedState}' on line 322, col 60
+        if _v is not None: write(_filter(_v, rawExpr=u'${transposedState}')) # from line 322, col 60.
+        _v = VFFSL(SL,"flags",True) # u'${flags}' on line 322, col 78
+        if _v is not None: write(_filter(_v, rawExpr=u'${flags}')) # from line 322, col 78.
+        write(u'''
+);
+if (!_fftw_''')
+        _v = VFFSL(SL,"direction",True) # u'${direction}' on line 324, col 12
+        if _v is not None: write(_filter(_v, rawExpr=u'${direction}')) # from line 324, col 12.
+        write(u'''_plan)
+  _LOG(_ERROR_LOG_LEVEL, "(%s: %i) Unable to create ''')
+        _v = VFFSL(SL,"direction",True) # u'${direction}' on line 325, col 53
+        if _v is not None: write(_filter(_v, rawExpr=u'${direction}')) # from line 325, col 53.
+        write(u''' mpi dft plan.\\n", __FILE__, __LINE__);
+
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def createGuruMPIR2RPlanInDirection(self, transformDict, direction, dataOut, inBlockSize, outBlockSize, transposedState, flags, **KWS):
+
+
+
+        ## CHEETAH: generated from @def createGuruMPIR2RPlanInDirection($transformDict, $direction, $dataOut, $inBlockSize, $outBlockSize, $transposedState, $flags) at line 330, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        for idx, dimRep in enumerate(transformDict['transformPair'][0]): # generated from line 332, col 3
+            write(u'''_r2r_kinds[''')
+            _v = VFFSL(SL,"idx",True) # u'${idx}' on line 333, col 12
+            if _v is not None: write(_filter(_v, rawExpr=u'${idx}')) # from line 333, col 12.
+            write(u'''] = ''')
+            _v = VFFSL(SL,"r2rKindForDimensionAndDirection",False)(dimRep.name, direction) # u'${r2rKindForDimensionAndDirection(dimRep.name, direction)}' on line 333, col 22
+            if _v is not None: write(_filter(_v, rawExpr=u'${r2rKindForDimensionAndDirection(dimRep.name, direction)}')) # from line 333, col 22.
+            write(u''';
+''')
+        write(u'''
+_fftw_''')
+        _v = VFFSL(SL,"direction",True) # u'${direction}' on line 336, col 7
+        if _v is not None: write(_filter(_v, rawExpr=u'${direction}')) # from line 336, col 7.
+        write(u'''_plan = ''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 336, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 336, col 27.
+        write(u'''_mpi_plan_many_r2r(
+  _transform_sizes_index, _transform_sizes, _postfix_lattice,
+  ''')
+        _v = VFFSL(SL,"inBlockSize",True) # u'${inBlockSize}' on line 338, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${inBlockSize}')) # from line 338, col 3.
+        write(u''', ''')
+        _v = VFFSL(SL,"outBlockSize",True) # u'${outBlockSize}' on line 338, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${outBlockSize}')) # from line 338, col 19.
+        write(u''',
+  reinterpret_cast<real*>(_data_in),
+  reinterpret_cast<real*>(''')
+        _v = VFFSL(SL,"dataOut",True) # u'${dataOut}' on line 340, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'${dataOut}')) # from line 340, col 27.
+        write(u'''),
+  MPI_COMM_WORLD, _r2r_kinds, ''')
+        _v = VFFSL(SL,"planType",True) # u'${planType}' on line 341, col 31
+        if _v is not None: write(_filter(_v, rawExpr=u'${planType}')) # from line 341, col 31.
+        write(u''' | ''')
+        _v = VFFSL(SL,"transposedState",True) # u'${transposedState}' on line 341, col 45
+        if _v is not None: write(_filter(_v, rawExpr=u'${transposedState}')) # from line 341, col 45.
+        _v = VFFSL(SL,"flags",True) # u'${flags}' on line 341, col 63
+        if _v is not None: write(_filter(_v, rawExpr=u'${flags}')) # from line 341, col 63.
+        write(u'''
+);
+
+if (!_fftw_''')
+        _v = VFFSL(SL,"direction",True) # u'${direction}' on line 344, col 12
+        if _v is not None: write(_filter(_v, rawExpr=u'${direction}')) # from line 344, col 12.
+        write(u'''_plan)
+  _LOG(_ERROR_LOG_LEVEL, "(%s: %i) Unable to create ''')
+        _v = VFFSL(SL,"direction",True) # u'${direction}' on line 345, col 53
+        if _v is not None: write(_filter(_v, rawExpr=u'${direction}')) # from line 345, col 53.
+        write(u''' mpi r2r plan.\\n", __FILE__, __LINE__);
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def loadWisdom(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def loadWisdom at line 350, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(FourierTransformFFTW3MPI, self).loadWisdom()
+        if _v is not None: write(_filter(_v))
+        # 
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 354, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 354, col 1.
+        write(u'''_mpi_broadcast_wisdom(MPI_COMM_WORLD);
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def saveWisdom(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def saveWisdom at line 358, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 360, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 360, col 1.
+        write(u'''_mpi_gather_wisdom(MPI_COMM_WORLD);
+''')
+        # 
+        _v = super(FourierTransformFFTW3MPI, self).saveWisdom()
+        if _v is not None: write(_filter(_v))
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # FourierTransformFFTW3MPI.tmpl
+        # 
+        # Created by Graham Dennis on 2008-06-06.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    fftwSuffix = 'mpi'
+
+    _mainCheetahMethod_for_FourierTransformFFTW3MPI= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(FourierTransformFFTW3MPI, '_initCheetahAttributes'):
+    templateAPIClass = getattr(FourierTransformFFTW3MPI, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(FourierTransformFFTW3MPI)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=FourierTransformFFTW3MPI()).run()
+
+
diff --git a/xpdeint/Features/Transforms/FourierTransformFFTW3MPI.tmpl b/xpdeint/Features/Transforms/FourierTransformFFTW3MPI.tmpl
new file mode 100644
index 0000000..d600c64
--- /dev/null
+++ b/xpdeint/Features/Transforms/FourierTransformFFTW3MPI.tmpl
@@ -0,0 +1,364 @@
+@*
+FourierTransformFFTW3MPI.tmpl
+
+Created by Graham Dennis on 2008-06-06.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features.Transforms._FourierTransformFFTW3MPI
+ at import operator
+ at from xpdeint.Geometry.UniformDimensionRepresentation import UniformDimensionRepresentation
+ at from xpdeint.Geometry.SplitUniformDimensionRepresentation import SplitUniformDimensionRepresentation
+
+ at from xpdeint.Utilities import permutations
+
+ at def description: FFTW3 with MPI
+ at attr $fftwSuffix = 'mpi'
+
+ at def includes
+  @#
+  @super
+  @#
+#include <fftw3-mpi.h>
+ at end def
+
+ at def globals
+  @#
+  @super
+  @#
+  @for dimRep in [dimRep for dim in self.mpiDimensions for dimRep in dim.representations if dimRep.hasLocalOffset]
+ptrdiff_t _block_size_${dimRep.name} = FFTW_MPI_DEFAULT_BLOCK;
+  @end for
+  @#
+ at end def
+
+ at def setLocalLatticeAndOffsetVariables
+  @#
+// First work out the local lattice and offset for the geometry
+ptrdiff_t _sizes[${len($geometry.dimensions)}];
+${fftwPrefix}_mpi_init();
+  @for firstMPIDimRep, secondMPIDimRep in permutations(*[dim.representations for dim in self.mpiDimensions]):
+    @if not (firstMPIDimRep.hasLocalOffset and secondMPIDimRep.hasLocalOffset)
+      @continue
+    @end if
+_sizes[0] = ${firstMPIDimRep.globalLattice}; _sizes[1] = ${secondMPIDimRep.globalLattice};
+${fftwPrefix}_mpi_local_size_many_transposed(
+  2, _sizes, 1, _block_size_${firstMPIDimRep.name}, _block_size_${secondMPIDimRep.name}, MPI_COMM_WORLD,
+  &${firstMPIDimRep.localLattice}, &${firstMPIDimRep.localOffset},
+  &${secondMPIDimRep.localLattice}, &${secondMPIDimRep.localOffset}
+);
+
+if (_rank == 0) {
+  _block_size_${firstMPIDimRep.name} = ${firstMPIDimRep.localLattice};
+  _block_size_${secondMPIDimRep.name} = ${secondMPIDimRep.localLattice};
+}
+MPI_Bcast(&_block_size_${firstMPIDimRep.name}, sizeof(ptrdiff_t), MPI_BYTE, 0, MPI_COMM_WORLD);
+MPI_Bcast(&_block_size_${secondMPIDimRep.name}, sizeof(ptrdiff_t), MPI_BYTE, 0, MPI_COMM_WORLD);
+
+  @end for
+  @#
+  @set firstMPIDim, secondMPIDim = $mpiDimensions
+  @for $field in $fields
+    @if field.name == 'geometry' or not field.isDistributed
+      @continue
+    @end if
+    @#
+    @# Set the local_lattice and local_offset variables based on the
+    @# values for the geometry's version of these
+    @set $fieldMPIDim1 = field.dimensionWithName(firstMPIDim.name)
+    @set $fieldMPIDim2 = field.dimensionWithName(secondMPIDim.name)
+    @for fieldDim, geometryDim in [(fieldMPIDim1, firstMPIDim), (fieldMPIDim2, secondMPIDim)]
+      @for fieldRep, geometryRep in zip(fieldDim.representations, geometryDim.representations)
+        @if (not fieldRep) or (not fieldRep.hasLocalOffset) or (not fieldRep.parent is fieldDim)
+          @continue
+        @end if
+// Set the local lattice and offset variables for the '${field.name}' field
+        @if fieldRep == geometryRep
+${fieldRep.localLattice} = ${geometryRep.localLattice};
+${fieldRep.localOffset} = ${geometryRep.localOffset};
+        @elif fieldRep.reductionMethod == fieldRep.ReductionMethod.fixedRange
+          @# In this case we are in 'x' space and are subdividing a distributed dimension
+          @# fixedRange reduction method means we take every nth point.
+ptrdiff_t _${field.name}_${fieldRep.name}_skip_size = ${geometryRep.globalLattice}/${fieldRep.globalLattice};
+if (_rank == 0) {
+  ${fieldRep.localOffset}  = 0;
+  ${fieldRep.localLattice} = (${geometryRep.localLattice}-1)/_${field.name}_${fieldRep.name}_skip_size + 1;
+} else {
+  ${fieldRep.localOffset}  = (${geometryRep.localOffset}-1)/_${field.name}_${fieldRep.name}_skip_size + 1;
+  ${fieldRep.localLattice} = (${geometryRep.localOffset} + ${geometryRep.localLattice} - 1)/_${field.name}_${fieldRep.name}_skip_size
+                             + 1 - ${fieldRep.localOffset};
+}
+        @elif isinstance(fieldRep, UniformDimensionRepresentation)
+          @# In this case, we are in 'k' space and may be subdividing a UniformDimensionRepresentation (dct/dst)
+          @# Note that this is a fixedStep reduction method
+if (${geometryRep.localOffset} >= ${fieldRep.globalLattice}) {
+  // No points here
+  ${fieldRep.localOffset} = 0;
+  ${fieldRep.localLattice} = 0;
+} else if (${geometryRep.localOffset} + ${geometryRep.localLattice} > ${fieldRep.globalLattice}){
+  // The upper edge is here
+  ${fieldRep.localOffset} = ${geometryRep.localOffset};
+  ${fieldRep.localLattice} = ${fieldRep.globalLattice} - ${geometryRep.localOffset};
+} else {
+  // somewhere near the start
+  ${fieldRep.localOffset} = ${geometryRep.localOffset};
+  ${fieldRep.localLattice} = ${geometryRep.localLattice};
+}
+        @elif isinstance(fieldRep, SplitUniformDimensionRepresentation)
+          @# In this case, we are in 'k' space and may be subdividing a SplitUniformDimensionRepresentation (dft)
+          @# Note that this is a fixedStep reduction method
+${fieldRep.localOffset} = -1;
+if (${geometryRep.localOffset} >= (${fieldRep.globalLattice}+1)/2) {
+  // No points due to positive 'k' values.
+} else if (${geometryRep.localOffset} + ${geometryRep.localLattice} > (${fieldRep.globalLattice}+1)/2) {
+  // the upper edge of the positive values are here
+  ${fieldRep.localOffset} = ${geometryRep.localOffset};
+  ${fieldRep.localLattice} = (${fieldRep.globalLattice}+1)/2 - ${geometryRep.localOffset};
+} else if (${geometryRep.localOffset} < (${fieldRep.globalLattice}+1)/2) {
+  // somewhere near the start of the positive values
+  ${fieldRep.localOffset} = ${geometryRep.localOffset};
+  ${fieldRep.localLattice} = ${geometryRep.localLattice};
+}
+
+if (${geometryRep.localOffset} + ${geometryRep.localLattice} <= ${geometryRep.globalLattice} - ${fieldRep.globalLattice}/2) {
+  // No points due to negative 'k' values.
+} else if (${geometryRep.localOffset} < ${geometryRep.globalLattice} - ${fieldRep.globalLattice}/2) {
+  // the lower edge of the negative values are here
+  if (${fieldRep.localOffset} == -1)
+    ${fieldRep.localOffset} = (${fieldRep.globalLattice}+1)/2;
+  ${fieldRep.localLattice} += ${geometryRep.localLattice} - (${geometryRep.globalLattice}-${fieldRep.globalLattice}/2-${geometryRep.localOffset});
+} else if (${geometryRep.localOffset} + ${geometryRep.localLattice} > ${geometryRep.globalLattice} - ${fieldRep.globalLattice}/2) {
+  // somewhere near the end of the negative values
+  ${fieldRep.localOffset} = ${geometryRep.localOffset} - (${geometryRep.globalLattice}-${fieldRep.globalLattice});
+  ${fieldRep.localLattice} = ${geometryRep.localLattice};
+}
+        @else
+          @assert False
+        @end if
+      @end for
+    @end for
+  @end for
+  @#
+ at end def
+
+ at def setVectorAllocSizes($vectors)
+  @#
+ptrdiff_t _local_alloc_size, _tmp;
+  @for tID, transformation in self.transformations
+    @if not transformation.get('distributedTransform', False)
+      @continue
+    @end if
+    @set untransformedDimRepBasis, transformedDimRepBasis = transformation['transformPair']
+    @for dimNum, dimRep in enumerate(untransformedDimRepBasis)
+_sizes[${dimNum}] = ${dimRep.globalLattice};
+    @end for
+_local_alloc_size = ${fftwPrefix}_mpi_local_size_many_transposed(
+  ${len(untransformedDimRepBasis)}, _sizes,
+  (ptrdiff_t)${transformation['postfixLatticeString']},
+  _block_size_${untransformedDimRepBasis[0].name}, _block_size_${transformedDimRepBasis[0].name},
+  MPI_COMM_WORLD,
+  &_tmp, &_tmp, &_tmp, &_tmp /* Local lattices and offsets were obtained above */
+);
+    @for vector in transformation['vectors']
+${vector.allocSize} = MAX(${vector.allocSize}, (_local_alloc_size${'+1) / 2' if vector.type == 'complex' and transformation.get('transformType', 'real') == 'real' else ')'});
+    @end for
+
+  @end for
+  @#
+ at end def
+
+ at def transposeTransformFunction(transformID, transformDict, function)
+  @#
+  @set runtimePrefix, prefixLattice, postfixLattice, runtimePostfix = transformDict['transformSpecifier']
+  @set flags = ' | FFTW_MPI_TRANSPOSED_IN | FFTW_MPI_TRANSPOSED_OUT' if transformDict['transposedOrder'] else ''
+  @set flags += ' | FFTW_DESTROY_INPUT' if transformDict.get('outOfPlace', False) else ''
+// _prefix_lattice should be ${prefixLattice}
+// _postfix_lattice should be ${postfixLattice}
+static ${fftwPrefix}_plan _fftw_forward_plan = NULL;
+static ${fftwPrefix}_plan _fftw_backward_plan = NULL;
+
+if (!_fftw_forward_plan) {
+  _LOG(_SIMULATION_LOG_LEVEL, "Planning for ${function.description}...");
+  @set $transformPair = transformDict['transformPair']
+  @if transformDict['transposedOrder']
+    @# Reverse the order
+    @silent transformPair = transformPair[::-1]
+  @end if
+  @set $dataOut = '_data_out' if transformDict.get('outOfPlace', False) else '_data_in'
+  
+  _fftw_forward_plan = ${fftwPrefix}_mpi_plan_many_transpose(
+    ${', '.join(dr.globalLattice for dr in transformPair[0])},
+    _postfix_lattice, _block_size_${transformPair[0][0].name}, _block_size_${transformPair[1][0].name},
+    reinterpret_cast<real*>(_data_in),
+    reinterpret_cast<real*>($dataOut),
+    MPI_COMM_WORLD, ${planType}${flags}
+  );
+  
+  if (!_fftw_forward_plan)
+    _LOG(_ERROR_LOG_LEVEL, "(%s: %i) Unable to create forward mpi transform plan.\n", __FILE__, __LINE__);
+  
+  _fftw_backward_plan = ${fftwPrefix}_mpi_plan_many_transpose(
+    ${', '.join(dr.globalLattice for dr in transformPair[1])},
+    _postfix_lattice, _block_size_${transformPair[1][0].name}, _block_size_${transformPair[0][0].name},
+    reinterpret_cast<real*>(_data_in),
+    reinterpret_cast<real*>($dataOut),
+    MPI_COMM_WORLD, ${planType}${flags}
+  );
+  
+  if (!_fftw_backward_plan)
+    _LOG(_ERROR_LOG_LEVEL, "(%s: %i) Unable to create backward mpi transform plan.\n", __FILE__, __LINE__);
+  
+  // Save wisdom
+  #if CFG_OSAPI == CFG_OSAPI_POSIX
+  ${saveWisdom, autoIndent=True}@slurp
+  #endif // POSIX
+  
+  _LOG(_SIMULATION_LOG_LEVEL, " done.\n");
+}
+
+if (_forward) {
+  ${fftwPrefix}_execute_r2r(
+    _fftw_forward_plan,
+    reinterpret_cast<real*>(_data_in),
+    reinterpret_cast<real*>(${dataOut})
+  );
+} else {
+  ${fftwPrefix}_execute_r2r(
+    _fftw_backward_plan,
+    reinterpret_cast<real*>(_data_in),
+    reinterpret_cast<real*>(${dataOut})
+  );
+}
+  @#
+ at end def
+
+ at def distributedTransformFunction(transformID, transformDict, function)
+  @#
+  @set runtimePrefix, prefixLattice, postfixLattice, runtimePostfix = transformDict['transformSpecifier']
+// _prefix_lattice should be ${prefixLattice}${''.join([' * ' + runtimeLattice for runtimeLattice in runtimePrefix])}
+// _postfix_lattice should be ${postfixLattice}${''.join([' * ' + runtimeLattice for runtimeLattice in runtimePostfix])}
+static ${fftwPrefix}_plan _fftw_forward_plan = NULL;
+static ${fftwPrefix}_plan _fftw_backward_plan = NULL;
+
+if (!_fftw_forward_plan) {
+  _LOG(_SIMULATION_LOG_LEVEL, "Planning for ${function.description}...");
+  @set $transformPair = transformDict['transformPair']
+  @set $dimensionsBeingTransformed = len(transformPair[0])
+  @set $transformType = transformDict['transformType']
+  @set $dataOut = '_data_out' if transformDict.get('outOfPlace', False) else '_data_in'
+  @set $flags = ' | FFTW_DESTROY_INPUT' if transformDict.get('outOfPlace', False) else ''
+  ptrdiff_t _transform_sizes[${dimensionsBeingTransformed}];
+  @if transformType == 'real'
+  ${fftwPrefix}_r2r_kind _r2r_kinds[${dimensionsBeingTransformed}];
+  @end if
+  
+  int _transform_sizes_index = 0;
+  
+  @#
+  @for dimID, dimRep in enumerate(transformPair[0])
+  _transform_sizes[_transform_sizes_index++] = ${dimRep.globalLattice};
+  @end for
+  
+  @if transformType == 'complex'
+    @set $guruPlanFunction = self.createGuruMPIDFTPlanInDirection
+  @else
+    @set $guruPlanFunction = self.createGuruMPIR2RPlanInDirection
+  @end if
+  @#
+  ${guruPlanFunction(
+      transformDict, 'forward', dataOut,
+      '_block_size_' + transformPair[0][0].name, '_block_size_' + transformPair[1][0].name, 'FFTW_MPI_TRANSPOSED_OUT', flags
+    ), autoIndent=True}@slurp
+  ${guruPlanFunction(
+      transformDict, 'backward', dataOut,
+      '_block_size_' + transformPair[1][0].name, '_block_size_' + transformPair[0][0].name, 'FFTW_MPI_TRANSPOSED_IN', flags
+    ), autoIndent=True}@slurp
+  
+  // Save wisdom
+  #if CFG_OSAPI == CFG_OSAPI_POSIX
+  ${saveWisdom, autoIndent=True}@slurp
+  #endif // POSIX
+  
+  _LOG(_SIMULATION_LOG_LEVEL, " done.\n");
+}
+
+if (_forward) {
+  ${fftwPrefix}_execute_r2r(
+    _fftw_forward_plan,
+    reinterpret_cast<real*>(_data_in),
+    reinterpret_cast<real*>(${dataOut})
+  );
+} else {
+  ${fftwPrefix}_execute_r2r(
+    _fftw_backward_plan,
+    reinterpret_cast<real*>(_data_in),
+    reinterpret_cast<real*>(${dataOut})
+  );
+}
+  @#
+ at end def
+
+ at def createGuruMPIDFTPlanInDirection($transformDict, $direction, $dataOut, $inBlockSize, $outBlockSize, $transposedState, $flags)
+  @#
+_fftw_${direction}_plan = ${fftwPrefix}_mpi_plan_many_dft(
+  _transform_sizes_index, _transform_sizes, _postfix_lattice,
+  ${inBlockSize}, ${outBlockSize},
+  reinterpret_cast<${fftwPrefix}_complex*>(_data_in),
+  reinterpret_cast<${fftwPrefix}_complex*>(${dataOut}),
+  MPI_COMM_WORLD, FFTW_${direction.upper()}, ${planType} | ${transposedState}${flags}
+);
+if (!_fftw_${direction}_plan)
+  _LOG(_ERROR_LOG_LEVEL, "(%s: %i) Unable to create ${direction} mpi dft plan.\n", __FILE__, __LINE__);
+
+  @#
+ at end def
+
+ at def createGuruMPIR2RPlanInDirection($transformDict, $direction, $dataOut, $inBlockSize, $outBlockSize, $transposedState, $flags)
+  @#
+  @for idx, dimRep in enumerate(transformDict['transformPair'][0])
+_r2r_kinds[${idx}] = ${r2rKindForDimensionAndDirection(dimRep.name, direction)};
+  @end for
+
+_fftw_${direction}_plan = ${fftwPrefix}_mpi_plan_many_r2r(
+  _transform_sizes_index, _transform_sizes, _postfix_lattice,
+  ${inBlockSize}, ${outBlockSize},
+  reinterpret_cast<real*>(_data_in),
+  reinterpret_cast<real*>(${dataOut}),
+  MPI_COMM_WORLD, _r2r_kinds, ${planType} | ${transposedState}${flags}
+);
+
+if (!_fftw_${direction}_plan)
+  _LOG(_ERROR_LOG_LEVEL, "(%s: %i) Unable to create ${direction} mpi r2r plan.\n", __FILE__, __LINE__);
+  @#
+ at end def
+
+
+ at def loadWisdom
+  @#
+  @super
+  @#
+${fftwPrefix}_mpi_broadcast_wisdom(MPI_COMM_WORLD);
+  @#
+ at end def
+
+ at def saveWisdom
+  @#
+${fftwPrefix}_mpi_gather_wisdom(MPI_COMM_WORLD);
+  @#
+  @super
+  @#
+ at end def
diff --git a/xpdeint/Features/Transforms/FourierTransformFFTW3Threads.py b/xpdeint/Features/Transforms/FourierTransformFFTW3Threads.py
new file mode 100644
index 0000000..f84ee64
--- /dev/null
+++ b/xpdeint/Features/Transforms/FourierTransformFFTW3Threads.py
@@ -0,0 +1,291 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features.Transforms.FourierTransformFFTW3 import FourierTransformFFTW3
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.469302
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/Transforms/FourierTransformFFTW3Threads.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class FourierTransformFFTW3Threads(FourierTransformFFTW3):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(FourierTransformFFTW3Threads, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: FFTW3 with threads at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''FFTW3 with threads''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def defines(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def defines at line 28, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(FourierTransformFFTW3Threads, self).defines()
+        if _v is not None: write(_filter(_v))
+        write(u'''#define _num_threads ''')
+        _v = VFFSL(SL,"threadCount",True) # u'${threadCount}' on line 31, col 22
+        if _v is not None: write(_filter(_v, rawExpr=u'${threadCount}')) # from line 31, col 22.
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def mainBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def mainBegin($dict) at line 35, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 37, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 37, col 1.
+        write(u'''_init_threads();
+''')
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 38, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 38, col 1.
+        write(u'''_plan_with_nthreads(_num_threads);
+''')
+        _v = super(FourierTransformFFTW3Threads, self).mainBegin(dict)
+        if _v is not None: write(_filter(_v))
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def mainEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def mainEnd($dict) at line 43, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        _v = super(FourierTransformFFTW3Threads, self).mainEnd(dict)
+        if _v is not None: write(_filter(_v))
+        _v = VFFSL(SL,"fftwPrefix",True) # u'${fftwPrefix}' on line 45, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${fftwPrefix}')) # from line 45, col 1.
+        write(u'''_cleanup_threads();
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # FourierTransformFFTW3Threads.tmpl
+        # 
+        # Created by Graham Dennis on 2007-12-23.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+''')
+        #  defines
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    fftwSuffix = 'threads'
+
+    _mainCheetahMethod_for_FourierTransformFFTW3Threads= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(FourierTransformFFTW3Threads, '_initCheetahAttributes'):
+    templateAPIClass = getattr(FourierTransformFFTW3Threads, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(FourierTransformFFTW3Threads)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=FourierTransformFFTW3Threads()).run()
+
+
diff --git a/xpdeint/Features/Transforms/FourierTransformFFTW3Threads.tmpl b/xpdeint/Features/Transforms/FourierTransformFFTW3Threads.tmpl
new file mode 100644
index 0000000..6bf3d9f
--- /dev/null
+++ b/xpdeint/Features/Transforms/FourierTransformFFTW3Threads.tmpl
@@ -0,0 +1,46 @@
+@*
+FourierTransformFFTW3Threads.tmpl
+
+Created by Graham Dennis on 2007-12-23.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features.Transforms.FourierTransformFFTW3
+
+ at def description: FFTW3 with threads
+ at attr $fftwSuffix = 'threads'
+
+@# defines
+ at def defines
+  @#
+  @super
+#define _num_threads ${threadCount}
+  @#
+ at end def
+
+ at def mainBegin($dict)
+  @#
+${fftwPrefix}_init_threads();
+${fftwPrefix}_plan_with_nthreads(_num_threads);
+  @super($dict)
+  @#
+ at end def
+
+ at def mainEnd($dict)
+  @super($dict)
+${fftwPrefix}_cleanup_threads();
+ at end def
diff --git a/xpdeint/Features/Transforms/HermiteGaussEPBasis.py b/xpdeint/Features/Transforms/HermiteGaussEPBasis.py
new file mode 100644
index 0000000..3822912
--- /dev/null
+++ b/xpdeint/Features/Transforms/HermiteGaussEPBasis.py
@@ -0,0 +1,367 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features.Transforms.EPBasis import EPBasis
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.514099
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/Transforms/HermiteGaussEPBasis.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class HermiteGaussEPBasis(EPBasis):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(HermiteGaussEPBasis, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Hermite-Gauss basis (Harmonic oscillator) at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Hermite-Gauss basis (Harmonic oscillator)''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def transformMatricesForwardDimConstantsAtIndex(self, forwardDimRep, backwardDimRep, forwardIndex, **KWS):
+
+
+
+        ## CHEETAH: generated from @def transformMatricesForwardDimConstantsAtIndex($forwardDimRep, $backwardDimRep, $forwardIndex) at line 29, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''real hermiteGaussMinusOne = 0.0;
+real hermiteGaussMinusTwo = 0.0;
+const real _root = _hermite_zeros_''')
+        _v = VFFSL(SL,"forwardDimRep.parent.name",True) # u'${forwardDimRep.parent.name}' on line 32, col 35
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.parent.name}')) # from line 32, col 35.
+        write(u'''[''')
+        _v = VFFSL(SL,"forwardIndex",True) # u'${forwardIndex}' on line 32, col 64
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardIndex}')) # from line 32, col 64.
+        write(u'''] / sqrt(''')
+        _v = VFFSL(SL,"forwardDimRep.fieldCount",True) / 2.0 # u'${forwardDimRep.fieldCount / 2.0}' on line 32, col 88
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.fieldCount / 2.0}')) # from line 32, col 88.
+        write(u''');
+const real expFactor = exp(-0.5 * _root * _root / ''')
+        _v = VFFSL(SL,"backwardDimRep.globalLattice",True) # u'${backwardDimRep.globalLattice}' on line 33, col 51
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardDimRep.globalLattice}')) # from line 33, col 51.
+        write(u''');
+const real expFactor2 = exp(-_root * _root / ''')
+        _v = VFFSL(SL,"backwardDimRep.globalLattice",True) # u'${backwardDimRep.globalLattice}' on line 34, col 46
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardDimRep.globalLattice}')) # from line 34, col 46.
+        write(u''');
+const real normalisation = 1.0/sqrt(''')
+        _v = VFFSL(SL,"forwardDimRep._maximum",True) # u'${forwardDimRep._maximum}' on line 35, col 37
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep._maximum}')) # from line 35, col 37.
+        write(u''');
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def transformMatricesForDimRepsAtIndices(self, forwardDimRep, backwardDimRep, forwardIndex, backwardIndex, **KWS):
+
+
+
+        ## CHEETAH: generated from @def transformMatricesForDimRepsAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex) at line 38, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''real hermiteGauss;
+const real correctionFactor = exp( -0.5 * _root * _root * (''')
+        _v = VFFSL(SL,"backwardDimRep.globalLattice",True) # u'${backwardDimRep.globalLattice}' on line 41, col 60
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardDimRep.globalLattice}')) # from line 41, col 60.
+        write(u''' - ''')
+        _v = VFFSL(SL,"backwardIndex",True) # u'${backwardIndex}' on line 41, col 94
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardIndex}')) # from line 41, col 94.
+        write(u''' - 1) / ''')
+        _v = VFFSL(SL,"backwardDimRep.globalLattice",True) # u'${backwardDimRep.globalLattice}' on line 41, col 118
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardDimRep.globalLattice}')) # from line 41, col 118.
+        write(u''') * normalisation;
+if (''')
+        _v = VFFSL(SL,"backwardIndex",True) # u'${backwardIndex}' on line 42, col 5
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardIndex}')) # from line 42, col 5.
+        write(u''' == 0)
+  hermiteGauss = pow(M_PI, -0.25) * expFactor;
+else if (''')
+        _v = VFFSL(SL,"backwardIndex",True) # u'${backwardIndex}' on line 44, col 10
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardIndex}')) # from line 44, col 10.
+        write(u''' == 1)
+  hermiteGauss = sqrt(2.0) * _root * hermiteGaussMinusOne * expFactor;
+else
+  hermiteGauss = sqrt(2.0/''')
+        _v = VFFSL(SL,"backwardIndex",True) # u'${backwardIndex}' on line 47, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardIndex}')) # from line 47, col 27.
+        write(u''') * _root * hermiteGaussMinusOne * expFactor \\
+                 - sqrt((''')
+        _v = VFFSL(SL,"backwardIndex",True) # u'${backwardIndex}' on line 48, col 26
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardIndex}')) # from line 48, col 26.
+        write(u'''-1.0)/''')
+        _v = VFFSL(SL,"backwardIndex",True) # u'${backwardIndex}' on line 48, col 48
+        if _v is not None: write(_filter(_v, rawExpr=u'${backwardIndex}')) # from line 48, col 48.
+        write(u''') * hermiteGaussMinusTwo * expFactor2;
+
+''')
+        _v = super(HermiteGaussEPBasis, self).transformMatricesForDimRepsAtIndices(forwardDimRep,backwardDimRep,forwardIndex,backwardIndex)
+        if _v is not None: write(_filter(_v))
+        write(u'''
+hermiteGaussMinusTwo = hermiteGaussMinusOne;
+hermiteGaussMinusOne = hermiteGauss;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def forwardMatrixForDimAtIndices(self, forwardDimRep, backwardDimRep, forwardIndex, backwardIndex, **KWS):
+
+
+
+        ## CHEETAH: generated from @def forwardMatrixForDimAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex) at line 57, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''hermiteGauss * correctionFactor * ''')
+        _v = VFFSL(SL,"forwardDimRep.stepSizeArrayName",True) # u'${forwardDimRep.stepSizeArrayName}' on line 58, col 35
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.stepSizeArrayName}')) # from line 58, col 35.
+        write(u'''[''')
+        _v = VFFSL(SL,"forwardIndex",True) # u'$forwardIndex' on line 58, col 70
+        if _v is not None: write(_filter(_v, rawExpr=u'$forwardIndex')) # from line 58, col 70.
+        write(u''']''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def backwardMatrixForDimAtIndices(self, forwardDimRep, backwardDimRep, forwardIndex, backwardIndex, **KWS):
+
+
+
+        ## CHEETAH: generated from @def backwardMatrixForDimAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex) at line 61, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''hermiteGauss * correctionFactor''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # HermiteGaussEPBasis.tmpl
+        # 
+        # Hermite-Gauss basis using the definite parity of the basis functions to remove
+        # half the work.
+        # 
+        # Created by Graham Dennis on 2008-12-28.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_HermiteGaussEPBasis= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(HermiteGaussEPBasis, '_initCheetahAttributes'):
+    templateAPIClass = getattr(HermiteGaussEPBasis, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(HermiteGaussEPBasis)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=HermiteGaussEPBasis()).run()
+
+
diff --git a/xpdeint/Features/Transforms/HermiteGaussEPBasis.tmpl b/xpdeint/Features/Transforms/HermiteGaussEPBasis.tmpl
new file mode 100644
index 0000000..1bedd41
--- /dev/null
+++ b/xpdeint/Features/Transforms/HermiteGaussEPBasis.tmpl
@@ -0,0 +1,64 @@
+@*
+HermiteGaussEPBasis.tmpl
+
+Hermite-Gauss basis using the definite parity of the basis functions to remove
+half the work.
+
+Created by Graham Dennis on 2008-12-28.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features.Transforms.EPBasis
+
+ at def description: Hermite-Gauss basis (Harmonic oscillator)
+
+ at def transformMatricesForwardDimConstantsAtIndex($forwardDimRep, $backwardDimRep, $forwardIndex)
+real hermiteGaussMinusOne = 0.0;
+real hermiteGaussMinusTwo = 0.0;
+const real _root = _hermite_zeros_${forwardDimRep.parent.name}[${forwardIndex}] / sqrt(${forwardDimRep.fieldCount / 2.0});
+const real expFactor = exp(-0.5 * _root * _root / ${backwardDimRep.globalLattice});
+const real expFactor2 = exp(-_root * _root / ${backwardDimRep.globalLattice});
+const real normalisation = 1.0/sqrt(${forwardDimRep._maximum});
+ at end def
+
+ at def transformMatricesForDimRepsAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex)
+  @#
+real hermiteGauss;
+const real correctionFactor = exp( -0.5 * _root * _root * (${backwardDimRep.globalLattice} - ${backwardIndex} - 1) / ${backwardDimRep.globalLattice}) * normalisation;
+if (${backwardIndex} == 0)
+  hermiteGauss = pow(M_PI, -0.25) * expFactor;
+else if (${backwardIndex} == 1)
+  hermiteGauss = sqrt(2.0) * _root * hermiteGaussMinusOne * expFactor;
+else
+  hermiteGauss = sqrt(2.0/${backwardIndex}) * _root * hermiteGaussMinusOne * expFactor \
+                 - sqrt((${backwardIndex}-1.0)/${backwardIndex}) * hermiteGaussMinusTwo * expFactor2;
+
+  @super(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex)
+
+hermiteGaussMinusTwo = hermiteGaussMinusOne;
+hermiteGaussMinusOne = hermiteGauss;
+  @#
+ at end def
+
+ at def forwardMatrixForDimAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex)
+hermiteGauss * correctionFactor * ${forwardDimRep.stepSizeArrayName}[$forwardIndex]@slurp
+ at end def
+
+ at def backwardMatrixForDimAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex)
+hermiteGauss * correctionFactor at slurp
+ at end def
+
diff --git a/xpdeint/Features/Transforms/HermiteGaussFourierEPBasis.py b/xpdeint/Features/Transforms/HermiteGaussFourierEPBasis.py
new file mode 100644
index 0000000..3f49cc4
--- /dev/null
+++ b/xpdeint/Features/Transforms/HermiteGaussFourierEPBasis.py
@@ -0,0 +1,314 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features.Transforms.HermiteGaussEPBasis import HermiteGaussEPBasis
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.542513
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/Transforms/HermiteGaussFourierEPBasis.tmpl'
+__CHEETAH_srcLastModified__ = 'Wed Jul  3 14:24:15 2013'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class HermiteGaussFourierEPBasis(HermiteGaussEPBasis):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(HermiteGaussFourierEPBasis, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Hermite-Gauss Fourier basis (Harmonic oscillator) at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Hermite-Gauss Fourier basis (Harmonic oscillator)''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def transformMatricesForwardDimConstantsAtIndex(self, forwardDimRep, backwardDimRep, forwardIndex, **KWS):
+
+
+
+        ## CHEETAH: generated from @def transformMatricesForwardDimConstantsAtIndex($forwardDimRep, $backwardDimRep, $forwardIndex) at line 31, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        _v = super(HermiteGaussFourierEPBasis, self).transformMatricesForwardDimConstantsAtIndex(forwardDimRep,backwardDimRep,forwardIndex)
+        if _v is not None: write(_filter(_v))
+        write(u'''complex eigenvalue_factor = 1.0;
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def transformMatricesForDimRepsAtIndices(self, forwardDimRep, backwardDimRep, forwardIndex, backwardIndex, **KWS):
+
+
+
+        ## CHEETAH: generated from @def transformMatricesForDimRepsAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex) at line 36, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(HermiteGaussFourierEPBasis, self).transformMatricesForDimRepsAtIndices(forwardDimRep,backwardDimRep,forwardIndex,backwardIndex)
+        if _v is not None: write(_filter(_v))
+        write(u'''eigenvalue_factor *= i;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def forwardMatrixForDimAtIndices(self, forwardDimRep, backwardDimRep, forwardIndex, backwardIndex, **KWS):
+
+
+
+        ## CHEETAH: generated from @def forwardMatrixForDimAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex) at line 43, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''eigenvalue_factor * ''')
+        _v = super(HermiteGaussFourierEPBasis, self).forwardMatrixForDimAtIndices(forwardDimRep,backwardDimRep,forwardIndex,backwardIndex)
+        if _v is not None: write(_filter(_v))
+        write(u'''
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def backwardMatrixForDimAtIndices(self, forwardDimRep, backwardDimRep, forwardIndex, backwardIndex, **KWS):
+
+
+
+        ## CHEETAH: generated from @def backwardMatrixForDimAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex) at line 47, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''conj(eigenvalue_factor) * ''')
+        _v = super(HermiteGaussFourierEPBasis, self).backwardMatrixForDimAtIndices(forwardDimRep,backwardDimRep,forwardIndex,backwardIndex)
+        if _v is not None: write(_filter(_v))
+        write(u'''
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # HermiteGaussFourierEPBasis.tmpl
+        # 
+        # Hermite-Gauss Fourier basis using the definite parity of the basis functions to remove
+        # half the work.
+        # 
+        # Created by Graham Dennis on 2009-08-12.
+        # 
+        # Copyright (c) 2009-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    matrixType = 'complex'
+
+    _mainCheetahMethod_for_HermiteGaussFourierEPBasis= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(HermiteGaussFourierEPBasis, '_initCheetahAttributes'):
+    templateAPIClass = getattr(HermiteGaussFourierEPBasis, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(HermiteGaussFourierEPBasis)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=HermiteGaussFourierEPBasis()).run()
+
+
diff --git a/xpdeint/Features/Transforms/HermiteGaussFourierEPBasis.tmpl b/xpdeint/Features/Transforms/HermiteGaussFourierEPBasis.tmpl
new file mode 100644
index 0000000..6f1a154
--- /dev/null
+++ b/xpdeint/Features/Transforms/HermiteGaussFourierEPBasis.tmpl
@@ -0,0 +1,50 @@
+@*
+HermiteGaussFourierEPBasis.tmpl
+
+Hermite-Gauss Fourier basis using the definite parity of the basis functions to remove
+half the work.
+
+Created by Graham Dennis on 2009-08-12.
+
+Copyright (c) 2009-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features.Transforms.HermiteGaussEPBasis
+
+ at def description: Hermite-Gauss Fourier basis (Harmonic oscillator)
+
+ at attr $matrixType = 'complex'
+
+ at def transformMatricesForwardDimConstantsAtIndex($forwardDimRep, $backwardDimRep, $forwardIndex)
+  @super(forwardDimRep, backwardDimRep, forwardIndex)
+complex eigenvalue_factor = 1.0;
+ at end def
+
+ at def transformMatricesForDimRepsAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex)
+  @#
+  @super(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex)
+eigenvalue_factor *= i;
+  @#
+ at end def
+
+ at def forwardMatrixForDimAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex)
+eigenvalue_factor * @super(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex)@slurp
+ at end def
+
+ at def backwardMatrixForDimAtIndices($forwardDimRep, $backwardDimRep, $forwardIndex, $backwardIndex)
+conj(eigenvalue_factor) * @super(forwardDimRep, backwardDimRep, forwardIndex, backwardIndex)@slurp
+ at end def
+
diff --git a/xpdeint/Features/Transforms/HermiteGaussTwiddleBasis.py b/xpdeint/Features/Transforms/HermiteGaussTwiddleBasis.py
new file mode 100644
index 0000000..f0b3afd
--- /dev/null
+++ b/xpdeint/Features/Transforms/HermiteGaussTwiddleBasis.py
@@ -0,0 +1,297 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features.Transforms.Basis import Basis
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.579578
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/Transforms/HermiteGaussTwiddleBasis.tmpl'
+__CHEETAH_srcLastModified__ = 'Fri Jul  5 16:29:35 2013'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class HermiteGaussTwiddleBasis(Basis):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(HermiteGaussTwiddleBasis, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Hermite-Gauss Twiddle basis (Multiplies eigenvalues by i) at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Hermite-Gauss Twiddle basis (Multiplies eigenvalues by i)''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def costEstimate(self, basisReps, **KWS):
+
+
+
+        ## CHEETAH: generated from @def costEstimate(basisReps) at line 32, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        return min([rep.latticeEstimate for rep in basisReps])
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def transformFunction(self, transformID, transformDict, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def transformFunction(transformID, transformDict, function) at line 37, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        transformPair = transformDict['transformPair']
+        forwardDimRep = transformPair[0][0]
+        backwardDimRep = transformPair[1][0]
+        isOutOfPlace = transformDict.get('outOfPlace', True)
+        write(u'''static const complex _forward_multipliers[4] = {1, -i, -1, i};
+static const complex _backward_multipliers[4] = {1, i, -1, -i};
+complex* const __restrict__ source_data = reinterpret_cast<complex* const>(_data_in);
+''')
+        if isOutOfPlace: # generated from line 46, col 1
+            write(u'''complex* const __restrict__ dest_data = reinterpret_cast<complex* const>(_data_out);
+''')
+        write(u'''
+const complex* const __restrict__ _multipliers = _forward ? _forward_multipliers : _backward_multipliers;
+
+''')
+        featureOrdering = ['OpenMP']
+        featureDict = {  'templateString': ''}
+        write(u'''for (long _i0 = 0; _i0 < _prefix_lattice; _i0++) {
+  for (long _i1 = 0; _i1 < ''')
+        _v = VFFSL(SL,"forwardDimRep.globalLattice",True) # u'${forwardDimRep.globalLattice}' on line 57, col 28
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.globalLattice}')) # from line 57, col 28.
+        write(u'''; _i1++) {
+    long multiplier_index = (_i1 & 3);
+''')
+        if not isOutOfPlace: # generated from line 59, col 5
+            write(u'''    if (multiplier_index == 0) continue;
+''')
+        write(u'''    
+    const complex multiplier = _multipliers[multiplier_index];
+    
+    #pragma ivdep
+''')
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('loopOverVectorsWithInnerContentTemplateBegin', featureOrdering, featureDict) # u"${insertCodeForFeatures('loopOverVectorsWithInnerContentTemplateBegin', featureOrdering, featureDict)}" on line 66, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('loopOverVectorsWithInnerContentTemplateBegin', featureOrdering, featureDict)}")) # from line 66, col 1.
+        write(u'''    for (long _i2 = 0; _i2 < _postfix_lattice; _i2++) {
+      ptrdiff_t _index = (_i0 * ''')
+        _v = VFFSL(SL,"forwardDimRep.globalLattice",True) # u'${forwardDimRep.globalLattice}' on line 68, col 33
+        if _v is not None: write(_filter(_v, rawExpr=u'${forwardDimRep.globalLattice}')) # from line 68, col 33.
+        write(u''' + _i1) * _postfix_lattice + _i2;
+''')
+        if isOutOfPlace: # generated from line 69, col 7
+            write(u'''      dest_data[_index] = multiplier * source_data[_index];
+''')
+        else: # generated from line 71, col 7
+            write(u'''      source_data[_index] *= multiplier;
+''')
+        write(u'''    }
+  }
+}
+''')
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('loopOverVectorsWithInnerContentTemplateEnd', featureOrdering, featureDict) # u"${insertCodeForFeaturesInReverseOrder('loopOverVectorsWithInnerContentTemplateEnd', featureOrdering, featureDict)}" on line 77, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeaturesInReverseOrder('loopOverVectorsWithInnerContentTemplateEnd', featureOrdering, featureDict)}")) # from line 77, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # HermiteGaussTwiddleBasis.tmpl
+        # 
+        # Hermite-Gauss Fourier basis using the definite parity of the basis functions to remove
+        # half the work.
+        # 
+        # Created by Graham Dennis on 2009-08-12.
+        # 
+        # Copyright (c) 2009-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    supportsInPlaceOperation = True
+
+    matrixType = 'complex'
+
+    _mainCheetahMethod_for_HermiteGaussTwiddleBasis= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(HermiteGaussTwiddleBasis, '_initCheetahAttributes'):
+    templateAPIClass = getattr(HermiteGaussTwiddleBasis, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(HermiteGaussTwiddleBasis)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=HermiteGaussTwiddleBasis()).run()
+
+
diff --git a/xpdeint/Features/Transforms/HermiteGaussTwiddleBasis.tmpl b/xpdeint/Features/Transforms/HermiteGaussTwiddleBasis.tmpl
new file mode 100644
index 0000000..dea61ce
--- /dev/null
+++ b/xpdeint/Features/Transforms/HermiteGaussTwiddleBasis.tmpl
@@ -0,0 +1,79 @@
+@*
+HermiteGaussTwiddleBasis.tmpl
+
+Hermite-Gauss Fourier basis using the definite parity of the basis functions to remove
+half the work.
+
+Created by Graham Dennis on 2009-08-12.
+
+Copyright (c) 2009-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features.Transforms.Basis
+
+ at def description: Hermite-Gauss Twiddle basis (Multiplies eigenvalues by i)
+
+ at attr $supportsInPlaceOperation = True
+ at attr $matrixType = 'complex'
+
+ at def costEstimate(basisReps)
+  @return min([rep.latticeEstimate for rep in basisReps])
+ at end def
+
+
+ at def transformFunction(transformID, transformDict, function)
+  @#
+  @set $transformPair = transformDict['transformPair']
+  @set $forwardDimRep = transformPair[0][0]
+  @set $backwardDimRep = transformPair[1][0]
+  @set isOutOfPlace =  transformDict.get('outOfPlace', True)
+static const complex _forward_multipliers[4] = {1, -i, -1, i};
+static const complex _backward_multipliers[4] = {1, i, -1, -i};
+complex* const __restrict__ source_data = reinterpret_cast<complex* const>(_data_in);
+ at if isOutOfPlace
+complex* const __restrict__ dest_data = reinterpret_cast<complex* const>(_data_out);
+ at end if
+
+const complex* const __restrict__ _multipliers = _forward ? _forward_multipliers : _backward_multipliers;
+
+ at set featureOrdering = ['OpenMP']
+ at set featureDict = {
+  'templateString': ''
+}
+for (long _i0 = 0; _i0 < _prefix_lattice; _i0++) {
+  for (long _i1 = 0; _i1 < ${forwardDimRep.globalLattice}; _i1++) {
+    long multiplier_index = (_i1 & 3);
+    @if not isOutOfPlace
+    if (multiplier_index == 0) continue;
+    @end if
+    
+    const complex multiplier = _multipliers[multiplier_index];
+    
+    #pragma ivdep
+${insertCodeForFeatures('loopOverVectorsWithInnerContentTemplateBegin', featureOrdering, featureDict)}@slurp
+    for (long _i2 = 0; _i2 < _postfix_lattice; _i2++) {
+      ptrdiff_t _index = (_i0 * ${forwardDimRep.globalLattice} + _i1) * _postfix_lattice + _i2;
+      @if isOutOfPlace
+      dest_data[_index] = multiplier * source_data[_index];
+      @else
+      source_data[_index] *= multiplier;
+      @end if
+    }
+  }
+}
+${insertCodeForFeaturesInReverseOrder('loopOverVectorsWithInnerContentTemplateEnd', featureOrdering, featureDict)}@slurp
+  @#
+ at end def
diff --git a/xpdeint/Features/Transforms/MMT.py b/xpdeint/Features/Transforms/MMT.py
new file mode 100644
index 0000000..d05e254
--- /dev/null
+++ b/xpdeint/Features/Transforms/MMT.py
@@ -0,0 +1,424 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features.Transforms._MMT import _MMT
+from xpdeint.Geometry.NonUniformDimensionRepresentation import NonUniformDimensionRepresentation
+from xpdeint.CallOnceGuards import callOnceGuard
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.616411
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/Transforms/MMT.tmpl'
+__CHEETAH_srcLastModified__ = 'Thu Nov  8 17:22:48 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class MMT(_MMT):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(MMT, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: MMT at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''MMT''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def includes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def includes at line 31, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(MMT, self).includes()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''#if   defined(CBLAS_MKL)
+  #include <mkl.h>
+#elif defined(CBLAS_VECLIB)
+  #include <Accelerate/Accelerate.h>
+#elif defined(CBLAS_ATLAS)
+''')
+        #  ATLAS CBLAS usually isn't wrapped by an extern "C" block, so we need to.
+        write(u'''  extern "C" {
+    #include <cblas.h>
+  }
+#elif defined(CBLAS_GSL)
+  #include <gsl/gsl_cblas.h>
+#endif
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def besselGlobalsForDim(self, dimName, basisDict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def besselGlobalsForDim($dimName, $basisDict) at line 50, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        besselOrder = basisDict['order'] + basisDict['orderOffset']
+        lattice = basisDict['lattice']
+        write(u'''const real _normbesseljzeros_''')
+        _v = VFFSL(SL,"dimName",True) # u'${dimName}' on line 54, col 30
+        if _v is not None: write(_filter(_v, rawExpr=u'${dimName}')) # from line 54, col 30.
+        write(u'''[] = {''')
+        _v = VFFSL(SL,"wrapArray",False)(VFFSL(SL,"normalisedBesselJZeros",False)(besselOrder, lattice)) # u'${wrapArray($normalisedBesselJZeros(besselOrder, lattice))}' on line 54, col 46
+        if _v is not None: write(_filter(_v, rawExpr=u'${wrapArray($normalisedBesselJZeros(besselOrder, lattice))}')) # from line 54, col 46.
+        write(u'''};
+const real _besseljnorm_''')
+        _v = VFFSL(SL,"dimName",True) # u'${dimName}' on line 55, col 25
+        if _v is not None: write(_filter(_v, rawExpr=u'${dimName}')) # from line 55, col 25.
+        write(u''' = ''')
+        _v = VFFSL(SL,"besselJZeros",False)(besselOrder, lattice+1)[-1] # u'${besselJZeros(besselOrder, lattice+1)[-1]}' on line 55, col 38
+        if _v is not None: write(_filter(_v, rawExpr=u'${besselJZeros(besselOrder, lattice+1)[-1]}')) # from line 55, col 38.
+        write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def hermiteGaussGlobalsForDim(self, dimName, basisDict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def hermiteGaussGlobalsForDim($dimName, $basisDict) at line 59, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        lattice = basisDict['lattice']
+        write(u'''const real _hermite_zeros_''')
+        _v = VFFSL(SL,"dimName",True) # u'${dimName}' on line 62, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'${dimName}')) # from line 62, col 27.
+        write(u'''[] = {''')
+        _v = VFFSL(SL,"wrapArray",False)(VFFSL(SL,"hermiteZeros",False)(lattice)) # u'${wrapArray($hermiteZeros(lattice))}' on line 62, col 43
+        if _v is not None: write(_filter(_v, rawExpr=u'${wrapArray($hermiteZeros(lattice))}')) # from line 62, col 43.
+        write(u'''};
+const real _hermite_gauss_weights_''')
+        _v = VFFSL(SL,"dimName",True) # u'${dimName}' on line 63, col 35
+        if _v is not None: write(_filter(_v, rawExpr=u'${dimName}')) # from line 63, col 35.
+        write(u'''[] = {''')
+        _v = VFFSL(SL,"wrapArray",False)(VFFSL(SL,"hermiteGaussWeights",False)(lattice)) # u'${wrapArray($hermiteGaussWeights(lattice))}' on line 63, col 51
+        if _v is not None: write(_filter(_v, rawExpr=u'${wrapArray($hermiteGaussWeights(lattice))}')) # from line 63, col 51.
+        write(u'''};
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def mainBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def mainBegin($dict) at line 67, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''
+''')
+        if 'mpi' in VFFSL(SL,"simulationBuildVariant",True): # generated from line 70, col 3
+            write(u'''#if defined(CBLAS_VECLIB)
+// We are using MPI. If we let vecLib spawn threads then overall performance will suffer
+  setenv("VECLIB_MAXIMUM_THREADS", "1", 1);
+#endif
+''')
+        # 
+        for dimName, basisDict in VFN(VFFSL(SL,"basisMap",True),"items",False)(): # generated from line 77, col 3
+            for field in [field for field in VFFSL(SL,"fields",True) if field.hasDimensionName(dimName)]: # generated from line 78, col 5
+                if field == VFFSL(SL,"geometry",True): # generated from line 79, col 7
+                    continue
+                for (fieldDimRep, geometryDimRep) in zip(field.dimensionWithName(dimName).representations, VFN(VFN(VFFSL(SL,"geometry",True),"dimensionWithName",False)(dimName),"representations",True)): # generated from line 82, col 7
+                    if not fieldDimRep or not isinstance(fieldDimRep, NonUniformDimensionRepresentation) or geometryDimRep.arrayName == fieldDimRep.arrayName: # generated from line 83, col 9
+                        continue
+                    if geometryDimRep.runtimeLattice == fieldDimRep.runtimeLattice: # generated from line 86, col 9
+                        write(u'''memcpy(''')
+                        _v = VFFSL(SL,"fieldDimRep.arrayName",True) # u'${fieldDimRep.arrayName}' on line 87, col 8
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldDimRep.arrayName}')) # from line 87, col 8.
+                        write(u''', ''')
+                        _v = VFFSL(SL,"geometryDimRep.arrayName",True) # u'${geometryDimRep.arrayName}' on line 87, col 34
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryDimRep.arrayName}')) # from line 87, col 34.
+                        write(u''', sizeof(real)*''')
+                        _v = VFFSL(SL,"geometryDimRep.globalLattice",True) # u'${geometryDimRep.globalLattice}' on line 87, col 76
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryDimRep.globalLattice}')) # from line 87, col 76.
+                        write(u''');
+memcpy(''')
+                        _v = VFFSL(SL,"fieldDimRep.stepSizeArrayName",True) # u'${fieldDimRep.stepSizeArrayName}' on line 88, col 8
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldDimRep.stepSizeArrayName}')) # from line 88, col 8.
+                        write(u''', ''')
+                        _v = VFFSL(SL,"geometryDimRep.stepSizeArrayName",True) # u'${geometryDimRep.stepSizeArrayName}' on line 88, col 42
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryDimRep.stepSizeArrayName}')) # from line 88, col 42.
+                        write(u''', sizeof(real) * ''')
+                        _v = VFFSL(SL,"geometryDimRep.globalLattice",True) # u'${geometryDimRep.globalLattice}' on line 88, col 94
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryDimRep.globalLattice}')) # from line 88, col 94.
+                        write(u''');
+''')
+                    else: # generated from line 89, col 9
+                        write(u'''for (long _i0=0; _i0 < ''')
+                        _v = VFFSL(SL,"fieldDimRep.globalLattice",True) # u'$fieldDimRep.globalLattice' on line 90, col 24
+                        if _v is not None: write(_filter(_v, rawExpr=u'$fieldDimRep.globalLattice')) # from line 90, col 24.
+                        write(u'''; _i0++) {
+  ''')
+                        _v = VFFSL(SL,"fieldDimRep.arrayName",True) # u'${fieldDimRep.arrayName}' on line 91, col 3
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldDimRep.arrayName}')) # from line 91, col 3.
+                        write(u'''[_i0] = ''')
+                        _v = VFFSL(SL,"geometryDimRep.arrayName",True) # u'${geometryDimRep.arrayName}' on line 91, col 35
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryDimRep.arrayName}')) # from line 91, col 35.
+                        write(u'''[_i0 * (''')
+                        _v = VFFSL(SL,"geometryDimRep.globalLattice",True) # u'$geometryDimRep.globalLattice' on line 91, col 70
+                        if _v is not None: write(_filter(_v, rawExpr=u'$geometryDimRep.globalLattice')) # from line 91, col 70.
+                        write(u''' / ''')
+                        _v = VFFSL(SL,"fieldDimRep.globalLattice",True) # u'$fieldDimRep.globalLattice' on line 91, col 102
+                        if _v is not None: write(_filter(_v, rawExpr=u'$fieldDimRep.globalLattice')) # from line 91, col 102.
+                        write(u''')];
+  ''')
+                        _v = VFFSL(SL,"fieldDimRep.stepSizeArrayName",True) # u'${fieldDimRep.stepSizeArrayName}' on line 92, col 3
+                        if _v is not None: write(_filter(_v, rawExpr=u'${fieldDimRep.stepSizeArrayName}')) # from line 92, col 3.
+                        write(u'''[_i0] = ''')
+                        _v = VFFSL(SL,"geometryDimRep.stepSizeArrayName",True) # u'${geometryDimRep.stepSizeArrayName}' on line 92, col 43
+                        if _v is not None: write(_filter(_v, rawExpr=u'${geometryDimRep.stepSizeArrayName}')) # from line 92, col 43.
+                        write(u'''[_i0 * (''')
+                        _v = VFFSL(SL,"geometryDimRep.globalLattice",True) # u'$geometryDimRep.globalLattice' on line 92, col 86
+                        if _v is not None: write(_filter(_v, rawExpr=u'$geometryDimRep.globalLattice')) # from line 92, col 86.
+                        write(u''' / ''')
+                        _v = VFFSL(SL,"fieldDimRep.globalLattice",True) # u'$fieldDimRep.globalLattice' on line 92, col 118
+                        if _v is not None: write(_filter(_v, rawExpr=u'$fieldDimRep.globalLattice')) # from line 92, col 118.
+                        write(u''')];
+}
+''')
+            write(u'''
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # MMT.tmpl
+        # 
+        # Created by Graham Dennis on 2008-12-12.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    uselib = ['cblas']
+
+    _mainCheetahMethod_for_MMT= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(MMT, '_initCheetahAttributes'):
+    templateAPIClass = getattr(MMT, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(MMT)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=MMT()).run()
+
+
diff --git a/xpdeint/Features/Transforms/MMT.tmpl b/xpdeint/Features/Transforms/MMT.tmpl
new file mode 100644
index 0000000..e2661dc
--- /dev/null
+++ b/xpdeint/Features/Transforms/MMT.tmpl
@@ -0,0 +1,100 @@
+@*
+MMT.tmpl
+
+Created by Graham Dennis on 2008-12-12.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features.Transforms._MMT
+
+ at from xpdeint.Geometry.NonUniformDimensionRepresentation import NonUniformDimensionRepresentation
+
+ at def description: MMT
+ at attr $uselib = ['cblas']
+
+ at from xpdeint.CallOnceGuards import callOnceGuard
+
+ at def includes
+  @#
+  @super
+  @#
+#if   defined(CBLAS_MKL)
+  #include <mkl.h>
+#elif defined(CBLAS_VECLIB)
+  #include <Accelerate/Accelerate.h>
+#elif defined(CBLAS_ATLAS)
+  @# ATLAS CBLAS usually isn't wrapped by an extern "C" block, so we need to.
+  extern "C" {
+    #include <cblas.h>
+  }
+#elif defined(CBLAS_GSL)
+  #include <gsl/gsl_cblas.h>
+#endif
+  @#
+ at end def
+
+ at def besselGlobalsForDim($dimName, $basisDict)
+  @#
+  @set $besselOrder = basisDict['order'] + basisDict['orderOffset']
+  @set $lattice = basisDict['lattice']
+const real _normbesseljzeros_${dimName}[] = {${wrapArray($normalisedBesselJZeros(besselOrder, lattice))}};
+const real _besseljnorm_${dimName} = ${besselJZeros(besselOrder, lattice+1)[-1]};
+  @#
+ at end def
+
+ at def hermiteGaussGlobalsForDim($dimName, $basisDict)
+  @#
+  @set $lattice = basisDict['lattice']
+const real _hermite_zeros_${dimName}[] = {${wrapArray($hermiteZeros(lattice))}};
+const real _hermite_gauss_weights_${dimName}[] = {${wrapArray($hermiteGaussWeights(lattice))}};
+  @#
+ at end def
+
+ at def mainBegin($dict)
+  @#
+
+  @if 'mpi' in $simulationBuildVariant
+#if defined(CBLAS_VECLIB)
+// We are using MPI. If we let vecLib spawn threads then overall performance will suffer
+  setenv("VECLIB_MAXIMUM_THREADS", "1", 1);
+#endif
+  @end if
+  @#
+  @for dimName, basisDict in $basisMap.items()
+    @for field in [field for field in $fields if field.hasDimensionName(dimName)]
+      @if field == $geometry
+        @continue
+      @end if
+      @for (fieldDimRep, geometryDimRep) in zip(field.dimensionWithName(dimName).representations, $geometry.dimensionWithName(dimName).representations)
+        @if not fieldDimRep or not isinstance(fieldDimRep, NonUniformDimensionRepresentation) or geometryDimRep.arrayName == fieldDimRep.arrayName
+          @continue
+        @end if
+        @if geometryDimRep.runtimeLattice == fieldDimRep.runtimeLattice
+memcpy(${fieldDimRep.arrayName}, ${geometryDimRep.arrayName}, sizeof(real)*${geometryDimRep.globalLattice});
+memcpy(${fieldDimRep.stepSizeArrayName}, ${geometryDimRep.stepSizeArrayName}, sizeof(real) * ${geometryDimRep.globalLattice});
+        @else
+for (long _i0=0; _i0 < $fieldDimRep.globalLattice; _i0++) {
+  ${fieldDimRep.arrayName}[_i0] = ${geometryDimRep.arrayName}[_i0 * ($geometryDimRep.globalLattice / $fieldDimRep.globalLattice)];
+  ${fieldDimRep.stepSizeArrayName}[_i0] = ${geometryDimRep.stepSizeArrayName}[_i0 * ($geometryDimRep.globalLattice / $fieldDimRep.globalLattice)];
+}
+        @end if
+      @end for
+    @end for
+
+  @end for
+ at end def
+
diff --git a/xpdeint/Features/Transforms/NoTransformMPI.py b/xpdeint/Features/Transforms/NoTransformMPI.py
new file mode 100644
index 0000000..bf0be87
--- /dev/null
+++ b/xpdeint/Features/Transforms/NoTransformMPI.py
@@ -0,0 +1,311 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features.Transforms._NoTransformMPI import _NoTransformMPI
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.638611
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/Transforms/NoTransformMPI.tmpl'
+__CHEETAH_srcLastModified__ = 'Thu Feb 23 00:45:53 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class NoTransformMPI(_NoTransformMPI):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(NoTransformMPI, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: MPI-distributed dimension control at line 23, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''MPI-distributed dimension control''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def setLocalLatticeAndOffsetVariables(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def setLocalLatticeAndOffsetVariables at line 25, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''// First work out the local lattice and offset for the geometry
+''')
+        mpiDimRep = VFN(VFFSL(SL,"mpiDimension",True),"representations",True)[0]
+        write(u'''// Set the block size for most ranks to lattice/processors rounded up
+ptrdiff_t _block_size = (''')
+        _v = VFFSL(SL,"mpiDimRep.globalLattice",True) # u'${mpiDimRep.globalLattice}' on line 30, col 26
+        if _v is not None: write(_filter(_v, rawExpr=u'${mpiDimRep.globalLattice}')) # from line 30, col 26.
+        write(u'''-1)/_size + 1;
+''')
+        _v = VFFSL(SL,"mpiDimRep.localOffset",True) # u'${mpiDimRep.localOffset}' on line 31, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${mpiDimRep.localOffset}')) # from line 31, col 1.
+        write(u''' = _rank * _block_size;
+if (_rank != _size - 1)
+  ''')
+        _v = VFFSL(SL,"mpiDimRep.localLattice",True) # u'${mpiDimRep.localLattice}' on line 33, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${mpiDimRep.localLattice}')) # from line 33, col 3.
+        write(u""" = _block_size;
+else {
+  // The last rank takes up everything else
+  // this should be less than or equal to _block_size
+  // And if there's nothing left, we don't have a local lattice.
+  """)
+        _v = VFFSL(SL,"mpiDimRep.localLattice",True) # u'${mpiDimRep.localLattice}' on line 38, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${mpiDimRep.localLattice}')) # from line 38, col 3.
+        write(u''' = MAX(''')
+        _v = VFFSL(SL,"mpiDimRep.globalLattice",True) # u'${mpiDimRep.globalLattice}' on line 38, col 35
+        if _v is not None: write(_filter(_v, rawExpr=u'${mpiDimRep.globalLattice}')) # from line 38, col 35.
+        write(u''' - _block_size * (_size - 1), 0);
+}
+
+''')
+        for field in VFFSL(SL,"fields",True): # generated from line 41, col 3
+            if field.name == 'geometry' or not VFFSL(SL,"isFieldDistributed",False)(field): # generated from line 42, col 5
+                continue
+            #  Set the local_lattice and local_offset variables based on the
+            #  values for the geometry's version of these variables
+            fieldMPIDimRep = field.dimensionWithName(VFFSL(SL,"mpiDimension.name",True)).representations[0]
+            write(u"""// Set the local_lattice and local_offset variables for the '""")
+            _v = VFFSL(SL,"field.name",True) # u'${field.name}' on line 48, col 62
+            if _v is not None: write(_filter(_v, rawExpr=u'${field.name}')) # from line 48, col 62.
+            write(u"""' field.
+ptrdiff_t _""")
+            _v = VFFSL(SL,"field.name",True) # u'${field.name}' on line 49, col 12
+            if _v is not None: write(_filter(_v, rawExpr=u'${field.name}')) # from line 49, col 12.
+            write(u'''_skip_size = ''')
+            _v = VFFSL(SL,"mpiDimRep.globalLattice",True) # u'${mpiDimRep.globalLattice}' on line 49, col 38
+            if _v is not None: write(_filter(_v, rawExpr=u'${mpiDimRep.globalLattice}')) # from line 49, col 38.
+            write(u'''/''')
+            _v = VFFSL(SL,"fieldMPIDimRep.globalLattice",True) # u'${fieldMPIDimRep.globalLattice}' on line 49, col 65
+            if _v is not None: write(_filter(_v, rawExpr=u'${fieldMPIDimRep.globalLattice}')) # from line 49, col 65.
+            write(u''';
+if (_rank == 0) {
+  ''')
+            _v = VFFSL(SL,"fieldMPIDimRep.localOffset",True) # u'${fieldMPIDimRep.localOffset}' on line 51, col 3
+            if _v is not None: write(_filter(_v, rawExpr=u'${fieldMPIDimRep.localOffset}')) # from line 51, col 3.
+            write(u''' = 0;
+  ''')
+            _v = VFFSL(SL,"fieldMPIDimRep.localLattice",True) # u'${fieldMPIDimRep.localLattice}' on line 52, col 3
+            if _v is not None: write(_filter(_v, rawExpr=u'${fieldMPIDimRep.localLattice}')) # from line 52, col 3.
+            write(u''' = (''')
+            _v = VFFSL(SL,"mpiDimRep.localLattice",True) # u'${mpiDimRep.localLattice}' on line 52, col 37
+            if _v is not None: write(_filter(_v, rawExpr=u'${mpiDimRep.localLattice}')) # from line 52, col 37.
+            write(u'''-1)/_''')
+            _v = VFFSL(SL,"field.name",True) # u'${field.name}' on line 52, col 67
+            if _v is not None: write(_filter(_v, rawExpr=u'${field.name}')) # from line 52, col 67.
+            write(u'''_skip_size + 1;
+} else {
+  ''')
+            _v = VFFSL(SL,"fieldMPIDimRep.localOffset",True) # u'${fieldMPIDimRep.localOffset}' on line 54, col 3
+            if _v is not None: write(_filter(_v, rawExpr=u'${fieldMPIDimRep.localOffset}')) # from line 54, col 3.
+            write(u''' = (''')
+            _v = VFFSL(SL,"mpiDimRep.localOffset",True) # u'${mpiDimRep.localOffset}' on line 54, col 36
+            if _v is not None: write(_filter(_v, rawExpr=u'${mpiDimRep.localOffset}')) # from line 54, col 36.
+            write(u'''-1)/_''')
+            _v = VFFSL(SL,"field.name",True) # u'${field.name}' on line 54, col 65
+            if _v is not None: write(_filter(_v, rawExpr=u'${field.name}')) # from line 54, col 65.
+            write(u'''_skip_size + 1;
+  ''')
+            _v = VFFSL(SL,"fieldMPIDimRep.localLattice",True) # u'${fieldMPIDimRep.localLattice}' on line 55, col 3
+            if _v is not None: write(_filter(_v, rawExpr=u'${fieldMPIDimRep.localLattice}')) # from line 55, col 3.
+            write(u''' = MIN((''')
+            _v = VFFSL(SL,"mpiDimRep.localOffset",True) # u'${mpiDimRep.localOffset}' on line 55, col 41
+            if _v is not None: write(_filter(_v, rawExpr=u'${mpiDimRep.localOffset}')) # from line 55, col 41.
+            write(u''' + ''')
+            _v = VFFSL(SL,"mpiDimRep.localLattice",True) # u'${mpiDimRep.localLattice}' on line 55, col 68
+            if _v is not None: write(_filter(_v, rawExpr=u'${mpiDimRep.localLattice}')) # from line 55, col 68.
+            write(u''' - 1)/_''')
+            _v = VFFSL(SL,"field.name",True) # u'${field.name}' on line 55, col 100
+            if _v is not None: write(_filter(_v, rawExpr=u'${field.name}')) # from line 55, col 100.
+            write(u'''_skip_size
+                                         + 1 - ''')
+            _v = VFFSL(SL,"fieldMPIDimRep.localOffset",True) # u'${fieldMPIDimRep.localOffset}' on line 56, col 48
+            if _v is not None: write(_filter(_v, rawExpr=u'${fieldMPIDimRep.localOffset}')) # from line 56, col 48.
+            write(u''', MAX(''')
+            _v = VFFSL(SL,"fieldMPIDimRep.globalLattice",True) # u'${fieldMPIDimRep.globalLattice}' on line 56, col 83
+            if _v is not None: write(_filter(_v, rawExpr=u'${fieldMPIDimRep.globalLattice}')) # from line 56, col 83.
+            write(u''' - ''')
+            _v = VFFSL(SL,"fieldMPIDimRep.localOffset",True) # u'${fieldMPIDimRep.localOffset}' on line 56, col 117
+            if _v is not None: write(_filter(_v, rawExpr=u'${fieldMPIDimRep.localOffset}')) # from line 56, col 117.
+            write(u''', 0));
+}
+
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # NoTransformMPI.tmpl
+        # 
+        # Created by Graham Dennis on 2008-08-24.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_NoTransformMPI= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(NoTransformMPI, '_initCheetahAttributes'):
+    templateAPIClass = getattr(NoTransformMPI, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(NoTransformMPI)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=NoTransformMPI()).run()
+
+
diff --git a/xpdeint/Features/Transforms/NoTransformMPI.tmpl b/xpdeint/Features/Transforms/NoTransformMPI.tmpl
new file mode 100644
index 0000000..7357d53
--- /dev/null
+++ b/xpdeint/Features/Transforms/NoTransformMPI.tmpl
@@ -0,0 +1,62 @@
+@*
+NoTransformMPI.tmpl
+
+Created by Graham Dennis on 2008-08-24.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features.Transforms._NoTransformMPI
+ at def description: MPI-distributed dimension control
+
+ at def setLocalLatticeAndOffsetVariables
+  @#
+// First work out the local lattice and offset for the geometry
+  @set $mpiDimRep = $mpiDimension.representations[0]
+// Set the block size for most ranks to lattice/processors rounded up
+ptrdiff_t _block_size = (${mpiDimRep.globalLattice}-1)/_size + 1;
+${mpiDimRep.localOffset} = _rank * _block_size;
+if (_rank != _size - 1)
+  ${mpiDimRep.localLattice} = _block_size;
+else {
+  // The last rank takes up everything else
+  // this should be less than or equal to _block_size
+  // And if there's nothing left, we don't have a local lattice.
+  ${mpiDimRep.localLattice} = MAX(${mpiDimRep.globalLattice} - _block_size * (_size - 1), 0);
+}
+
+  @for $field in $fields
+    @if field.name == 'geometry' or not $isFieldDistributed(field)
+      @continue
+    @end if
+    @# Set the local_lattice and local_offset variables based on the
+    @# values for the geometry's version of these variables
+    @set fieldMPIDimRep = field.dimensionWithName($mpiDimension.name).representations[0]
+// Set the local_lattice and local_offset variables for the '${field.name}' field.
+ptrdiff_t _${field.name}_skip_size = ${mpiDimRep.globalLattice}/${fieldMPIDimRep.globalLattice};
+if (_rank == 0) {
+  ${fieldMPIDimRep.localOffset} = 0;
+  ${fieldMPIDimRep.localLattice} = (${mpiDimRep.localLattice}-1)/_${field.name}_skip_size + 1;
+} else {
+  ${fieldMPIDimRep.localOffset} = (${mpiDimRep.localOffset}-1)/_${field.name}_skip_size + 1;
+  ${fieldMPIDimRep.localLattice} = MIN((${mpiDimRep.localOffset} + ${mpiDimRep.localLattice} - 1)/_${field.name}_skip_size
+                                         + 1 - ${fieldMPIDimRep.localOffset}, MAX(${fieldMPIDimRep.globalLattice} - ${fieldMPIDimRep.localOffset}, 0));
+}
+
+  @end for
+  @#
+ at end def
+
diff --git a/xpdeint/Features/Transforms/TransformMultiplexer.py b/xpdeint/Features/Transforms/TransformMultiplexer.py
new file mode 100644
index 0000000..e922dc2
--- /dev/null
+++ b/xpdeint/Features/Transforms/TransformMultiplexer.py
@@ -0,0 +1,751 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features.Transforms._TransformMultiplexer import _TransformMultiplexer
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.742398
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/Transforms/TransformMultiplexer.tmpl'
+__CHEETAH_srcLastModified__ = 'Mon Jul 23 09:42:26 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class TransformMultiplexer(_TransformMultiplexer):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(TransformMultiplexer, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Transform Multiplexer at line 23, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Transform Multiplexer''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def includes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def includes at line 25, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''#include <utility>
+#include <map>
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def globals at line 30, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''typedef pair<ptrdiff_t, ptrdiff_t> _basis_pair;
+typedef void (*transform_function)(bool, real, real* const __restrict__, real* const __restrict__, ptrdiff_t, ptrdiff_t);
+
+// Less than operator needed by the C++ map class
+struct _basis_pair_less_than
+{
+  bool operator()(const _basis_pair& _x, const _basis_pair& _y) const {
+    return (_x.first < _y.first) || ((_x.first == _y.first) && (_x.second < _y.second));
+  }
+};
+
+struct _transform_step
+{
+  transform_function _func;
+  bool _forward;
+  bool _out_of_place;
+  ptrdiff_t _prefix_lattice;
+  ptrdiff_t _postfix_lattice;
+};
+
+// Structure to hold the basis change information
+struct _basis_transform_t
+{
+  vector<_transform_step> _transform_steps;
+  real _multiplier;
+  
+  _basis_transform_t(real _multiplier_in = 1.0) : _multiplier(_multiplier_in) {}
+  
+  _basis_transform_t(const _basis_transform_t& _b) : _transform_steps(_b._transform_steps), _multiplier(_b._multiplier) {}
+  
+  void append(transform_function _func, bool _forward, bool _out_of_place, ptrdiff_t _prefix_lattice, ptrdiff_t _postfix_lattice)
+  {
+    _transform_steps.push_back((_transform_step){_func, _forward, _out_of_place, _prefix_lattice, _postfix_lattice});
+  }
+};
+
+// Map type for holding (old_basis, new_basis) -> _basis_transform_t mappings
+typedef map<_basis_pair, _basis_transform_t, _basis_pair_less_than> _basis_map;
+
+''')
+        for vector in self.vectorTransformMap: # generated from line 71, col 3
+            write(u'''_basis_map _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 72, col 13
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 72, col 13.
+            write(u'''_basis_map;
+''')
+        write(u'''
+real *_auxiliary_array = NULL;
+
+const char *_basis_identifiers[] = {
+''')
+        for idx, basis in enumerate(self.basesNeeded): # generated from line 78, col 3
+            write(u'''  /* ''')
+            _v = VFFSL(SL,"idx",True) # u'${idx}' on line 79, col 6
+            if _v is not None: write(_filter(_v, rawExpr=u'${idx}')) # from line 79, col 6.
+            write(u''' */ "(''')
+            _v = ', '.join(basis) # u"${', '.join(basis)}" on line 79, col 18
+            if _v is not None: write(_filter(_v, rawExpr=u"${', '.join(basis)}")) # from line 79, col 18.
+            write(u''')",
+''')
+        write(u'''};
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def basisTransformFunctionContentsBegin(self, dict, **KWS):
+
+
+        """
+        Returns the ``basis_transform`` function implementation for vector `vector`.
+        
+        This writes the function that does the fourier transforming of a specific vector
+        to and from arbitrary combinations of fourier-space and normal-space.
+        """
+
+        ## CHEETAH: generated from @def basisTransformFunctionContentsBegin($dict) at line 85, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        function = dict['function']
+        vector = dict['caller']
+        transformInfo = self.vectorTransformMap[vector]
+        write(u'''if (_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 96, col 6
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 96, col 6.
+        write(u'''_basis == new_basis)
+  return;
+
+if (_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 99, col 6
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 99, col 6.
+        write(u'''_basis == -1) {
+  _LOG(
+    _ERROR_LOG_LEVEL,
+    "Error: Attempted to transform the vector \'''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 102, col 48
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 102, col 48.
+        write(u'''\' to basis %s, but the vector doesn\'t have a basis specified yet!\\n"
+    "       Please report this error to ''')
+        _v = VFFSL(SL,"bugReportAddress",True) # u'$bugReportAddress' on line 103, col 41
+        if _v is not None: write(_filter(_v, rawExpr=u'$bugReportAddress')) # from line 103, col 41.
+        write(u'''\\n",
+    _basis_identifiers[new_basis]
+    );
+}
+
+if (_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 108, col 6
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 108, col 6.
+        write(u'''_basis_map.count(_basis_pair(_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 108, col 48
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 108, col 48.
+        write(u'''_basis, new_basis)) == 0) {
+  _LOG(
+    _ERROR_LOG_LEVEL,
+    "Error: We should have information about how to do every needed transform, but it seems we don\'t for this transform.\\n"
+    "       The transform is for the vector \'''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 112, col 46
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 112, col 46.
+        write(u'''\' from basis %s to basis %s.\\n",
+    _basis_identifiers[_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 113, col 25
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 113, col 25.
+        write(u'''_basis], _basis_identifiers[new_basis]
+  );
+}
+_basis_transform_t &_t = _''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 116, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 116, col 27.
+        write(u'''_basis_map[_basis_pair(_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 116, col 63
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 116, col 63.
+        write(u'''_basis, new_basis)];
+if (_t._transform_steps.size() == 0) {
+  _LOG(_ERROR_LOG_LEVEL, "Error: It looks like we tried to create plans for this transform, but failed.\\n"
+                         "       The transform was for the vector \'''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 119, col 68
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 119, col 68.
+        write(u'''\' from basis %s to basis %s.\\n",
+                         _basis_identifiers[_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 120, col 46
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 120, col 46.
+        write(u'''_basis], _basis_identifiers[new_basis]);
+}
+real *_source_data = reinterpret_cast<real*>(_active_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 122, col 54
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 122, col 54.
+        write(u''');
+real *_dest_data = _auxiliary_array;
+for (vector<_transform_step>::iterator _it = _t._transform_steps.begin(); _it != _t._transform_steps.end(); ++_it) {
+  _it->_func(_it->_forward, _t._multiplier, _source_data, _dest_data, _it->_prefix_lattice, _it->_postfix_lattice);
+  if (_it->_out_of_place) {
+    real *_temp = _source_data;
+    _source_data = _dest_data;
+    _dest_data = _temp;
+  }
+}
+_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 132, col 2
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 132, col 2.
+        write(u'''_basis = new_basis;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def oopCopyTransformFunction(self, transformID, transformDict, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def oopCopyTransformFunction(transformID, transformDict, function) at line 136, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''memcpy(_data_out, _data_in, _prefix_lattice * _postfix_lattice * sizeof(real));
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def ipMultiplyTransformFunction(self, transformID, transformDict, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def ipMultiplyTransformFunction(transformID, transformDict, function) at line 142, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        featureOrdering = ['OpenMP']
+        featureDict = {    'templateString': ''  }
+        write(u'''#pragma ivdep
+''')
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('loopOverVectorsWithInnerContentTemplateBegin', featureOrdering, featureDict) # u"${insertCodeForFeatures('loopOverVectorsWithInnerContentTemplateBegin', featureOrdering, featureDict)}" on line 149, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('loopOverVectorsWithInnerContentTemplateBegin', featureOrdering, featureDict)}")) # from line 149, col 1.
+        write(u'''for (long _i0 = 0; _i0 < _prefix_lattice * _postfix_lattice; _i0++) {
+  _data_in[_i0] *= _multiplier;
+}
+''')
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('loopOverVectorsWithInnerContentTemplateEnd', featureOrdering, featureDict) # u"${insertCodeForFeaturesInReverseOrder('loopOverVectorsWithInnerContentTemplateEnd', featureOrdering, featureDict)}" on line 153, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeaturesInReverseOrder('loopOverVectorsWithInnerContentTemplateEnd', featureOrdering, featureDict)}")) # from line 153, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def oopMultiplyTransformFunction(self, transformID, transformDict, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def oopMultiplyTransformFunction(transformID, transformDict, function) at line 157, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        featureOrdering = ['OpenMP']
+        featureDict = {    'templateString': ''  }
+        write(u'''#pragma ivdep
+''')
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('loopOverVectorsWithInnerContentTemplateBegin', featureOrdering, featureDict) # u"${insertCodeForFeatures('loopOverVectorsWithInnerContentTemplateBegin', featureOrdering, featureDict)}" on line 164, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('loopOverVectorsWithInnerContentTemplateBegin', featureOrdering, featureDict)}")) # from line 164, col 1.
+        write(u'''for (long _i0 = 0; _i0 < _prefix_lattice * _postfix_lattice; _i0++) {
+  _data_out[_i0] = _data_in[_i0] * _multiplier;
+}
+''')
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('loopOverVectorsWithInnerContentTemplateEnd', featureOrdering, featureDict) # u"${insertCodeForFeaturesInReverseOrder('loopOverVectorsWithInnerContentTemplateEnd', featureOrdering, featureDict)}" on line 168, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeaturesInReverseOrder('loopOverVectorsWithInnerContentTemplateEnd', featureOrdering, featureDict)}")) # from line 168, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def mainBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def mainBegin($dict) at line 173, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''
+_basis_transform_t *_basis_transform = NULL;
+ptrdiff_t _auxiliary_array_size = 0;
+ptrdiff_t _max_vector_size = 0;
+real* _max_vector_array = NULL;
+
+''')
+        boolMap = {True: 'true', False: 'false'}
+        for vector, vectorTransformInfo in self.vectorTransformMap.items(): # generated from line 182, col 3
+            sizePrefix = '2 * ' if vector.type == 'complex' else ''
+            write(u'''if (''')
+            _v = VFFSL(SL,"sizePrefix",True) # u'${sizePrefix}' on line 184, col 5
+            if _v is not None: write(_filter(_v, rawExpr=u'${sizePrefix}')) # from line 184, col 5.
+            _v = VFFSL(SL,"vector.allocSize",True) # u'${vector.allocSize}' on line 184, col 18
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.allocSize}')) # from line 184, col 18.
+            write(u''' > _max_vector_size) {
+  _max_vector_size = ''')
+            _v = VFFSL(SL,"sizePrefix",True) # u'${sizePrefix}' on line 185, col 22
+            if _v is not None: write(_filter(_v, rawExpr=u'${sizePrefix}')) # from line 185, col 22.
+            _v = VFFSL(SL,"vector.allocSize",True) # u'${vector.allocSize}' on line 185, col 35
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.allocSize}')) # from line 185, col 35.
+            write(u''';
+  _max_vector_array = reinterpret_cast<real*>(_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 186, col 48
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 186, col 48.
+            write(u''');
+}
+''')
+            needsAuxiliaryArray = False
+            bases = vectorTransformInfo['bases']
+            basisPairMap = vectorTransformInfo['basisPairMap']
+            for basisPairInfo in basisPairMap.values(): # generated from line 191, col 5
+                basisPair = basisPairInfo['basisPair']
+                write(u'''_basis_transform = &_''')
+                _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 193, col 22
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 193, col 22.
+                write(u'''_basis_map[_basis_pair(''')
+                _v = ', '.join([str(self.basisIndexForBasis(basis)) for basis in basisPair]) # u"${', '.join([str(self.basisIndexForBasis(basis)) for basis in basisPair])}" on line 193, col 57
+                if _v is not None: write(_filter(_v, rawExpr=u"${', '.join([str(self.basisIndexForBasis(basis)) for basis in basisPair])}")) # from line 193, col 57.
+                write(u''')];
+''')
+                if basisPairInfo['forwardScale']: # generated from line 194, col 7
+                    write(u'''_basis_transform->_multiplier = ''')
+                    _v = ' * '.join(basisPairInfo['forwardScale']) # u"${' * '.join(basisPairInfo['forwardScale'])}" on line 195, col 33
+                    if _v is not None: write(_filter(_v, rawExpr=u"${' * '.join(basisPairInfo['forwardScale'])}")) # from line 195, col 33.
+                    write(u''';
+''')
+                for transformStep in basisPairInfo['transformSteps']: # generated from line 197, col 7
+                    needsAuxiliaryArray = True if transformStep[2] else needsAuxiliaryArray
+                    write(u'''_basis_transform->append(
+  /* transform function */ _transform_''')
+                    _v = VFFSL(SL,"transformStep",True)[0] # u'${transformStep[0]}' on line 200, col 39
+                    if _v is not None: write(_filter(_v, rawExpr=u'${transformStep[0]}')) # from line 200, col 39.
+                    write(u''',
+  /* forward? */ ''')
+                    _v = VFFSL(SL,"boolMap",True)[transformStep[1]] # u'${boolMap[transformStep[1]]}' on line 201, col 18
+                    if _v is not None: write(_filter(_v, rawExpr=u'${boolMap[transformStep[1]]}')) # from line 201, col 18.
+                    write(u''',
+  /* out-of-place? */ ''')
+                    _v = VFFSL(SL,"boolMap",True)[transformStep[2]] # u'${boolMap[transformStep[2]]}' on line 202, col 23
+                    if _v is not None: write(_filter(_v, rawExpr=u'${boolMap[transformStep[2]]}')) # from line 202, col 23.
+                    write(u''',
+  /* prefix lattice */ ''')
+                    _v = VFFSL(SL,"transformStep",True)[3] # u'${transformStep[3]}' on line 203, col 24
+                    if _v is not None: write(_filter(_v, rawExpr=u'${transformStep[3]}')) # from line 203, col 24.
+                    write(u''',
+  /* postfix lattice*/ ''')
+                    _v = VFFSL(SL,"transformStep",True)[4] # u'${transformStep[4]}' on line 204, col 24
+                    if _v is not None: write(_filter(_v, rawExpr=u'${transformStep[4]}')) # from line 204, col 24.
+                    write(u'''
+);
+''')
+                write(u'''
+_basis_transform = &_''')
+                _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 208, col 22
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 208, col 22.
+                write(u'''_basis_map[_basis_pair(''')
+                _v = ', '.join([str(self.basisIndexForBasis(basis)) for basis in reversed(basisPair)]) # u"${', '.join([str(self.basisIndexForBasis(basis)) for basis in reversed(basisPair)])}" on line 208, col 57
+                if _v is not None: write(_filter(_v, rawExpr=u"${', '.join([str(self.basisIndexForBasis(basis)) for basis in reversed(basisPair)])}")) # from line 208, col 57.
+                write(u''')];
+''')
+                if basisPairInfo['backwardScale']: # generated from line 209, col 7
+                    write(u'''_basis_transform->_multiplier = ''')
+                    _v = ' * '.join(basisPairInfo['backwardScale']) # u"${' * '.join(basisPairInfo['backwardScale'])}" on line 210, col 33
+                    if _v is not None: write(_filter(_v, rawExpr=u"${' * '.join(basisPairInfo['backwardScale'])}")) # from line 210, col 33.
+                    write(u''';
+''')
+                for transformStep in reversed(basisPairInfo['transformSteps']): # generated from line 212, col 7
+                    needsAuxiliaryArray = True if transformStep[2] else needsAuxiliaryArray
+                    write(u'''_basis_transform->append(
+  /* transform function */ _transform_''')
+                    _v = VFFSL(SL,"transformStep",True)[0] # u'${transformStep[0]}' on line 215, col 39
+                    if _v is not None: write(_filter(_v, rawExpr=u'${transformStep[0]}')) # from line 215, col 39.
+                    write(u''',
+  /* forward? */ ''')
+                    _v = VFFSL(SL,"boolMap",True)[not transformStep[1]] # u'${boolMap[not transformStep[1]]}' on line 216, col 18
+                    if _v is not None: write(_filter(_v, rawExpr=u'${boolMap[not transformStep[1]]}')) # from line 216, col 18.
+                    write(u''',
+  /* out-of-place? */ ''')
+                    _v = VFFSL(SL,"boolMap",True)[transformStep[2]] # u'${boolMap[transformStep[2]]}' on line 217, col 23
+                    if _v is not None: write(_filter(_v, rawExpr=u'${boolMap[transformStep[2]]}')) # from line 217, col 23.
+                    write(u''',
+  /* prefix lattice */ ''')
+                    _v = VFFSL(SL,"transformStep",True)[3] # u'${transformStep[3]}' on line 218, col 24
+                    if _v is not None: write(_filter(_v, rawExpr=u'${transformStep[3]}')) # from line 218, col 24.
+                    write(u''',
+  /* postfix lattice */ ''')
+                    _v = VFFSL(SL,"transformStep",True)[4] # u'${transformStep[4]}' on line 219, col 25
+                    if _v is not None: write(_filter(_v, rawExpr=u'${transformStep[4]}')) # from line 219, col 25.
+                    write(u'''
+);
+''')
+                write(u'''
+''')
+            if needsAuxiliaryArray: # generated from line 224, col 5
+                sizePrefix = '2 * ' if vector.type == 'complex' else ''
+                write(u'''_auxiliary_array_size = MAX(_auxiliary_array_size, ''')
+                _v = VFFSL(SL,"sizePrefix",True) # u'${sizePrefix}' on line 226, col 52
+                if _v is not None: write(_filter(_v, rawExpr=u'${sizePrefix}')) # from line 226, col 52.
+                _v = VFFSL(SL,"vector.allocSize",True) # u'${vector.allocSize}' on line 226, col 65
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.allocSize}')) # from line 226, col 65.
+                write(u"""); // vector '""")
+                _v = VFFSL(SL,"vector.name",True) # u'${vector.name}' on line 226, col 98
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.name}')) # from line 226, col 98.
+                write(u"""' needs an out-of-place transform
+
+""")
+        write(u'''if (_auxiliary_array_size) {
+  _auxiliary_array = (real*) xmds_malloc(sizeof(real) * _auxiliary_array_size);
+}
+
+bool _allocated_temporary_array = false;
+if (!_max_vector_array && _max_vector_size > 0) {
+  _max_vector_array = (real*) xmds_malloc(sizeof(real) * _max_vector_size);
+  _allocated_temporary_array = true;
+}
+
+// Make all geometry-dependent transformations prepare plans, etc.
+''')
+        for tID, transformation in enumerate(self.neededTransformations): # generated from line 241, col 3
+            if not transformation.get('geometryDependent', False): # generated from line 242, col 5
+                continue
+            write(u'''_transform_''')
+            _v = VFFSL(SL,"tID",True) # u'${tID}' on line 245, col 12
+            if _v is not None: write(_filter(_v, rawExpr=u'${tID}')) # from line 245, col 12.
+            write(u'''(true, 1.0, _max_vector_array, _auxiliary_array, ''')
+            _v = VFFSL(SL,"transformation",True)['prefixLatticeString'] # u"${transformation['prefixLatticeString']}" on line 245, col 67
+            if _v is not None: write(_filter(_v, rawExpr=u"${transformation['prefixLatticeString']}")) # from line 245, col 67.
+            write(u''', ''')
+            _v = VFFSL(SL,"transformation",True)['postfixLatticeString'] # u"${transformation['postfixLatticeString']}" on line 245, col 109
+            if _v is not None: write(_filter(_v, rawExpr=u"${transformation['postfixLatticeString']}")) # from line 245, col 109.
+            write(u''');
+''')
+        write(u'''
+if (_allocated_temporary_array) {
+  xmds_free(_max_vector_array);
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def mainEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def mainEnd($dict) at line 254, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''if (_auxiliary_array) {
+  xmds_free(_auxiliary_array);
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # TransformMultiplexer.tmpl
+        # 
+        # Created by Graham Dennis on 2008-12-23.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_TransformMultiplexer= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(TransformMultiplexer, '_initCheetahAttributes'):
+    templateAPIClass = getattr(TransformMultiplexer, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(TransformMultiplexer)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=TransformMultiplexer()).run()
+
+
diff --git a/xpdeint/Features/Transforms/TransformMultiplexer.tmpl b/xpdeint/Features/Transforms/TransformMultiplexer.tmpl
new file mode 100644
index 0000000..94f3c48
--- /dev/null
+++ b/xpdeint/Features/Transforms/TransformMultiplexer.tmpl
@@ -0,0 +1,260 @@
+@*
+TransformMultiplexer.tmpl
+
+Created by Graham Dennis on 2008-12-23.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features.Transforms._TransformMultiplexer
+ at def description: Transform Multiplexer
+
+ at def includes
+#include <utility>
+#include <map>
+ at end def
+
+ at def globals
+  @#
+typedef pair<ptrdiff_t, ptrdiff_t> _basis_pair;
+typedef void (*transform_function)(bool, real, real* const __restrict__, real* const __restrict__, ptrdiff_t, ptrdiff_t);
+
+// Less than operator needed by the C++ map class
+struct _basis_pair_less_than
+{
+  bool operator()(const _basis_pair& _x, const _basis_pair& _y) const {
+    return (_x.first < _y.first) || ((_x.first == _y.first) && (_x.second < _y.second));
+  }
+};
+
+struct _transform_step
+{
+  transform_function _func;
+  bool _forward;
+  bool _out_of_place;
+  ptrdiff_t _prefix_lattice;
+  ptrdiff_t _postfix_lattice;
+};
+
+// Structure to hold the basis change information
+struct _basis_transform_t
+{
+  vector<_transform_step> _transform_steps;
+  real _multiplier;
+  
+  _basis_transform_t(real _multiplier_in = 1.0) : _multiplier(_multiplier_in) {}
+  
+  _basis_transform_t(const _basis_transform_t& _b) : _transform_steps(_b._transform_steps), _multiplier(_b._multiplier) {}
+  
+  void append(transform_function _func, bool _forward, bool _out_of_place, ptrdiff_t _prefix_lattice, ptrdiff_t _postfix_lattice)
+  {
+    _transform_steps.push_back((_transform_step){_func, _forward, _out_of_place, _prefix_lattice, _postfix_lattice});
+  }
+};
+
+// Map type for holding (old_basis, new_basis) -> _basis_transform_t mappings
+typedef map<_basis_pair, _basis_transform_t, _basis_pair_less_than> _basis_map;
+
+  @for vector in self.vectorTransformMap
+_basis_map _${vector.id}_basis_map;
+  @end for
+
+real *_auxiliary_array = NULL;
+
+const char *_basis_identifiers[] = {
+  @for idx, basis in enumerate(self.basesNeeded)
+  /* ${idx} */ "(${', '.join(basis)})",
+  @end for
+};
+  @#
+ at end def
+
+ at def basisTransformFunctionContentsBegin($dict)
+@*doc:
+Returns the ``basis_transform`` function implementation for vector `vector`.
+
+This writes the function that does the fourier transforming of a specific vector
+to and from arbitrary combinations of fourier-space and normal-space.
+*@
+  @#
+  @set $function = dict['function']
+  @set $vector = dict['caller']
+  @set $transformInfo = self.vectorTransformMap[vector]
+if (_${vector.id}_basis == new_basis)
+  return;
+
+if (_${vector.id}_basis == -1) {
+  _LOG(
+    _ERROR_LOG_LEVEL,
+    "Error: Attempted to transform the vector '${vector.id}' to basis %s, but the vector doesn't have a basis specified yet!\n"
+    "       Please report this error to $bugReportAddress\n",
+    _basis_identifiers[new_basis]
+    );
+}
+
+if (_${vector.id}_basis_map.count(_basis_pair(_${vector.id}_basis, new_basis)) == 0) {
+  _LOG(
+    _ERROR_LOG_LEVEL,
+    "Error: We should have information about how to do every needed transform, but it seems we don't for this transform.\n"
+    "       The transform is for the vector '${vector.id}' from basis %s to basis %s.\n",
+    _basis_identifiers[_${vector.id}_basis], _basis_identifiers[new_basis]
+  );
+}
+_basis_transform_t &_t = _${vector.id}_basis_map[_basis_pair(_${vector.id}_basis, new_basis)];
+if (_t._transform_steps.size() == 0) {
+  _LOG(_ERROR_LOG_LEVEL, "Error: It looks like we tried to create plans for this transform, but failed.\n"
+                         "       The transform was for the vector '${vector.id}' from basis %s to basis %s.\n",
+                         _basis_identifiers[_${vector.id}_basis], _basis_identifiers[new_basis]);
+}
+real *_source_data = reinterpret_cast<real*>(_active_${vector.id});
+real *_dest_data = _auxiliary_array;
+for (vector<_transform_step>::iterator _it = _t._transform_steps.begin(); _it != _t._transform_steps.end(); ++_it) {
+  _it->_func(_it->_forward, _t._multiplier, _source_data, _dest_data, _it->_prefix_lattice, _it->_postfix_lattice);
+  if (_it->_out_of_place) {
+    real *_temp = _source_data;
+    _source_data = _dest_data;
+    _dest_data = _temp;
+  }
+}
+_${vector.id}_basis = new_basis;
+  @#
+ at end def
+
+ at def oopCopyTransformFunction(transformID, transformDict, function)
+  @#
+memcpy(_data_out, _data_in, _prefix_lattice * _postfix_lattice * sizeof(real));
+  @#
+ at end def
+
+ at def ipMultiplyTransformFunction(transformID, transformDict, function)
+  @#
+  @set featureOrdering = ['OpenMP']
+  @set featureDict = {
+    'templateString': ''
+  }
+#pragma ivdep
+${insertCodeForFeatures('loopOverVectorsWithInnerContentTemplateBegin', featureOrdering, featureDict)}@slurp
+for (long _i0 = 0; _i0 < _prefix_lattice * _postfix_lattice; _i0++) {
+  _data_in[_i0] *= _multiplier;
+}
+${insertCodeForFeaturesInReverseOrder('loopOverVectorsWithInnerContentTemplateEnd', featureOrdering, featureDict)}@slurp
+  @#
+ at end def
+
+ at def oopMultiplyTransformFunction(transformID, transformDict, function)
+  @#
+  @set featureOrdering = ['OpenMP']
+  @set featureDict = {
+    'templateString': ''
+  }
+#pragma ivdep
+${insertCodeForFeatures('loopOverVectorsWithInnerContentTemplateBegin', featureOrdering, featureDict)}@slurp
+for (long _i0 = 0; _i0 < _prefix_lattice * _postfix_lattice; _i0++) {
+  _data_out[_i0] = _data_in[_i0] * _multiplier;
+}
+${insertCodeForFeaturesInReverseOrder('loopOverVectorsWithInnerContentTemplateEnd', featureOrdering, featureDict)}@slurp
+  @#
+ at end def
+
+
+ at def mainBegin($dict)
+  @#
+
+_basis_transform_t *_basis_transform = NULL;
+ptrdiff_t _auxiliary_array_size = 0;
+ptrdiff_t _max_vector_size = 0;
+real* _max_vector_array = NULL;
+
+  @set $boolMap = {True: 'true', False: 'false'}
+  @for vector, vectorTransformInfo in self.vectorTransformMap.items()
+    @set sizePrefix = '2 * ' if vector.type == 'complex' else ''
+if (${sizePrefix}${vector.allocSize} > _max_vector_size) {
+  _max_vector_size = ${sizePrefix}${vector.allocSize};
+  _max_vector_array = reinterpret_cast<real*>(_${vector.id});
+}
+    @set $needsAuxiliaryArray = False
+    @set $bases = vectorTransformInfo['bases']
+    @set $basisPairMap = vectorTransformInfo['basisPairMap']
+    @for basisPairInfo in basisPairMap.values()
+      @set $basisPair = basisPairInfo['basisPair']
+_basis_transform = &_${vector.id}_basis_map[_basis_pair(${', '.join([str(self.basisIndexForBasis(basis)) for basis in basisPair])})];
+      @if basisPairInfo['forwardScale']
+_basis_transform->_multiplier = ${' * '.join(basisPairInfo['forwardScale'])};
+      @end if
+      @for transformStep in basisPairInfo['transformSteps']
+        @set needsAuxiliaryArray = True if transformStep[2] else needsAuxiliaryArray
+_basis_transform->append(
+  /* transform function */ _transform_${transformStep[0]},
+  /* forward? */ ${boolMap[transformStep[1]]},
+  /* out-of-place? */ ${boolMap[transformStep[2]]},
+  /* prefix lattice */ ${transformStep[3]},
+  /* postfix lattice*/ ${transformStep[4]}
+);
+      @end for
+
+_basis_transform = &_${vector.id}_basis_map[_basis_pair(${', '.join([str(self.basisIndexForBasis(basis)) for basis in reversed(basisPair)])})];
+      @if basisPairInfo['backwardScale']
+_basis_transform->_multiplier = ${' * '.join(basisPairInfo['backwardScale'])};
+      @end if
+      @for transformStep in reversed(basisPairInfo['transformSteps'])
+        @set needsAuxiliaryArray = True if transformStep[2] else needsAuxiliaryArray
+_basis_transform->append(
+  /* transform function */ _transform_${transformStep[0]},
+  /* forward? */ ${boolMap[not transformStep[1]]},
+  /* out-of-place? */ ${boolMap[transformStep[2]]},
+  /* prefix lattice */ ${transformStep[3]},
+  /* postfix lattice */ ${transformStep[4]}
+);
+      @end for
+
+    @end for
+    @if needsAuxiliaryArray
+      @set sizePrefix = '2 * ' if vector.type == 'complex' else ''
+_auxiliary_array_size = MAX(_auxiliary_array_size, ${sizePrefix}${vector.allocSize}); // vector '${vector.name}' needs an out-of-place transform
+
+    @end if
+  @end for
+if (_auxiliary_array_size) {
+  _auxiliary_array = (real*) xmds_malloc(sizeof(real) * _auxiliary_array_size);
+}
+
+bool _allocated_temporary_array = false;
+if (!_max_vector_array && _max_vector_size > 0) {
+  _max_vector_array = (real*) xmds_malloc(sizeof(real) * _max_vector_size);
+  _allocated_temporary_array = true;
+}
+
+// Make all geometry-dependent transformations prepare plans, etc.
+  @for tID, transformation in enumerate(self.neededTransformations)
+    @if not transformation.get('geometryDependent', False)
+      @continue
+    @end if
+_transform_${tID}(true, 1.0, _max_vector_array, _auxiliary_array, ${transformation['prefixLatticeString']}, ${transformation['postfixLatticeString']});
+  @end for
+
+if (_allocated_temporary_array) {
+  xmds_free(_max_vector_array);
+}
+  @#
+ at end def
+
+ at def mainEnd($dict)
+  @#
+if (_auxiliary_array) {
+  xmds_free(_auxiliary_array);
+}
+  @#
+ at end def
diff --git a/xpdeint/Features/Transforms/_FourierTransformFFTW3.py b/xpdeint/Features/Transforms/_FourierTransformFFTW3.py
new file mode 100755
index 0000000..d3fade9
--- /dev/null
+++ b/xpdeint/Features/Transforms/_FourierTransformFFTW3.py
@@ -0,0 +1,209 @@
+#!/usr/bin/env python,
+# encoding: utf-8
+"""
+_FourierTransform.py
+
+Created by Graham Dennis on 2008-07-30.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Features.Transforms._Transform import _Transform
+
+from xpdeint.Geometry.DimensionRepresentation import DimensionRepresentation
+from xpdeint.Geometry.UniformDimensionRepresentation import UniformDimensionRepresentation
+from xpdeint.Geometry.SplitUniformDimensionRepresentation import SplitUniformDimensionRepresentation
+
+from xpdeint.Utilities import lazy_property
+
+import math, operator, types
+from itertools import groupby
+
+class _FourierTransformFFTW3 (_Transform):
+  transformName = 'FourierTransform'
+  fftwSuffix = ''
+  
+  coordinateSpaceTag = DimensionRepresentation.registerTag('FFTW coordinate space', parent = 'coordinate')
+  fourierSpaceTag = DimensionRepresentation.registerTag('FFTW Fourier space', parent = 'spectral')
+  
+  def __init__(self, *args, **KWs):
+    _Transform.__init__(self, *args, **KWs)
+    self.transformNameMap = {}
+  
+  @lazy_property
+  def fftwPrefix(self):
+    precision = self.getVar('precision')
+    return {'double': 'fftw', 'single': 'fftwf'}[precision]
+  
+  @lazy_property
+  def fftwLibVersionName(self):
+      return {'fftw': 'fftw3', 'fftwf': 'fftw3f'}[self.fftwPrefix]
+  
+  @lazy_property
+  def wisdomExtension(self):
+    result = '.' + self.fftwLibVersionName
+    if self.fftwSuffix:
+      result += '_' + self.fftwSuffix
+    return result
+  
+  @lazy_property
+  def uselib(self):
+    result = [self.fftwLibVersionName]
+    if self.fftwSuffix:
+      result.append(self.fftwLibVersionName + '_' + self.fftwSuffix)
+    return result
+  
+  def newDimension(self, name, lattice, minimum, maximum,
+                   parent, transformName, aliases = set(),
+                   spectralLattice = None,
+                   type = 'real', volumePrefactor = None,
+                   xmlElement = None):
+    assert type == 'real'
+    assert transformName in ['dft', 'dct', 'dst']
+    dim = super(_FourierTransformFFTW3, self).newDimension(name, lattice, minimum, maximum,
+                                                           parent, transformName, aliases,
+                                                           type, volumePrefactor, xmlElement)
+    self.transformNameMap[dim.name] = transformName
+    if transformName == 'dft':
+      # x-space representation
+      xspace = UniformDimensionRepresentation(name = name, type = type, runtimeLattice = lattice,
+                                              _minimum = minimum, _maximum = maximum, parent = dim,
+                                              tag = self.coordinateSpaceTag,
+                                              **self.argumentsToTemplateConstructors)
+      # kspace representation
+      kspace = SplitUniformDimensionRepresentation(
+        name = 'k' + name, type = type, runtimeLattice = lattice,
+        _range = '%s - %s' % (xspace.maximum, xspace.minimum),
+        parent = dim, tag = self.fourierSpaceTag,
+        reductionMethod = SplitUniformDimensionRepresentation.ReductionMethod.fixedStep,
+        **self.argumentsToTemplateConstructors
+      )
+    else:
+      # x-space representation
+      stepSize = '((real)%(maximum)s - %(minimum)s)/(%(lattice)s)' % locals()
+      xspace = UniformDimensionRepresentation(
+        name = name, type = type, runtimeLattice = lattice,
+        _stepSize = stepSize, tag = self.coordinateSpaceTag,
+        parent = dim, **self.argumentsToTemplateConstructors
+      )
+      # Modify the minimum and maximum values to deal with the 0.5*stepSize offset
+      xspace._minimum = '%s + 0.5*%s' % (minimum, xspace.stepSize)
+      xspace._maximum = '%s + 0.5*%s' % (maximum, xspace.stepSize)
+      if transformName == 'dct':
+        # kspace representation
+        kspace = UniformDimensionRepresentation(
+          name = 'k' + name, type = type, runtimeLattice = lattice,
+          _minimum = '0.0', _stepSize = '(M_PI/(%(maximum)s - %(minimum)s))' % locals(),
+          tag = self.fourierSpaceTag,
+          reductionMethod = UniformDimensionRepresentation.ReductionMethod.fixedStep,
+          parent = dim, **self.argumentsToTemplateConstructors
+        )
+        kspace._maximum = '%s * %s' % (kspace.stepSize, kspace.globalLattice)
+      else:
+        kspace = UniformDimensionRepresentation(
+          name = 'k' + name, type = type, runtimeLattice = lattice,
+          _stepSize = '(M_PI/(%(maximum)s - %(minimum)s))' % locals(),
+          tag = self.fourierSpaceTag,
+          reductionMethod = UniformDimensionRepresentation.ReductionMethod.fixedStep,
+          parent = dim, **self.argumentsToTemplateConstructors
+        )
+        kspace._minimum = '%s' % kspace.stepSize
+        kspace._maximum = '%s * (%s + 1)' % (kspace.stepSize, kspace.globalLattice)
+    
+    dim.addRepresentation(xspace)
+    dim.addRepresentation(kspace)
+    return dim
+  
+  def r2rKindForDimensionAndDirection(self, dim, direction):
+    dimName = dim.name if not isinstance(dim, types.StringTypes) else dim
+    transformName = self.transformNameMap[dimName]
+    return {'dct': {'forward': 'FFTW_REDFT10', 'backward': 'FFTW_REDFT01'},
+            'dst': {'forward': 'FFTW_RODFT10', 'backward': 'FFTW_RODFT01'}}[transformName][direction]
+  
+  def fftCost(self, dimNames):
+    geometry = self.getVar('geometry')
+    untransformedDimReps = dict([(dimName, geometry.dimensionWithName(dimName).representations[0]) for dimName in dimNames])
+    cost = sum([int(math.ceil(math.log(untransformedDimReps[dimName].latticeEstimate))) for dimName in dimNames], 0)
+    cost *= reduce(operator.mul, [untransformedDimReps[dimName].latticeEstimate for dimName in dimNames], 1)
+    return cost
+  
+  @staticmethod
+  def scaleFactorForDimReps(dimReps):
+    return ' * '.join(['_inverse_sqrt_2pi * _d' + dimRepName for dimRepName in dimReps])
+  
+  def availableTransformations(self):
+    results = []
+    geometry = self.getVar('geometry')
+    sortedDimNames = [(geometry.indexOfDimensionName(dimName), dimName) for dimName in self.transformNameMap]
+    sortedDimNames.sort()
+    sortedDimNames = [o[1] for o in sortedDimNames]
+    
+    transformFunctions = dict(
+      geometryDependent = True,
+      transformFunction = self.transformFunction,
+    )
+    
+    for dimName in sortedDimNames:
+      dimReps = [rep for rep in geometry.dimensionWithName(dimName).representations if not rep.hasLocalOffset]
+      results.append(dict(
+        transformations = [tuple(rep.name for rep in dimReps)],
+        cost = self.fftCost([dimName]),
+        forwardScale = self.scaleFactorForDimReps([dimReps[0].name]),
+        backwardScale = self.scaleFactorForDimReps([dimReps[1].name]),
+        requiresScaling = True,
+        transformType = 'complex' if self.transformNameMap[dimName] == 'dft' else 'real',
+        **transformFunctions
+      ))
+    
+    if self.hasattr('mpiDimensions'):
+      for dim in [dim for dim in self.mpiDimensions if dim.name in sortedDimNames]:
+        sortedDimNames.remove(dim.name)
+    
+    c2cDimNames = [dimName for dimName in sortedDimNames if self.transformNameMap[dimName] == 'dft']
+    r2rDimNames = [dimName for dimName in sortedDimNames if self.transformNameMap[dimName] in ['dct', 'dst']]
+    
+    untransformedDimReps = dict([(dimName, geometry.dimensionWithName(dimName).representations[0]) for dimName in sortedDimNames])
+    transformedDimReps = dict([(dimName, geometry.dimensionWithName(dimName).representations[1]) for dimName in sortedDimNames])
+    
+    # Create optimised forward/backward transforms
+    keyFunc = lambda x: {'dft': 'complex', 'dct': 'real', 'dst': 'real'}[self.transformNameMap[x]]
+    for transformType, dimNames in groupby(sortedDimNames, keyFunc):
+      dimNames = list(dimNames)
+      if len(dimNames) <= 1: continue
+      cost = self.fftCost(dimNames)
+      untransformedBasis = tuple(untransformedDimReps[dimName].name for dimName in dimNames)
+      transformedBasis = tuple(transformedDimReps[dimName].name for dimName in dimNames)
+      bases = tuple([untransformedBasis, transformedBasis])
+      results.append(dict(
+        transformations = [bases],
+        cost = cost,
+        forwardScale = self.scaleFactorForDimReps(untransformedBasis),
+        backwardScale = self.scaleFactorForDimReps(transformedBasis),
+        requiresScaling = True,
+        transformType = transformType,
+        **transformFunctions
+      ))
+    
+    final_transforms = []
+    for transform in results:
+      final_transforms.append(transform.copy())
+      transform['outOfPlace'] = True
+      final_transforms.append(transform)
+    
+    return final_transforms
+  
+
diff --git a/xpdeint/Features/Transforms/_FourierTransformFFTW3MPI.py b/xpdeint/Features/Transforms/_FourierTransformFFTW3MPI.py
new file mode 100644
index 0000000..aa6028d
--- /dev/null
+++ b/xpdeint/Features/Transforms/_FourierTransformFFTW3MPI.py
@@ -0,0 +1,216 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_FourierTransformFFTW3MPI.py
+
+Created by Graham Dennis on 2008-06-08.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Features.Transforms.FourierTransformFFTW3 import FourierTransformFFTW3
+
+from xpdeint.ParserException import ParserException
+from xpdeint.Utilities import permutations, lazy_property
+
+import operator
+from itertools import groupby
+
+class _FourierTransformFFTW3MPI (FourierTransformFFTW3):
+  def preflight(self):
+    super(_FourierTransformFFTW3MPI, self).preflight()
+    
+    fields = self.getVar('fields')
+    geometry = self.getVar('geometry')
+    driver = self._driver
+    
+    # Check that all vectors that are distributed and need fourier transforms
+    # contain all the points in the MPI dimensions. Otherwise we can't fourier
+    # transform them.
+    for field in filter(driver.isFieldDistributed, fields):
+      # If all the distributed dimensions are the same in this field as in the geometry, then everything is OK
+      if all([field.dimensionWithName(name) == geometry.dimensionWithName(name) for name in driver.distributedDimensionNames]):
+        continue
+      for vector in [v for v in self.vectorsNeedingThisTransform if v.field == field]:
+        raise ParserException(vector.xmlElement, "Vector '%s' cannot be fourier transformed because it would be distributed with MPI "
+                                                 "and it doesn't have the same number of points as the geometry for the distributed dimensions." % vector)
+    
+    for field in [field for field in fields if not field.isDistributed]:
+      for dim in [dim for dim in field.dimensions if dim.transform == self]:
+        for rep in [rep for rep in dim.representations if rep and rep.hasLocalOffset]:
+          dim.invalidateRepresentation(rep)
+  
+  def initialiseForMPIWithDimensions(self, dimensions):
+    # We can only upgrade to MPI support if both the first and second dimensions
+    # are 'dft' or 'r2r' transforms. In the future, this restriction can be lifted
+    if len(dimensions) < 2:
+      raise ParserException(self._driver.xmlElement,
+                            "There must be at least two dimensions to use the 'distributed-mpi' with the '%s' transform." % self.transformName[dimensions[0].name])
+    if len(dimensions[0].representations) <= 1 or len(dimensions[1].representations) <= 1:
+      raise ParserException(
+        self._driver.xmlElement,
+        "To use the 'distributed-mpi' driver either the first dimension must have no transform or "
+        "the first two dimensions must both have transforms."
+      )
+    
+    self._driver.distributedDimensionNames = [dim.name for dim in dimensions[0:2]]
+    self.mpiDimensions = dimensions[0:2]
+    
+    firstMPIDimension = dimensions[0]
+    secondMPIDimension = dimensions[1]
+    # Add additional transformed representations for the swapped case.
+    for rep in firstMPIDimension.representations[:]:
+      distributedRep = rep.copy(parent = firstMPIDimension)
+      distributedRep.setHasLocalOffset('unswapped')
+      firstMPIDimension.addRepresentation(distributedRep)
+    
+    for rep in secondMPIDimension.representations[:]:
+      distributedRep = rep.copy(parent = secondMPIDimension)
+      distributedRep.setHasLocalOffset('swapped')
+      secondMPIDimension.addRepresentation(distributedRep)
+    
+  
+  def isFieldDistributed(self, field):
+    if not field:
+      return False
+    return field.hasDimension(self.mpiDimensions[0]) and field.hasDimension(self.mpiDimensions[1])
+  
+  @lazy_property
+  def hasFFTWDistributedTransforms(self):
+    geometry = self.getVar('geometry')
+    return True if self.fullTransformDimensionsForField(geometry) else False
+  
+  def fullTransformDimensionsForField(self, field):
+    keyFunc = lambda x: {'dft': 'complex', 'dct': 'real', 'dst': 'real'}.get(self.transformNameMap.get(x.name))
+    for transformType, dims in groupby(field.transverseDimensions, keyFunc):
+      return list(dims) if transformType else []
+  
+  @property
+  def vectorsNeedingDistributedTransforms(self):
+    result = set()
+    [result.update(transformationDict['vectors']) 
+      for tID, transformationDict in self.transformations if transformationDict.get('distributedTransform', False)]
+    return result
+  
+  def availableTransformations(self):
+    parent_results = super(_FourierTransformFFTW3MPI, self).availableTransformations()
+    
+    results = []
+    
+    # Create mpi forward / back operations
+    geometry = self.getVar('geometry')
+    sortedDimNames = [(geometry.indexOfDimensionName(dimName), dimName) for dimName in self.transformNameMap]
+    sortedDimNames.sort()
+    sortedDimNames = [o[1] for o in sortedDimNames]
+    
+    untransformedDimReps = dict([(dimName, geometry.dimensionWithName(dimName).firstDimRepWithTagName('coordinate')) for dimName in sortedDimNames])
+    transformedDimReps = dict([(dimName, geometry.dimensionWithName(dimName).firstDimRepWithTagName('spectral')) for dimName in sortedDimNames])
+    
+    mpiTransformDimNamesLists = []
+    fullTransformDims = self.fullTransformDimensionsForField(geometry)
+    if len(fullTransformDims) > 2:
+      mpiTransformDimNamesLists.append([dim.name for dim in fullTransformDims])
+    if len(fullTransformDims) >= 2:
+      mpiTransformDimNamesLists.append([dim.name for dim in fullTransformDims[0:2]])
+    
+    for dimNames in mpiTransformDimNamesLists:
+      untransformedBasis = tuple(untransformedDimReps[dimName].name for dimName in dimNames)
+      transformedBasis = tuple(transformedDimReps[dimName].name for dimName in dimNames)
+      transformCost = self.fftCost([dimName for dimName in dimNames])
+      communicationsCost = reduce(operator.mul, [untransformedDimReps[dimName].latticeEstimate for dimName in dimNames])
+      
+      results.append(dict(
+        transformations = [tuple([self.canonicalBasisForBasis(untransformedBasis), self.canonicalBasisForBasis(transformedBasis)])],
+        communicationsCost = communicationsCost,
+        cost = transformCost,
+        distributedTransform = True,
+        forwardScale = self.scaleFactorForDimReps(untransformedBasis),
+        backwardScale = self.scaleFactorForDimReps(transformedBasis),
+        requiresScaling = True,
+        transformType = 'complex' if self.transformNameMap[self.mpiDimensions[0].name] == 'dft' else 'real',
+        geometryDependent = True,
+        transformFunction = self.distributedTransformFunction
+      ))
+    
+    # Create transpose operations
+    transposeOperations = []
+    for firstDimRep, secondDimRep in permutations(*[[rep for rep in dim.representations if not rep.hasLocalOffset] for dim in self.mpiDimensions]):
+      communicationsCost = firstDimRep.latticeEstimate * secondDimRep.latticeEstimate
+      basisA = ('distributed ' + firstDimRep.name, secondDimRep.name)
+      basisB = ('distributed ' + secondDimRep.name, firstDimRep.name)
+      if not self.hasFFTWDistributedTransforms:
+        basisA = tuple(reversed(basisA))
+        basisB = tuple(reversed(basisB))
+      results.append(dict(
+        transformations = [tuple([basisA, basisB])],
+        communicationsCost = communicationsCost,
+        geometryDependent = True,
+        transformType = 'real',
+        distributedTransform = True,
+        transformFunction = self.transposeTransformFunction,
+        transposedOrder = not self.hasFFTWDistributedTransforms,
+      ))
+    
+    final_transforms = []
+    for transform in results:
+      final_transforms.append(transform.copy())
+      transform['outOfPlace'] = True
+      final_transforms.append(transform)
+    
+    return parent_results + final_transforms
+  
+  def canonicalBasisForBasis(self, basis, noTranspose = False):
+    if all([set(rep.canonicalName for rep in mpiDim.representations).intersection(basis) for mpiDim in self.mpiDimensions]):
+      # Decide what the order is.
+      basis = list(basis)
+      mpiDimRepNames = [rep.canonicalName for mpiDim in self.mpiDimensions for rep in mpiDim.representations if rep.canonicalName in basis]
+      mpiDimRepIndices = [basis.index(rep.canonicalName) for mpiDim in self.mpiDimensions for rep in mpiDim.representations
+                            if rep.canonicalName in basis]
+      mpiDimRepIndices.sort()
+      assert len(mpiDimRepIndices) == 2
+      assert mpiDimRepIndices[1] - mpiDimRepIndices[0] == 1
+      basisSlice = slice(mpiDimRepIndices[0], mpiDimRepIndices[1]+1)
+      
+      nonDistributedMPIDimRepNames = [b.replace('distributed ', '') for b in mpiDimRepNames]
+      
+      if (not noTranspose) and sum(b.startswith('distributed ') for b in basis[basisSlice]) == 1:
+        # Transposes are legal, and the basis is already propery distributed.
+        # Leave it alone.
+        pass
+      else:
+        if (not noTranspose) \
+            and all([any([rep.canonicalName in mpiDimRepNames
+                            for rep in mpiDim.representations if issubclass(rep.tag, rep.tagForName('spectral'))])
+                      for mpiDim in self.mpiDimensions]):
+          # Transposes are legal and all MPI dimensions are in spectral representations.
+          # We decide that this means we are swapped.
+          basis[basisSlice] = reversed(nonDistributedMPIDimRepNames)
+        else:
+          # Either transposes aren't legal or not all MPI dimensions were in spectral representation.
+          basis[basisSlice] = nonDistributedMPIDimRepNames
+        
+        distributedIdx = basisSlice.start if self.hasFFTWDistributedTransforms else basisSlice.start + 1
+        basis[distributedIdx] = 'distributed ' + basis[distributedIdx]
+      basis = tuple(basis)
+    else:
+      # At most one of the mpi dimensions is in this basis. Therefore we must ensure that no part of the basis contains 'distributed '
+      basis = tuple(b.replace('distributed ','') for b in basis)
+    
+    assert sum('distributed ' in b for b in basis) <= 1
+    return basis
+  
+
diff --git a/xpdeint/Features/Transforms/_MMT.py b/xpdeint/Features/Transforms/_MMT.py
new file mode 100755
index 0000000..50fa7bf
--- /dev/null
+++ b/xpdeint/Features/Transforms/_MMT.py
@@ -0,0 +1,365 @@
+#!/usr/bin/env python,
+# encoding: utf-8
+"""
+_MMT.py
+
+Created by Graham Dennis on 2008-12-12.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Features.Transforms._Transform import _Transform
+
+from xpdeint.Features.Transforms.BesselBasis import BesselBasis
+from xpdeint.Features.Transforms.HermiteGaussEPBasis import HermiteGaussEPBasis
+from xpdeint.Features.Transforms.HermiteGaussFourierEPBasis import HermiteGaussFourierEPBasis
+from xpdeint.Features.Transforms.HermiteGaussTwiddleBasis import HermiteGaussTwiddleBasis
+
+from xpdeint.Geometry.DimensionRepresentation import DimensionRepresentation
+from xpdeint.Geometry.UniformDimensionRepresentation import UniformDimensionRepresentation
+from xpdeint.Geometry.BesselDimensionRepresentation import BesselDimensionRepresentation
+from xpdeint.Geometry.SphericalBesselDimensionRepresentation import SphericalBesselDimensionRepresentation
+from xpdeint.Geometry.HermiteGaussDimensionRepresentation import HermiteGaussDimensionRepresentation
+
+from xpdeint.ParserException import ParserException
+
+import operator
+
+# We don't directly import mpmath so that mpmath isn't a requirement for xpdeint
+# unless you use MMT's.
+mpmath = None
+
+# Again, don't directly import numpy
+numpy = None
+
+def require_mpmath():
+  global mpmath
+  if not mpmath:
+    import mpmath
+    if not hasattr(mpmath, 'besselj'):
+      mpmath.besselj = mpmath.jn
+    mpmath.mp.prec = 64
+    
+
+def require_numpy():
+  global numpy
+  if not numpy:
+    import numpy
+
+def normalisedExtremeHermite(n, x):
+  """
+  Evaluate the normalised 'extreme' Hermite polynomial H_n(x) exp(-x^2/2)/(sqrt(n! 2^n sqrt(pi))).
+  """
+  require_numpy()
+  assert isinstance(n, int)
+  x = numpy.array(x)
+  expFactor = numpy.exp(-x*x/(2*n))
+  expFactor2 = numpy.exp(-x*x/n)
+  hermites = [None, 0.0, numpy.power(numpy.pi, -0.25) * expFactor]
+  for j in range(1, n+1):
+    hermites[:2] = hermites[1:]
+    hermites[2] = x * numpy.sqrt(2./j) * hermites[1] * expFactor \
+                  - numpy.sqrt((j-1.)/j) * hermites[0] * expFactor2
+  return hermites[2]
+
+
+def hermiteZeros(n):
+  """Return the n zeros of the nth Hermite polynomial H_n(x)."""
+  # This method works by constructing a matrix T_n such that |T_n - xI| = H_n(x)
+  # where I is the identity matrix. The matrix T_n is tridiagonal and is constructed
+  # via the recurrence relationship
+  #
+  #           b p (x) = (x - a ) p   (x) - b   p   (x)
+  #            j j            j   j-1       j-1 j-2
+  #
+  # The constructed matrix has a_j on the diagonal and sqrt(b_j) on the two neighbouring diagonals.
+  #
+  # The recurrence relationship for H_n(x) has a_n = 0 and b_n = sqrt(n/2).
+  # To improve the accuracy and speed of the calculation of the roots we note that the roots are symmetric
+  # about zero and the Hermite functions can be written as
+  #
+  #                          2
+  #            H (x) = J   (x ) for even x, and 
+  #             n       n/2
+  #
+  #                                2
+  #            H (x) = x K       (x ) for odd x.
+  #             n         (n-1)/2
+  #
+  # For even n, the recurrence relation for J_n is defined by a_n = 2n - 3/2, b_n = sqrt( n (n - 1/2) ).
+  # For odd n, the recurrence relation for K_n is defined by a_n = 2n - 1/2, b_n = sqrt( n (n + 1/2) ).
+  
+  require_numpy()
+  assert isinstance(n, int)
+  positiveRoots = n//2
+  if (n & 1) == 0:
+    # n is even
+    a = 2*numpy.arange(1, positiveRoots + 1) - 1.5
+    b = numpy.sqrt(numpy.arange(1, positiveRoots) * (numpy.arange(1, positiveRoots) - 0.5))
+  else:
+    # n is odd
+    a = 2*numpy.arange(1, positiveRoots + 1) - 0.5
+    b = numpy.sqrt(numpy.arange(1, positiveRoots) * (numpy.arange(1, positiveRoots) + 0.5))
+  nproots = numpy.sqrt(numpy.linalg.eigvalsh(numpy.diag(a) + numpy.diag(b, -1)))
+  roots = list(nproots)
+  # Add the negative roots
+  roots.extend(-nproots)
+  # if n is odd, add zero as a root
+  if (n & 1) == 1: roots.append(0.0)
+  roots.sort()
+  # Convert back to python float format for storage.
+  return map(float, roots)
+
+def hermiteGaussWeightsFromZeros(n, roots):
+  assert isinstance(n, int)
+  require_numpy()
+  roots = numpy.array(roots)
+  weights = numpy.exp(-roots*roots/(n-1)) / (n * normalisedExtremeHermite(n-1, roots) ** 2)
+  # Convert back to python float format for storage
+  return map(float, weights)
+
+
+def besselJZeros(m, a, b):
+  require_mpmath()
+  if not hasattr(mpmath, 'besseljzero'):
+    besseljn = lambda x: mpmath.besselj(m, x)
+    results = [mpmath.findroot(besseljn, mpmath.pi*(kp - 1./4 + 0.5*m)) for kp in range(a, b+1)]
+  else:
+    results = [mpmath.besseljzero(m, i) for i in xrange(a, b+1)]
+  # Check that we haven't found double roots or missed a root. All roots should be separated by approximately pi
+  assert all([0.6*mpmath.pi < (b - a) < 1.4*mpmath.pi for a, b in zip(results[:-1], results[1:])]), "Separation of Bessel zeros was incorrect."
+  return results
+
+class _MMT (_Transform):
+  transformName = 'MMT'
+  
+  coordinateSpaceTag = DimensionRepresentation.registerTag('MMT coordinate space', parent = 'coordinate')
+  spectralSpaceTag = DimensionRepresentation.registerTag('MMT spectral space', parent = 'spectral')
+  auxiliarySpaceTag = DimensionRepresentation.registerTag('MMT auxiliary space', parent = 'auxiliary')
+  
+  def __init__(self, *args, **KWs):
+    _Transform.__init__(self, *args, **KWs)
+    self.basisMap = {}
+    dataCache = self.getVar('dataCache')
+    
+    self.besselJZeroCache = dataCache.setdefault('besselJZeros', {})
+    self.hermiteCache = dataCache.setdefault('hermiteGauss', {})
+  
+  @property
+  def children(self):
+    children = super(_MMT, self).children
+    [children.extend(basisDict['transformations'].values()) for basisDict in self.basisMap.values()]
+    return children
+  
+  def globals(self):
+    return '\n'.join([basisDict.get('globalsFunction')(dimName, basisDict) \
+                          for dimName, basisDict in self.basisMap.items() if basisDict.get('globalsFunction')])
+  
+  def newDimension(self, name, lattice, minimum, maximum,
+                   parent, transformName, aliases = set(),
+                   spectralLattice = None,
+                   type = 'real', volumePrefactor = None,
+                   xmlElement = None):
+    assert type == 'real'
+    assert transformName in ['bessel', 'spherical-bessel', 'hermite-gauss']
+    if not spectralLattice:
+      spectralLattice = lattice
+    dim = super(_MMT, self).newDimension(name, max(lattice, spectralLattice), minimum, maximum,
+                                         parent, transformName, aliases, 
+                                         type, volumePrefactor, xmlElement)
+    self.basisMap[dim.name] = transformName # Needs to be constructed basis here
+    
+    if transformName in ('bessel', 'spherical-bessel'):
+      # Bessel functions
+      order = 0
+      if xmlElement.hasAttribute('order'):
+        features = self.getVar('features')
+        orderString = xmlElement.getAttribute('order')
+        try:
+          order = int(orderString)
+        except ValueError:
+          raise ParserException(xmlElement, "Cannot understand '%s' as a meaningful order. "
+                                            "Order values must be non-negative integers." \
+                                            % xmlElement.getAttribute('order'))
+        else:
+          if order < 0:
+            raise ParserException(xmlElement, "The 'order' attribute for Bessel transforms must be non-negative integers.")
+      orderOffset = 0
+      dimRepClass = BesselDimensionRepresentation
+      
+      if transformName == 'spherical-bessel':
+        dimRepClass = SphericalBesselDimensionRepresentation
+        if not self.hasattr('uselib'):
+          self.uselib = []
+        self.uselib.append('gsl')
+        orderOffset = 0.5
+      
+      self.basisMap[dim.name] = dict(
+        globalsFunction = self.besselGlobalsForDim,
+        order = order,
+        orderOffset = orderOffset,
+        lattice = lattice,
+        transformations = dict([
+          ((name, 'k' + name), BesselBasis(parent = self, **self.argumentsToTemplateConstructors))
+        ])
+      )
+      
+      if not float(minimum) == 0.0:
+        raise ParserException(xmlElement, "The domain for Bessel transform dimensions must begin at 0.")
+      
+      # Real space representation
+      xspace = dimRepClass(name = name, type = type, runtimeLattice = lattice,
+                           stepSizeArray = True, parent = dim,
+                           tag = self.coordinateSpaceTag,
+                           _maximum = maximum, _order = order,
+                           **self.argumentsToTemplateConstructors)
+      dim.addRepresentation(xspace)
+      
+      # Spectral space representation
+      kspace = dimRepClass(name = 'k' + name, type = type, runtimeLattice = spectralLattice,
+                           stepSizeArray = True, parent = dim,
+                           _maximum = '(_besseljnorm_%(name)s/((real)%(maximum)s))' % locals(),
+                           _order = order,
+                           reductionMethod = dimRepClass.ReductionMethod.fixedStep,
+                           tag = self.spectralSpaceTag,
+                           **self.argumentsToTemplateConstructors)
+      dim.addRepresentation(kspace)
+      
+    elif transformName == 'hermite-gauss':
+      # Hermite-gauss basis (harmonic oscillator)
+      coordinate2SpectralBasisChange = HermiteGaussEPBasis(parent = self, **self.argumentsToTemplateConstructors)
+      spectralBasisTwiddleChange = HermiteGaussTwiddleBasis(parent = self, **self.argumentsToTemplateConstructors)
+      # This is how we used to do 'nx' -> 'kx' transforms
+      fourier2SpectralBasisChange = HermiteGaussFourierEPBasis(parent = self, **self.argumentsToTemplateConstructors)
+      
+      self.basisMap[dim.name] = dict(
+        globalsFunction = self.hermiteGaussGlobalsForDim,
+        lattice = lattice,
+        transformations = dict([
+          ((name, 'n' + name), coordinate2SpectralBasisChange),
+          ((name + '_4f', 'n' + name), coordinate2SpectralBasisChange),
+          (('k' + name, 'n' + name + '_twiddle'), coordinate2SpectralBasisChange),
+          (('n' + name, 'n' + name + '_twiddle'), spectralBasisTwiddleChange),
+          # This is how the 'nx' -> 'kx' transforms used to be done, but it's slower.
+          # This transform should never be chosen because the cost estimates should prevent it, but we keep it here
+          # anyway for reference.
+          (('k' + name, 'n' + name), fourier2SpectralBasisChange)
+        ])
+      )
+      
+      if not float(minimum) == 0.0:
+        raise ParserException(xmlElement, "For 'hermite-gauss' transformed dimensions, use the 'length_scale' attribute "
+                                          "instead of 'domain'.")
+      
+      # Real space representation
+      xspace = HermiteGaussDimensionRepresentation(
+        name = name, type = type, runtimeLattice = lattice, _maximum = maximum,
+        stepSizeArray = True, parent = dim, tag = self.coordinateSpaceTag,
+        **self.argumentsToTemplateConstructors
+      )
+      dim.addRepresentation(xspace)
+      
+      # Spectral space representation
+      nspace = UniformDimensionRepresentation(
+        name = 'n' + name, type = 'long', runtimeLattice = spectralLattice,
+        _minimum = '0', _maximum = spectralLattice, _stepSize = '1',
+        parent = dim, tag = self.spectralSpaceTag,
+        reductionMethod = UniformDimensionRepresentation.ReductionMethod.fixedStep,
+        **self.argumentsToTemplateConstructors
+      )
+      dim.addRepresentation(nspace)
+      
+      # Fourier space representation
+      # FIXME: We may want to make this have a fixedStep ReductionMethod, but that requires support from
+      # the DimRep and from FourierTransformFFTW3MPI in the case that this dimension is distributed.
+      kspace = HermiteGaussDimensionRepresentation(
+        name = 'k' + name, type = type, runtimeLattice = lattice, _maximum = "(1.0 / (%s))" % maximum,
+        stepSizeArray = True, parent = dim, tag = self.auxiliarySpaceTag,
+        **self.argumentsToTemplateConstructors
+      )
+      dim.addRepresentation(kspace)
+      
+      twiddleSpace = UniformDimensionRepresentation(
+          name = 'n' + name + '_twiddle', type = 'long', runtimeLattice = spectralLattice,
+          _minimum = '0', _maximum = spectralLattice, _stepSize = '1',
+          parent = dim, tag = self.auxiliarySpaceTag,
+          reductionMethod = UniformDimensionRepresentation.ReductionMethod.fixedStep,
+          **self.argumentsToTemplateConstructors
+      )
+      dim.addRepresentation(twiddleSpace)
+      
+      fourFieldCoordinateSpace = HermiteGaussDimensionRepresentation(
+        name = name + '_4f', type = type, runtimeLattice = lattice, _maximum = maximum,
+        stepSizeArray = True, parent = dim, tag = self.auxiliarySpaceTag, fieldCount = 4.0,
+        **self.argumentsToTemplateConstructors
+      )
+      dim.addRepresentation(fourFieldCoordinateSpace)
+    return dim
+  
+  def availableTransformations(self):
+    results = []
+    geometry = self.getVar('geometry')
+    # Sort dimension names based on their ordering in the geometry.
+    sortedDimNames = [(geometry.indexOfDimensionName(dimName), dimName) for dimName in self.basisMap]
+    sortedDimNames.sort()
+    sortedDimNames = [o[1] for o in sortedDimNames]
+    # Create all transforms just for each dimension individually
+    for dimName, basisDict in self.basisMap.items():
+      dimReps = geometry.dimensionWithName(dimName).representations
+      for transformPair, basis in basisDict['transformations'].items():
+        basisReps = [[rep for rep in dimReps if rep.name == repName][0] for repName in transformPair]
+        def addTransform(outOfPlace):
+          results.append(dict(
+            transformations = [transformPair],
+            cost = basis.costEstimate(basisReps),
+            outOfPlace = outOfPlace,
+            transformFunction = basis.transformFunction,
+            transformType = basis.matrixType,
+          ))
+        addTransform(True)
+        if basis.supportsInPlaceOperation:
+            addTransform(False)
+    
+    return results
+  
+  def besselJZeros(self, m, k):
+    if not m in self.besselJZeroCache:
+      self.besselJZeroCache[m] = besselJZeros(m, 1, k)
+    else:
+      if len(self.besselJZeroCache[m]) < k:
+        self.besselJZeroCache[m].extend(besselJZeros(m, len(self.besselJZeroCache[m])+1, k))
+    
+    return self.besselJZeroCache[m][:k]
+  
+  def normalisedBesselJZeros(self, m, k):
+    zeros = self.besselJZeros(m, k+1)
+    norm = zeros[-1]
+    return [zero/norm for zero in zeros[:-1]]
+  
+  def hermiteZeros(self, n):
+    zerosCache = self.hermiteCache.setdefault('zeros',{})
+    if not n in zerosCache:
+      zerosCache[n] = hermiteZeros(n)
+    return zerosCache[n]
+  
+  def hermiteGaussWeights(self, n):
+    weightsCache = self.hermiteCache.setdefault('weights',{})
+    if not n in weightsCache:
+      weightsCache[n] = hermiteGaussWeightsFromZeros(n, self.hermiteZeros(n))
+    return weightsCache[n]
+  
+
diff --git a/xpdeint/Features/Transforms/_NoTransform.py b/xpdeint/Features/Transforms/_NoTransform.py
new file mode 100755
index 0000000..7089f58
--- /dev/null
+++ b/xpdeint/Features/Transforms/_NoTransform.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_NoTransform.py
+
+Created by Graham Dennis on 2008-07-30.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Features.Transforms._Transform import _Transform
+
+from xpdeint.Geometry.UniformDimensionRepresentation import UniformDimensionRepresentation
+
+class _NoTransform (_Transform):
+  transformName = 'NoTransform'
+  
+  dimRepTag = UniformDimensionRepresentation.registerTag('No transform', parent = 'coordinate')
+  
+  def __init__(self, *args, **KWs):
+    _Transform.__init__(self, *args, **KWs)
+  
+  def newDimension(self, name, lattice, minimum, maximum,
+                   parent, transformName, aliases = set(),
+                   type = 'real', spectralLattice = None, volumePrefactor = None,
+                   xmlElement = None):
+    assert transformName == 'none'
+    dim = super(_NoTransform, self).newDimension(name, lattice, minimum, maximum,
+                                                 parent, transformName, aliases,
+                                                 type, volumePrefactor, xmlElement)
+    if type == 'long':
+      stepSize = '1'
+    else:
+      stepSize = None
+    rep = UniformDimensionRepresentation(
+      name = name, type = type, runtimeLattice = lattice,
+      _minimum = minimum, _maximum = maximum, _stepSize = stepSize, parent = dim,
+      tag = self.dimRepTag, reductionMethod = UniformDimensionRepresentation.ReductionMethod.fixedRange,
+      **self.argumentsToTemplateConstructors
+    )
+    dim.addRepresentation(rep)
+    return dim
+  
+
diff --git a/xpdeint/Features/Transforms/_NoTransformMPI.py b/xpdeint/Features/Transforms/_NoTransformMPI.py
new file mode 100644
index 0000000..7f83c63
--- /dev/null
+++ b/xpdeint/Features/Transforms/_NoTransformMPI.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_NoTransformMPI.py
+
+Created by Graham Dennis on 2008-08-24.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Features.Transforms._NoTransform import _NoTransform
+
+class _NoTransformMPI (_NoTransform):
+  def initialiseForMPIWithDimensions(self, dimensions):
+    dimensions[0].representations[0].setHasLocalOffset()
+    self.mpiDimension = dimensions[0]
+    self._driver.distributedDimensionNames.append(self.mpiDimension.name)
+  
+  def isFieldDistributed(self, field):
+    return field.hasDimension(self.mpiDimension)
+  
+  def canonicalBasisForBasis(self, basis, **KWs):
+    mpiDimRep = self.mpiDimension.representations[0]
+    mpiDimNames = set([mpiDimRep.name, mpiDimRep.canonicalName])
+    if mpiDimNames.intersection(basis):
+      basis = list(basis)
+      for idx, b in enumerate(basis[:]):
+        if b in mpiDimNames:
+          basis[idx] = mpiDimRep.canonicalName
+          break
+      basis = tuple(basis)
+    return basis
+  
+
diff --git a/xpdeint/Features/Transforms/_Transform.py b/xpdeint/Features/Transforms/_Transform.py
new file mode 100755
index 0000000..8df6bcf
--- /dev/null
+++ b/xpdeint/Features/Transforms/_Transform.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_Transform.py
+
+Created by Graham Dennis on 2008-07-30.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.ScriptElement import ScriptElement
+from xpdeint.Geometry._Dimension import _Dimension
+from xpdeint.Utilities import lazy_property
+
+class _Transform (ScriptElement):
+  mpiCapableSubclass = None
+  
+  def __init__(self, *args, **KWs):
+    ScriptElement.__init__(self, *args, **KWs)
+    # Register ourselves with the transform multiplexer
+    self.getVar('features')['TransformMultiplexer'].transforms.add(self)
+    self.transformations = []
+  
+  def __hash__(self):
+    """
+    Returns a hash of the transform.
+    This is used to ensure the ordering of transforms in sets remains the same between invocations.
+    """
+    return hash(self.transformName)
+  
+  @lazy_property
+  def isMPICapable(self):
+    return bool(self.mpiCapableSubclass)
+  
+  @property
+  def vectorsNeedingThisTransform(self):
+    vectors = set()
+    for f in self.getVar('fields'): vectors.update(f.vectors)
+    return set([v for v in vectors if v.needsTransforms and any([d.transform == self for d in v.field.dimensions])])
+  
+  def initialiseForMPIWithDimensions(self, dimensions):
+    """Upgrade the current class to support MPI."""
+    assert self.isMPICapable
+    assert not self.__class__ == self.mpiCapableSubclass
+    self.__class__ = self.mpiCapableSubclass
+    self._driver.distributedTransform = self
+    # MPI subclass must define this method
+    self.initialiseForMPIWithDimensions(dimensions)
+  
+  def newDimension(self, name, lattice, minimum, maximum,
+                   parent, transformName, aliases = set(),
+                   type = 'real', volumePrefactor = None, xmlElement = None):
+    dim = _Dimension(name = name, transform = self, aliases = aliases, volumePrefactor = volumePrefactor,
+                     parent = parent, xmlElement = xmlElement,
+                     **self.argumentsToTemplateConstructors)
+    return dim
+  
+  def setVectorAllocSizes(self, vectors):
+    return ''
+  
+
diff --git a/xpdeint/Features/Transforms/_TransformMultiplexer.py b/xpdeint/Features/Transforms/_TransformMultiplexer.py
new file mode 100644
index 0000000..2a65096
--- /dev/null
+++ b/xpdeint/Features/Transforms/_TransformMultiplexer.py
@@ -0,0 +1,517 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_TransformMultiplexer.py
+
+Created by Graham Dennis on 2008-12-23.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Features._Feature import _Feature
+from xpdeint.Utilities import combinations, GeneralisedBidirectionalSearch
+from xpdeint.Function import Function
+from xpdeint.Vectors.VectorElement import VectorElement
+from xpdeint.ParserException import ParserException
+
+import operator
+
+class _TransformMultiplexer (_Feature):
+  featureName = 'TransformMultiplexer'
+  transformClasses = dict()
+  
+  def __init__(self, *args, **KWs):
+    _Feature.__init__(self, *args, **KWs)
+    self.transforms = set()
+    self.availableTransformations = []
+    self.neededTransformations = []
+    self.transformations = []
+  
+  def transformWithName(self, name):
+    if not name in self.transformClasses:
+      return None
+    cls = self.transformClasses[name]
+    transformWithClass = [t for t in self.transforms if isinstance(t, cls)]
+    assert 0 <= len(transformWithClass) <= 1
+    if transformWithClass:
+      return transformWithClass[0]
+    else:
+      return cls(parent = self.simulation, **self.argumentsToTemplateConstructors)
+  
+  def __getattribute__(self, name):
+    """
+    Call through to all methods on the child transforms. This should only be used for
+    the 'insertCodeForFeatures' functions. We don't want this to happen for 'includes', etc.
+    This is prevented from occuring because all of these methods are defined on `_ScriptElement`.
+    """
+    # As we are customising attribute access in this method, attempts to access attributes directly
+    # would lead to infinite recursion (bad), so we must access variables specially
+    
+    # If the attribute isn't one that we are doing a special proxy for, then it perform as per usual.
+    if not name in ['mainBegin', 'mainEnd']:
+      return _Feature.__getattribute__(self, name)
+    
+    attributes = []
+    # If we have the attribute, then we go first
+    try:
+      attributes.append(_Feature.__getattribute__(self, name))
+    except AttributeError:
+      pass
+    
+    # Then we add any child attributes
+    transforms = _Feature.__getattribute__(self, 'transforms')
+    attributes.extend([getattr(t, name) for t in transforms if t.hasattr(name)])
+    
+    # If neither ourself nor any of our children have this attribute, then we need to raise an AttributeError
+    # the easiest way to do this is to just call the default implementation which will do this.
+    # We want to do the same thing 
+    if not attributes or not all([callable(attr) for attr in attributes]):
+      return _Feature.__getattribute__(self, name)
+    
+    # If there's only one, we don't need to multiplex.
+    if len(attributes) == 1:
+      return attributes[0]
+    
+    # Create a multiplexing function and return it.
+    def multiplexingFunction(*args, **KWs):
+      results = [attr(*args, **KWs) for attr in attributes]
+      if name == 'mainBegin':
+        results.reverse()
+      return ''.join([result for result in results if result is not None])
+    
+    return multiplexingFunction
+  
+  def preflight(self):
+    super(_TransformMultiplexer, self).preflight()
+    for transform in self.transforms:
+      if hasattr(transform, 'availableTransformations'):
+        for transformation in transform.availableTransformations():
+          transformation.setdefault('owner', transform)
+          self.availableTransformations.append(transformation)
+    # We need to add a few transforms of our own.
+    
+    # Out-of-place copy
+    self.oopCopy = dict(
+      owner = self,
+      transformations = [tuple()],
+      cost = 1,
+      outOfPlace = True,
+      transformFunction = self.oopCopyTransformFunction,
+      description = 'Out-of-place copy',
+    )
+    self.availableTransformations.append(self.oopCopy)
+    
+    # In-place multiply
+    self.ipMultiply = dict(
+      owner = self,
+      transformations = [tuple()],
+      cost = 1,
+      scaling = True,
+      transformFunction = self.ipMultiplyTransformFunction,
+      description = 'In-place multiply',
+    )
+    
+    # Out-of-place multiply
+    self.oopMultiply = dict(
+      owner = self,
+      transformations = [tuple()],
+      cost = 2,
+      outOfPlace = True,
+      scaling = True,
+      transformFunction = self.oopMultiplyTransformFunction,
+      description = 'Out-of-place multiply',
+    )
+  
+  def buildTransformMap(self):
+    # The mighty plan is to do the following for each vector:
+    # 1. Convert all required spaces to the new-style spaces
+    
+    def transformedBasis(basis, transformationPair):
+      """
+      This function determines if `basis` can be transformed by the transform represented
+      by `transformPair`. If `basis` can be transformed, then it returns the transformed basis,
+      the matched part of the basis, and the components of the basis before and after the match.
+      """
+      if not transformationPair: return basis, (basis, tuple(), tuple())
+      
+      if not isinstance(basis, tuple): basis = tuple([basis])
+      for sourceBasis, destBasis in [transformationPair, reversed(transformationPair)]:
+        # Optimisation: If it's just a single-dimension transform, do it the fast way
+        if not isinstance(sourceBasis, tuple):
+          if not sourceBasis in basis: continue
+          basis = list(basis)
+          offset = basis.index(sourceBasis)
+          basis[offset] = destBasis
+          basis = tuple(basis)
+          return basis, (basis[:offset], tuple([sourceBasis]), basis[offset+1:])
+        
+        for offset in range(0, len(basis)+1-len(sourceBasis)):
+          if basis[offset:offset+len(sourceBasis)] == sourceBasis:
+            basis = list(basis)
+            basis[offset:offset+len(sourceBasis)] = destBasis
+            basis = tuple(basis)
+            return basis, (basis[:offset], sourceBasis, basis[offset+len(sourceBasis):])
+      return None, (None, None, None)
+    
+    class BasisState(GeneralisedBidirectionalSearch.State):
+      """
+      This class represents a node in the transform graph. This node specifies
+      both the current basis and also whether the data for the vector being
+      transformed is currently 'in-place' (the data is stored in the same location
+      as it was originally) or 'out-of-place' (the data is stored in a different location).
+      This distinction is necessary as transforms such as matrix multiplication transforms
+      necessitate an out-of-place operation, but overall, we require the data after the 
+      complete transform to be back where it was to start with.
+      """
+      __slots__ = []
+      availableTransformations = self.availableTransformations
+      
+      IN_PLACE = 0
+      OUT_OF_PLACE = 1
+      
+      def next(self):
+        """
+        This function returns the next nodes in the transform graph that can be reached from this node.
+        
+        It iterates through all available transforms trying to find matches that can transform the current
+        basis and determines the cost of doing so.
+        """
+        results = []
+        
+        currentBasis, currentState = self.location
+        
+        # Loop through all available transforms
+        for transformID, transformation in enumerate(self.availableTransformations):
+          # Loop through all basis-changes this 'transform' can handle
+          for transformationPair in transformation['transformations']:
+            # Does the transformPair match?
+            resultBasis, (prefixBasis, matchedSourceBasis, postfixBasis) = transformedBasis(currentBasis, transformationPair)
+            if not resultBasis: continue
+            
+            # The cost specified in the transform is per-point in dimensions not listed in the transformationPair
+            # So we must multiply that cost by the product of the number of points in all other dimensions
+            
+            costMultiplier = reduce(
+              operator.mul,
+              [self.representationMap[repName].latticeEstimate \
+                for repName in currentBasis if not repName in matchedSourceBasis],
+              1
+            )
+            
+            newCost = list(self.cost)
+            
+            # This transformation may change the state and/or the basis.
+            # Here we consider state changes like in-place <--> out-of-place
+            # and multiplying the data by a constant
+            resultState = currentState
+            if transformation.get('outOfPlace', False):
+              resultState = {
+                BasisState.IN_PLACE: BasisState.OUT_OF_PLACE,
+                BasisState.OUT_OF_PLACE: BasisState.IN_PLACE
+              }[currentState]
+              
+              # Now you might think that we're violating the cost >= 0 requirement here
+              # where we use the negative of the number of out-of-place operations.
+              # While that would be true if this was the only part of the cost, it
+              # isn't the whole thing. Both 'communicationsCost' and 'cost' occur before
+              # this term, and 'cost' is guaranteed to be positive.
+              #
+              # It is the negative number of out-of-place operations we use here as
+              # FFTW is faster for out-of-place operations than in-place operations for
+              # typical transform sizes
+              newCost[3] -= 1 # Minus the number of out-of-place operations
+            
+            # Multiply the costMultiplier through the cost listed by the transform
+            newCost[0:2] = [costMultiplier * transformation.get(key, 0) for key in ['communicationsCost', 'cost']]
+            newCost[2] += 1 # Number of steps
+            # Add that cost to the old cost
+            newCost = tuple(old + new for old, new in zip(self.cost, newCost))
+            
+            # Create the new BasisState and add it to the list of nodes reachable from this node.
+            newState = BasisState(
+              newCost,
+              (resultBasis, resultState),
+              self.source,
+              previous = self.location,
+              transformation = (transformID, transformationPair)
+            )
+            results.append(newState)
+        return results
+      
+    def pathFromBasisToBasis(start, endID, pathInfo):
+      """
+      Given a dictionary of shortest paths provided by a GeneralisedBidirectional search, determine
+      the actual path that connects the basis `start` and the basis `end`.
+      """
+      # Final state must be net in-place.
+      # But we may or may not need scaling
+      loc = start
+      path = [loc]
+      
+      while loc:
+        path.append(pathInfo[loc].transformations[endID])
+        path.append(pathInfo[loc].next[endID])
+        loc = pathInfo[loc].next[endID]
+      
+      path = path[:-2]
+      
+      return path
+    
+    def printBasis(basis):
+      if isinstance(basis, basestring): return basis
+      elif len(basis) == 1:
+        return basis[0] if isinstance(basis[0], basestring) else basis[0].canonicalName
+      else:
+        return '(' + ', '.join(dimRep if isinstance(dimRep, basestring) else dimRep.canonicalName for dimRep in basis) + ')'
+    
+    
+    geometry = self.getVar('geometry')
+    representationMap = dict()
+    representationMap.update((rep.canonicalName, rep) for dim in geometry.dimensions for rep in dim.representations)
+    distributedRepresentations = [rep for dim in geometry.dimensions for rep in dim.representations if rep.hasLocalOffset]
+    BasisState.representationMap = representationMap
+    
+    def basisToDimRepBasis(repNameBasis):
+      if not isinstance(repNameBasis, tuple):
+        repNameBasis = tuple([repNameBasis])
+      return tuple(representationMap[dimRepName] for dimRepName in repNameBasis)
+    
+    vectors = set([v for v in self.getVar('templates') if isinstance(v, VectorElement) and v.needsTransforms])
+    
+    driver = self._driver
+    transformMap = dict()
+    
+    basesFieldMap = dict()
+    for vector in vectors:
+      vectorBases = vector.basesNeeded.copy()
+      if not vector.field.name in basesFieldMap:
+        basesFieldMap[vector.field.name] = set()
+      basesFieldMap[vector.field.name].update(vectorBases)
+    
+    # Next step: Perform Dijkstra search over the provided transforms to find the optimal transform map.
+    for basesNeeded in basesFieldMap.values():
+      targetStates = [BasisState( (0, 0, 0, 0), (basis, BasisState.IN_PLACE), sourceID) for sourceID, basis in enumerate(basesNeeded)]
+      targetLocations = [state.location for state in targetStates]
+      pathInfo = GeneralisedBidirectionalSearch.perform(targetStates)
+      for sourceLoc, targetLoc in combinations(2, targetLocations):
+        path = pathFromBasisToBasis(sourceLoc, targetLocations.index(targetLoc), pathInfo)
+        # While we now have the paths and we have them quickly, we just need to add the scaling operations
+        # where and if needed.
+        
+        transformMap[frozenset([sourceLoc[0], targetLoc[0]])] = path
+    
+    self.availableTransformations.append(self.ipMultiply)
+    ipMultiplyID = self.availableTransformations.index(self.ipMultiply)
+    self.availableTransformations.append(self.oopMultiply)
+    oopMultiplyID = self.availableTransformations.index(self.oopMultiply)
+    
+    for basisPair, path in transformMap.items():
+      if any([self.availableTransformations[transformID].get('requiresScaling', False) for transformID, transformPair in path[1::2]]):
+        # Scaling is needed.
+        # There are different strategies for dealing with this.
+        # A good method would be to modify a matrix transform if we can get away with it, but that's an advanced optimisation
+        # that will be considered later.
+        # A simple optimisation is to use an out-of-place multiply instead of an out-of-place copy
+        if self.oopCopy in path:
+          # Change an out-of-place copy to an out-of-place multiply if we have one
+          path[path.index(self.oopCopy)] = (oopMultiplyID, ())
+        else:
+          # Add an in-place multiply at the end
+          path.extend([(ipMultiplyID, ()), path[-1]])
+    
+    self.vectorTransformMap = dict()
+    transformsNeeded = list()
+    basesNeeded = set()
+    
+    prefixLatticeStringMap = dict()
+    postfixLatticeStringMap = dict()
+    
+    delayedException = None
+    
+    for vector in vectors:
+      basesNeeded.update(vector.basesNeeded)
+      vectorBases = list(vector.basesNeeded)
+      vectorBases.sort()
+      self.vectorTransformMap[vector] = dict(
+        bases = vectorBases,
+        basisPairMap = dict(),
+      )
+      vector.transformMap = self.vectorTransformMap[vector]
+      
+      for basisPair in combinations(2, vectorBases):
+        basisPairSet = frozenset(basisPair)
+        path = transformMap[basisPairSet]
+        
+        basisPair = (path[0][0], path[-1][0])
+        
+        basisPairInfo = dict(
+          basisPair = basisPair,
+          forwardScale = [],
+          backwardScale = [],
+        )
+        self.vectorTransformMap[vector]['basisPairMap'][basisPairSet] = basisPairInfo
+        
+        transformSteps = []
+        
+        for (currentBasis, basisState), (transformID, transformPair) in zip(path[:-2:2], path[1::2]):
+          # The transform may decide that different actions of the same transform
+          # should be considered different transformations
+          # (think FFT's with different numbers of points not in the FFT dimension)
+          geometrySpecification = None
+          transformation = self.availableTransformations[transformID]
+          transformation.setdefault('vectors', set()).add(vector)
+          
+          resultBasis, (prefixBasis, matchedSourceBasis, postfixBasis) = transformedBasis(currentBasis, transformPair)
+          forward = True
+          if transformPair:
+            sourceBasis = transformPair[0]
+            if not isinstance(sourceBasis, tuple): sourceBasis = tuple([sourceBasis])
+            forward = True if sourceBasis == matchedSourceBasis else False
+          
+          if 'requiresScaling' in transformation:
+            forwardScale, backwardScale = transformation['forwardScale'], transformation['backwardScale']
+            if not forward:
+              forwardScale, backwardScale = backwardScale, forwardScale
+            basisPairInfo['forwardScale'].append(forwardScale)
+            basisPairInfo['backwardScale'].append(backwardScale)
+          
+          prefixDimReps = basisToDimRepBasis(prefixBasis)
+          postfixDimReps = basisToDimRepBasis(postfixBasis)
+          
+          runtimePrefixDimensions = tuple([dimRep.localLattice for dimRep in prefixDimReps if dimRep.hasLocalOffset or isinstance(dimRep.runtimeLattice, basestring)])
+          runtimePostfixDimensions = tuple([dimRep.localLattice for dimRep in postfixDimReps if dimRep.hasLocalOffset or isinstance(dimRep.runtimeLattice, basestring)])
+          
+          prefixLattice = [(dimRep.latticeEstimate, dimRep.localLattice) for dimRep in prefixDimReps if not (dimRep.hasLocalOffset or isinstance(dimRep.runtimeLattice, basestring))]
+          
+          postfixLattice = [(dimRep.latticeEstimate, dimRep.localLattice) for dimRep in postfixDimReps if not (dimRep.hasLocalOffset or isinstance(dimRep.runtimeLattice, basestring))]
+          postfixLattice.append((vector.nComponents, '_' + vector.id + '_ncomponents'))
+          
+          if transformation.get('transformType', 'real') is 'real' and vector.type == 'complex':
+            postfixLattice.append((2, '2'))
+          
+          if transformation.get('transformType', 'real') is 'complex' and vector.type == 'real':
+            delayedException = ParserException(
+              vector.xmlElement,
+              "Vector '%(vectorName)s' is of type 'real', but is needed in the following bases: %(basisList)s.\n"
+              "To transform between these bases, it is necessary to perform the %(firstBasis)s <--> %(secondBasis)s transform, "
+              "which is only possible for complex-valued vectors." % dict(
+                vectorName = vector.name,
+                basisList = ', '.join([printBasis(basis) for basis in vectorBases]),
+                firstBasis = printBasis(transformPair[0]),
+                secondBasis = printBasis(transformPair[1])
+              )
+            )
+            # Ideally, we'd rather raise this error on a user-created vector. Similar
+            # errors may also exist for related vectors which are of the same type as the original vector
+            # Identifying the error as originating from a user-generated vector makes the problem more obvious
+            # to the user. The difference between a user-created vector and an automatically generated one is that
+            # a user-created vector will have an XML element associated with it.
+            # But, should we not find a user-created vector with this problem, the exception will still be raised below.
+            # The problem will be harder to trace though.
+            if vector.xmlElement:
+              raise delayedException
+          
+          if transformation.get('geometryDependent', False):
+            geometrySpecification = (
+              runtimePrefixDimensions,
+              reduce(operator.mul, [lattice[0] for lattice in prefixLattice], 1),
+              reduce(operator.mul, [lattice[0] for lattice in postfixLattice], 1),
+              runtimePostfixDimensions
+            )
+          
+          transformDescriptor = (transformID, geometrySpecification, tuple(basisToDimRepBasis(b) for b in transformPair))
+          if transformDescriptor not in transformsNeeded:
+            transformsNeeded.append(transformDescriptor)
+          
+          prefixLatticeStrings = list(runtimePrefixDimensions)
+          prefixLatticeStrings.extend([lattice[1] for lattice in prefixLattice])
+          postfixLatticeStrings = list(runtimePostfixDimensions)
+          postfixLatticeStrings.extend([lattice[1] for lattice in postfixLattice])
+          
+          prefixLatticeString = ' * '.join(prefixLatticeStrings) or '1'
+          postfixLatticeString = ' * '.join(postfixLatticeStrings) or '1'
+          
+          if transformation.get('geometryDependent', False):
+            prefixLatticeStringMap.setdefault(transformDescriptor, prefixLatticeString)
+            postfixLatticeStringMap.setdefault(transformDescriptor, postfixLatticeString)
+          
+          transformSteps.append(
+            (
+              transformsNeeded.index(transformDescriptor),
+              forward,
+              transformation.get('outOfPlace', False),
+              prefixLatticeString,
+              postfixLatticeString,
+            )
+          )
+        basisPairInfo['transformSteps'] = transformSteps
+    
+    # If we still have a delayed exception, we must raise it.
+    if delayedException: raise delayedException
+    
+    # Now we need to extract the transforms and include that information in choosing transforms
+    # One advantage of this method is that we no longer have to make extra fft plans or matrices when we could just re-use others.
+    # Not only do we need to extract the transforms, but we must also produce a simple list of transforms that must be applied
+    # to change between any bases for this vector.
+    
+    self.basesNeeded = list(basesNeeded)
+    self.basesNeeded.sort()
+    
+    self.neededTransformations = []
+    for transformDescriptor in transformsNeeded:
+      transformID, transformSpecifier, transformPair = transformDescriptor
+      transformation = self.availableTransformations[transformID].copy()
+      transformation['transformSpecifier'] = transformSpecifier
+      del transformation['transformations']
+      transformation['transformPair'] = transformPair
+      # A bit dodgy, but I can't think of a better way
+      if transformation.get('geometryDependent', False):
+        transformation['prefixLatticeString'] = prefixLatticeStringMap[transformDescriptor]
+        transformation['postfixLatticeString'] = postfixLatticeStringMap[transformDescriptor]
+      self.neededTransformations.append(transformation)
+    
+    def functionImplementation(func):
+      transform = func.transform
+      transformFunction = transform.get('transformFunction')
+      transformFunctionPrelude = "if (_prefix_lattice <= 0 || _postfix_lattice <= 0) return;\n"
+      return transformFunctionPrelude + transformFunction(*func.transformFunctionArgs) if transformFunction else ''
+    
+    for tID, transform in enumerate(self.neededTransformations):
+      description = transform.get('description')
+      if transform['transformPair'] and not description:
+        basisA, basisB = transform['transformPair']
+        description = "%s <---> %s transform" % (printBasis(basisA), printBasis(basisB))
+        transform['description'] = description
+      functionName = '_transform_%i' % tID
+      args = [
+        ('bool', '_forward'),
+        ('real', '_multiplier'),
+        ('real* const __restrict__', '_data_in'),
+        ('real* const __restrict__', '_data_out'),
+        ('ptrdiff_t', '_prefix_lattice'),
+        ('ptrdiff_t', '_postfix_lattice')
+      ]
+      f = Function(name = functionName,
+                   args = args,
+                   implementation = functionImplementation,
+                   description = description)
+      f.transform = transform
+      f.transformFunctionArgs = [tID, transform, f]
+      self.functions[functionName] = f
+      transform['owner'].transformations.append((tID, transform))
+  
+
diff --git a/xpdeint/Features/Transforms/__init__.py b/xpdeint/Features/Transforms/__init__.py
new file mode 100644
index 0000000..1073250
--- /dev/null
+++ b/xpdeint/Features/Transforms/__init__.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+import TransformMultiplexer
+transformClasses = TransformMultiplexer.TransformMultiplexer.transformClasses
+
+import _NoTransform
+import NoTransformMPI
+_NoTransform._NoTransform.mpiCapableSubclass = NoTransformMPI.NoTransformMPI
+transformClasses['none'] = _NoTransform._NoTransform
+
+import FourierTransformFFTW3
+import FourierTransformFFTW3Threads
+import FourierTransformFFTW3MPI
+FourierTransformFFTW3.FourierTransformFFTW3.mpiCapableSubclass = FourierTransformFFTW3MPI.FourierTransformFFTW3MPI
+transformClasses.update([(name, FourierTransformFFTW3.FourierTransformFFTW3) for name in ['dft', 'dct', 'dst', 'mpi']])
+
+import MMT
+transformClasses.update([(name, MMT.MMT) for name in ['bessel', 'spherical-bessel', 'hermite-gauss']])
+
+del transformClasses
\ No newline at end of file
diff --git a/xpdeint/Features/Validation.py b/xpdeint/Features/Validation.py
new file mode 100644
index 0000000..fb342a6
--- /dev/null
+++ b/xpdeint/Features/Validation.py
@@ -0,0 +1,221 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Features._Validation import _Validation
+import textwrap
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.669223
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Features/Validation.tmpl'
+__CHEETAH_srcLastModified__ = 'Thu Aug 22 16:32:53 2013'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class Validation(_Validation):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(Validation, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Runtime variable validation at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Runtime variable validation''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def mainBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def mainBegin($dict) at line 29, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        if not VFFSL(SL,"runValidationChecks",True): # generated from line 31, col 3
+            return
+        write(u'''// Run-time validation checks
+''')
+        for validationCheck in VFFSL(SL,"validationChecks",True): # generated from line 35, col 3
+            _v = VFN(VFFSL(SL,"textwrap",True),"dedent",False)(validationCheck) # u'${textwrap.dedent(validationCheck)}' on line 36, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${textwrap.dedent(validationCheck)}')) # from line 36, col 1.
+            write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # Validation.tmpl
+        # 
+        # Created by Graham Dennis on 2008-03-21.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    featureName = 'Validation'
+
+    _mainCheetahMethod_for_Validation= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(Validation, '_initCheetahAttributes'):
+    templateAPIClass = getattr(Validation, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(Validation)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=Validation()).run()
+
+
diff --git a/xpdeint/Features/Validation.tmpl b/xpdeint/Features/Validation.tmpl
new file mode 100644
index 0000000..f01021f
--- /dev/null
+++ b/xpdeint/Features/Validation.tmpl
@@ -0,0 +1,40 @@
+@*
+Validation.tmpl
+
+Created by Graham Dennis on 2008-03-21.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Features._Validation
+
+ at import textwrap
+
+ at def description: Runtime variable validation
+ at attr featureName = 'Validation'
+
+ at def mainBegin($dict)
+  @#
+  @if not $runValidationChecks
+    @return
+  @end if
+// Run-time validation checks
+  @for $validationCheck in $validationChecks
+${textwrap.dedent(validationCheck)}@slurp
+
+  @end for
+  @#
+ at end def
diff --git a/xpdeint/Features/_AutoVectorise.py b/xpdeint/Features/_AutoVectorise.py
new file mode 100644
index 0000000..3958fa0
--- /dev/null
+++ b/xpdeint/Features/_AutoVectorise.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+AutoVectorise.py
+
+Created by Graham Dennis on 2008-02-07.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Features._Feature import _Feature
+
+import re
+
+class _AutoVectorise (_Feature):
+  
+  # Match things of the form someSymbol${someSubstitution}restOfSymbol[${index}]
+  # where the ${someSubstitution} is optional, and the curly braces around the
+  # index replacement are also optional.
+  arrayNameRegex = re.compile(r'\b([a-zA-Z_]\w*(?:\$\{[a-zA-Z0-9_.]+\}\w*)?)(?=\[\$(?:\{index\}|index)\])')
+  
+  def loopOverVectorsWithInnerContentTemplateModifyTemplate(self, dict):
+    """
+    Modifies the ``templateString`` to add in auto-vectorisation features.
+    
+    This function is called from `ScriptElement`'s `loopOverVectorsWithInnerContentTemplate`.
+    """
+    templateString = dict['templateString']
+    
+    if 'UNVECTORISABLE' in templateString:
+      dict['vectorisable'] = False
+      return
+    else:
+      dict['vectorisable'] = True
+    
+    # Assert that no-one has touched the loopCountPrefixFunction because I can't
+    # think of a possible way to make multiple bits of code that want to modify
+    # this function work safely together. If such a need ever arises, then the
+    # problem can be solved then, and it will be picked up thanks to this assert.
+    assert dict['loopCountPrefixFunction'] == None
+    
+    def loopCountPrefixFunction(vector):
+      if vector.type == 'complex':
+        return '2 * '
+      else:
+        return ''
+    
+    dict['loopCountPrefixFunction'] = loopCountPrefixFunction
+    
+    arrayNames = set(self.arrayNameRegex.findall(templateString))
+    
+    # Create a template prefix that creates the *_dbl variables
+    vectorisationPreambleContents = ''.join(['  _MAKE_AUTOVEC_VARIABLE(%s);\n' % arrayName for arrayName in arrayNames])
+    
+    vectorisationPreambleTemplateFunction = ''.join(["@def vectorisationPreamble\n",
+                                                     vectorisationPreambleContents,
+                                                     "@end def\n"])
+    
+    newTemplateString = self.arrayNameRegex.sub(r'_AUTOVEC(\1)', templateString)
+    
+    dict['templateString'] = newTemplateString
+    dict['templateFunctions'].append(vectorisationPreambleTemplateFunction)
+  
+  def loopOverVectorsWithInnerContentTemplateBegin(self, dict):
+      if not dict['vectorisable']:
+        return '#pragma novector\n'
+      else:
+        dblVariableConstruction = dict['template'].vectorisationPreamble()
+        dict['extraIndent'] += 2
+        return ''.join(['{\n',
+                        dblVariableConstruction,
+                        '  #pragma ivdep\n'])
+  
+  def loopOverVectorsWithInnerContentTemplateEnd(self, dict):
+    if not dict['vectorisable']:
+      return
+    else:
+      dict['extraIndent'] -= 2
+      return '}\n'
+  
diff --git a/xpdeint/Features/_ChunkedOutput.py b/xpdeint/Features/_ChunkedOutput.py
new file mode 100644
index 0000000..7f78cac
--- /dev/null
+++ b/xpdeint/Features/_ChunkedOutput.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_ChunkedOutput.py
+
+Created by Graham Dennis on 2010-09-17.
+
+Copyright (c) 2010-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Features._Feature import _Feature
+
+from xpdeint.ParserException import ParserException
+
+class _ChunkedOutput (_Feature):
+  def __init__(self, *args, **KWs):
+    localKWs = self.extractLocalKWs(['chunkSize'], KWs)
+    
+    _Feature.__init__(self, *args, **KWs)
+    
+    self.chunkSize = localKWs['chunkSize']
+  
+  def preflight(self):
+    super(_ChunkedOutput, self).preflight()
+    
+    for mg in self.getVar('momentGroups'):
+      mg.propDimRep.setHasLocalOffset()
+    
+    outputFormat = self.getVar('features')['Output'].outputFormat
+    if not outputFormat.mpiSafe:
+      # If an output format is not mpi safe, then it isn't safe for us either
+      # This is because MPI requires random access to the output file, just as we do.
+      raise ParserException(
+        self.xmlElement,
+        "The 'chunked_output' feature cannot be used with the '%s' output format." % outputFormat.name
+      )
+    
+    # We also can't work if something like the 'error_check' feature is used because it wants to use all the output data
+    # at the end of the simulation
+    for momentGroup in self.getVar('momentGroups'):
+      if momentGroup.processedVector.aliases:
+        # Anything that sets an alias is bad.  But that's not a helpful error message to provide to the user
+        # So let's try and interpret why there are aliases on the processed vector
+        for alias in momentGroup.processedVector.aliases:
+          if alias.endswith('_halfstep'):
+            error = "the 'error_check' feature.  They are mutually exclusive."
+          elif alias.endswith('_sd'):
+            error = "any of the 'multi-path' drivers.  They are mutually exclusive."
+          else:
+            # If this error is hit, it means that a new feature was added that collides with chunked_output, but
+            # it didn't exist at the time that the chunked_output feature was created.  Please add a check here
+            # for this new feature so that the user recieves a nicer error message.
+            error = "any function of xmds2 that creates aliases of moment group processed vectors. "\
+                    "Please send your script and report this error to %s" % self.getVar('bugReportAddress')
+          raise ParserException(
+            self.xmlElement,
+            "The 'chunked_output' feature cannot be used with " + error
+            )
+  
+
diff --git a/xpdeint/Features/_Diagnostics.py b/xpdeint/Features/_Diagnostics.py
new file mode 100644
index 0000000..9d30e38
--- /dev/null
+++ b/xpdeint/Features/_Diagnostics.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_Diagnostics.py
+
+Created by Graham Dennis on 2009-06-15.
+
+Copyright (c) 2009-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Features._Feature import _Feature
+
+from xpdeint.Geometry.UniformDimensionRepresentation import UniformDimensionRepresentation
+from xpdeint.Function import Function
+
+class _Diagnostics (_Feature):
+  def nonlocalAccess(self, dict):
+    """
+    The purpose of this function is to safety-check nonlocal dimension access. The only place where this is potentially
+    unsafe is with integer-valued dimensions as we permit users to use any code to access a dimension. For speed reasons
+    we don't run safety checks. But in the diagnostics feature, we can sacrifice speed for more safety.
+    
+    For any nonlocally-accessed dimReps, we replace the usual #define with a function call that includes the line number
+    from which it was called from the original .xmds file. The function then does a bounds check on all potentially-unsafe
+    accesses and stops the simulation if any are found.
+    """
+    availableDimReps = dict['availableDimReps']
+    dimRepsNeeded = dict['dimRepsNeeded']
+    
+    if not any(dimRep.type == 'long' and isinstance(dimRep, UniformDimensionRepresentation) for dimRep in dimRepsNeeded):
+      return
+    
+    vector = dict['vector']
+    nonlocalAccessVariableName = dict['nonlocalAccessVariableName']
+    nonlocalAccessString = dict['nonlocalAccessString']
+    componentName = dict['componentName']
+    
+    args = [('long', dimRep.loopIndex) for dimRep in availableDimReps]
+    args.extend([('const char*', 'filename'), ('int', 'line_number')])
+    
+    implementation = lambda func: self.nonlocalAccessValidationFunctionContents(dimRepsNeeded, nonlocalAccessString, componentName, func)
+    
+    self.functions[nonlocalAccessVariableName] = Function(
+      '_' + nonlocalAccessVariableName,
+      args,
+      implementation,
+      returnType = 'inline ' + vector.type + '&',
+    )
+    
+    defineArgumentsString = ', '.join(dimRep.loopIndex for dimRep in dimRepsNeeded)
+    functionArgumentsString = ', '.join(dimRep.loopIndex for dimRep in availableDimReps)
+    defineString = '#define %(nonlocalAccessVariableName)s(%(defineArgumentsString)s) _%(nonlocalAccessVariableName)s(%(functionArgumentsString)s, __FILE__, __LINE__)\n' % locals()
+    dict['defineString'] = defineString
diff --git a/xpdeint/Features/_ErrorCheck.py b/xpdeint/Features/_ErrorCheck.py
new file mode 100644
index 0000000..f330a33
--- /dev/null
+++ b/xpdeint/Features/_ErrorCheck.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_ErrorCheck.py
+
+Created by Graham Dennis on 2008-02-02.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Features._Feature import _Feature
+
+from xpdeint.Segments.Integrators.FixedStep import FixedStep
+from xpdeint.Operators.DeltaAOperator import DeltaAOperator
+from xpdeint.Vectors.NoiseVector import NoiseVector
+
+class _ErrorCheck (_Feature):
+  
+  def post_preflight(self):
+    super(_ErrorCheck, self).preflight()
+    
+    for mg in self.getVar('momentGroups'):
+      mg.processedVector.aliases.add('_%s_halfstep' % mg.outputField.name)
+    
+    # When we have error checking, every dynamic noise vector used by an integrator in a fixed step integrator
+    # needs a '2' noise vector alias for generating two half-step noises and adding them.
+    if 'ErrorCheck' in self.getVar('features'):
+      noiseVectorsNeedingAlias = set()
+      # Loop over all fixed-step integrators ...
+      for fixedStepIntegrator in [o for o in self.getVar('templates') if isinstance(o, FixedStep)]:
+        # ... adding the dynamic noise vectors of that integrator
+        noiseVectorsNeedingAlias.update(fixedStepIntegrator.dynamicNoiseVectors)
+        
+      for noiseVector in noiseVectorsNeedingAlias:
+        noiseVector.aliases.add('_%s2' % noiseVector.id)
+    
diff --git a/xpdeint/Features/_Feature.py b/xpdeint/Features/_Feature.py
new file mode 100644
index 0000000..407a728
--- /dev/null
+++ b/xpdeint/Features/_Feature.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_Feature.py
+
+This contains all the pure-python code for all features
+
+Created by Graham Dennis on 2007-10-18.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.ScriptElement import ScriptElement
+
+class _Feature (ScriptElement):
+  def __init__(self, *args, **KWs):
+    ScriptElement.__init__(self, *args, **KWs)
+    
+    self.getVar('features')[self.featureName] = self
+  
diff --git a/xpdeint/Features/_HDF5Format.py b/xpdeint/Features/_HDF5Format.py
new file mode 100644
index 0000000..d05e87b
--- /dev/null
+++ b/xpdeint/Features/_HDF5Format.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_HDF5Format.py
+
+Created by Graham Dennis on 2009-01-31.
+
+Copyright (c) 2009-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Features.OutputFormat import OutputFormat
+from xpdeint.HDF5 import HDF5
+
+class _HDF5Format (OutputFormat, HDF5):
+  def __init__(self, *args, **KWs):
+    OutputFormat.__init__(self, *args, **KWs)
+    HDF5.__init__(self, *args, **KWs)
+  
diff --git a/xpdeint/Features/_Stochastic.py b/xpdeint/Features/_Stochastic.py
new file mode 100755
index 0000000..8a36400
--- /dev/null
+++ b/xpdeint/Features/_Stochastic.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_Stochastic.py
+
+Created by Graham Dennis on 2008-01-13.
+
+Copyright (c) 2008-2012, Graham Dennis and Joe Hope
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Features._Feature import _Feature
+from xpdeint.Vectors.NoiseVector import NoiseVector
+from xpdeint.Segments.Integrators.AdaptiveStep import AdaptiveStep as AdaptiveStepIntegrator
+from xpdeint.Geometry.NonUniformDimensionRepresentation import NonUniformDimensionRepresentation
+from xpdeint.Stochastic.RandomVariables.GaussianRandomVariable import GaussianRandomVariable
+
+from xpdeint.ParserException import ParserException, parserWarning
+
+class _Stochastic (_Feature):
+  def adaptiveIntegratorsWithNoises(self):
+    adaptiveIntegratorList = [ai for ai in self.getVar('templates') if isinstance(ai, AdaptiveStepIntegrator) and ai.dynamicNoiseVectors]
+
+    return adaptiveIntegratorList
+
+  def xsilOutputInfo(self, dict):
+    return '\n'.join(nv.implementationsForFunctionName('xsilOutputInfo', dict) for nv in self.noiseVectors)
+  
+  def preflight(self):
+    super(_Stochastic, self).preflight()
+    
+    self.noiseVectors = [o for o in self.getVar('templates') if isinstance(o, NoiseVector)]
+    
+    self.nonUniformDimRepsNeededForGaussianNoise = set()
+    for nv in [nv for nv in self.noiseVectors if isinstance(nv.randomVariable, GaussianRandomVariable)]:
+      self.nonUniformDimRepsNeededForGaussianNoise.update(dimRep for dimRep in nv.field.inBasis(nv.initialBasis) if isinstance(dimRep, NonUniformDimensionRepresentation))
+    
+    
+  
diff --git a/xpdeint/Features/_Validation.py b/xpdeint/Features/_Validation.py
new file mode 100644
index 0000000..25a6e45
--- /dev/null
+++ b/xpdeint/Features/_Validation.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_Validation.py
+
+Created by Graham Dennis on 2008-03-21.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Features._Feature import _Feature
+
+class _Validation (_Feature):
+  def __init__(self, *args, **KWs):
+    localKWs = self.extractLocalKWs(['runValidationChecks'], KWs)
+    
+    _Feature.__init__(self, *args, **KWs)
+    
+    self.validationChecks = []
+    self.runValidationChecks = localKWs.get('runValidationChecks', True)
+  
diff --git a/xpdeint/Features/__init__.py b/xpdeint/Features/__init__.py
new file mode 100644
index 0000000..d2fbb06
--- /dev/null
+++ b/xpdeint/Features/__init__.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+import Arguments
+import AutoVectorise
+import Benchmark
+import Bing
+import CFlags
+import ChunkedOutput
+import Diagnostics
+import ErrorCheck
+import Globals
+import HaltNonFinite
+import MaxIterations
+import OpenMP
+import Output
+import Stochastic
+import Transforms
+import Validation
+
+import OutputFormat
+from BinaryFormat import BinaryFormat
+from AsciiFormat import AsciiFormat
+from HDF5Format import HDF5Format
+
+formatMapping = [(f.name, f) for f in [BinaryFormat, AsciiFormat, HDF5Format]]
+del BinaryFormat, AsciiFormat, HDF5Format
+
+OutputFormat.OutputFormat.outputFormatClasses.update(formatMapping)
+
diff --git a/xpdeint/FriendlyPlusStyle.py b/xpdeint/FriendlyPlusStyle.py
new file mode 100644
index 0000000..9d621cb
--- /dev/null
+++ b/xpdeint/FriendlyPlusStyle.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+FriendlyPlusStyle.py
+
+Created by Graham Dennis on 2008-11-18.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from pygments.styles.friendly import FriendlyStyle
+from pygments.token import String
+
+class FriendlyPlusStyle(FriendlyStyle):
+  """
+  Slight modification of the Friendly style to make attribute-string values
+  have different colours.
+  """
+  
+  styles = FriendlyStyle.styles.copy()
+  styles.update({String: "italic #517918"})
+  
diff --git a/xpdeint/Function.py b/xpdeint/Function.py
new file mode 100644
index 0000000..f234fc7
--- /dev/null
+++ b/xpdeint/Function.py
@@ -0,0 +1,115 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+Function.py
+
+Created by Graham Dennis on 2008-07-10.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+class Function(object):
+  """
+  The idea behind Function objects is that they wrap C functions that will be in
+  the generated source file that will need to be flexible in terms of what
+  arguments they have. This way, one object can add function arguments to the
+  functions 'belonging' to other objects without the second object needing to be
+  involved.
+
+  An example of an application of this is passing the cross-propagation dimension
+  variable to delta-a operators in the cross-propagation integrator. As the
+  cross-propagation integrator is a normal integrator, it wouldn't normally need
+  to pass the propagation dimension variable to the delta a operator as the
+  propagation dimension value is stored in a global variable. With the function
+  objects, the cross-propagation operator just needs to add additional arguments
+  to the cross-propagation delta-a calculation function and the delta-a operator
+  and these variables are then passed through these functions.
+
+  In a similar way other variables like cycle number of a looping segment could
+  be passed to children if a use for that can be found. This behaviour was
+  present in xmds-1, but hasn't been added to xpdeint as there hasn't been a need
+  for it, and it isn't clear how this behaviour would work in the face of nested
+  looping segments.
+  """
+  def __init__(self, name, args, implementation,
+               description = None, returnType = 'void', predicate = lambda: True):
+    """
+    Initialise a `Function` object with C name `functionName`, arguments `args` and a
+    return type of `returnType`. The `implementation` argument must be a function that
+    returns the body of the C function.
+    
+    The `args` argument is an array of 2-tuples of the form ``('argType', 'argName')``.
+    
+    `predicate` is a callable that will cause the function not to be defined if it returns false
+    """
+    self.name = name
+    self.args = args[:]
+    self.implementationContents = implementation
+    self.returnType = returnType
+    self.description = description
+    # Note that the predicate is actually used by _ScriptElement
+    self.predicate = predicate
+  
+  def _prototype(self):
+    """
+    Return as a string the C function prototype that can be used for both
+    function declaration and definition.
+    
+    For example, return ``void _segment3(int myInt)``.
+    """
+    argumentString = ', '.join([arg[0] + ' ' + arg[1] for arg in self.args])
+    return ''.join([self.returnType, ' ', self.name, '(', argumentString, ')'])
+  
+  def prototype(self):
+    """
+    Return as a string the C function prototype for this function.
+    
+    For example, return ``void _segment3(int myInt);\\n``.
+    """
+    return self._prototype() + ';\n'
+  
+  def implementation(self):
+    """
+    Return as a string the C function implementation for this function.
+    """
+    implementationBodyString = self.implementationContents(self)
+    result = []
+    if self.description:
+      result.append('// ' + self.description + '\n')
+    result.extend([self._prototype(), '\n{\n'])
+    for line in implementationBodyString.splitlines(True):
+      result.extend(['  ', line])
+    result.append('}\n')
+    return ''.join(result)
+  
+  def call(self, arguments = None, parentFunction = None, **KWs):
+    """
+    Return as a string the C code to call this function with arguments `arguments`
+    and any keyword arguments.
+    """
+    availableArguments = {}
+    # The precendence for the arguments is KWs, arguments, parentFunction.
+    # So we add arguments to availableArguments in the opposite order.
+    if parentFunction:
+      availableArguments.update([(arg[1], arg[1]) for arg in parentFunction.args])
+    if arguments:
+      availableArguments.update(arguments)
+    if KWs:
+      availableArguments.update(KWs)
+    argumentString = ', '.join([str(availableArguments[arg[1]]) for arg in self.args])
+    return ''.join([self.name, '(', argumentString, ');'])
+  
diff --git a/xpdeint/Geometry/BesselDimensionRepresentation.py b/xpdeint/Geometry/BesselDimensionRepresentation.py
new file mode 100644
index 0000000..d3e20c9
--- /dev/null
+++ b/xpdeint/Geometry/BesselDimensionRepresentation.py
@@ -0,0 +1,405 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Geometry.NonUniformDimensionRepresentation import NonUniformDimensionRepresentation
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.703494
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Geometry/BesselDimensionRepresentation.tmpl'
+__CHEETAH_srcLastModified__ = 'Wed Jul 11 19:41:11 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class BesselDimensionRepresentation(NonUniformDimensionRepresentation):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(BesselDimensionRepresentation, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def besselJFunctionCall(self, order, argument, **KWS):
+
+
+
+        ## CHEETAH: generated from @def besselJFunctionCall($order, $argument) at line 28, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        if VFFSL(SL,"order",True) in [0, 1]: # generated from line 29, col 3
+            write(u'''j''')
+            _v = VFFSL(SL,"order",True) # u'${order}' on line 30, col 2
+            if _v is not None: write(_filter(_v, rawExpr=u'${order}')) # from line 30, col 2.
+            write(u'''(''')
+            _v = VFFSL(SL,"argument",True) # u'$argument' on line 30, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'$argument')) # from line 30, col 11.
+            write(u''')''')
+        else: # generated from line 31, col 3
+            write(u'''jn(''')
+            _v = VFFSL(SL,"order",True) # u'${order}' on line 32, col 4
+            if _v is not None: write(_filter(_v, rawExpr=u'${order}')) # from line 32, col 4.
+            write(u''', ''')
+            _v = VFFSL(SL,"argument",True) # u'${argument}' on line 32, col 14
+            if _v is not None: write(_filter(_v, rawExpr=u'${argument}')) # from line 32, col 14.
+            write(u''')''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def gridAndStepAtIndex(self, index, **KWS):
+
+
+
+        ## CHEETAH: generated from @def gridAndStepAtIndex($index) at line 36, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''const real besselFactor = ''')
+        _v = VFFSL(SL,"besselJFunctionCall",False)(VFFSL(SL,"_order",True) + 1, ''.join([u'_normbesseljzeros_',str(VFFSL(SL,"parent.name",True)),u'[',str(VFFSL(SL,"index",True)),u'] * _besseljnorm_',str(VFFSL(SL,"parent.name",True))])) # u"${besselJFunctionCall($_order + 1, c'_normbesseljzeros_${parent.name}[${index}] * _besseljnorm_${parent.name}')}" on line 38, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u"${besselJFunctionCall($_order + 1, c'_normbesseljzeros_${parent.name}[${index}] * _besseljnorm_${parent.name}')}")) # from line 38, col 27.
+        write(u''';
+const real ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 39, col 12
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 39, col 12.
+        write(u'''_max = ''')
+        _v = VFFSL(SL,"_maximum",True) # u'${_maximum}' on line 39, col 26
+        if _v is not None: write(_filter(_v, rawExpr=u'${_maximum}')) # from line 39, col 26.
+        write(u''';
+''')
+        # 
+        _v = super(BesselDimensionRepresentation, self).gridAndStepAtIndex(index)
+        if _v is not None: write(_filter(_v))
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def gridAtIndex(self, index, **KWS):
+
+
+
+        ## CHEETAH: generated from @def gridAtIndex($index) at line 45, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''_normbesseljzeros_''')
+        _v = VFFSL(SL,"parent.name",True) # u'${parent.name}' on line 47, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${parent.name}')) # from line 47, col 19.
+        write(u'''[''')
+        _v = VFFSL(SL,"index",True) # u'$index' on line 47, col 34
+        if _v is not None: write(_filter(_v, rawExpr=u'$index')) # from line 47, col 34.
+        write(u'''] * ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 47, col 44
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 47, col 44.
+        write(u'''_max''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def stepWeightAtIndex(self, index, **KWS):
+
+
+
+        ## CHEETAH: generated from @def stepWeightAtIndex($index) at line 51, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''2.0 / (besselFactor * besselFactor * _besseljnorm_''')
+        _v = VFFSL(SL,"parent.name",True) # u'${parent.name}' on line 53, col 51
+        if _v is not None: write(_filter(_v, rawExpr=u'${parent.name}')) # from line 53, col 51.
+        write(u''' * _besseljnorm_''')
+        _v = VFFSL(SL,"parent.name",True) # u'${parent.name}' on line 53, col 81
+        if _v is not None: write(_filter(_v, rawExpr=u'${parent.name}')) # from line 53, col 81.
+        write(u''') * ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 53, col 99
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 53, col 99.
+        write(u'''_max * ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 53, col 113
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 53, col 113.
+        write(u'''_max''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def indexForSinglePointSample(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def indexForSinglePointSample at line 57, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  Take the first point, which is close to r=0
+        write(u'''0''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def createCoordinateVariableForSinglePointSample(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def createCoordinateVariableForSinglePointSample at line 64, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"type",True) # u'${type}' on line 66, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${type}')) # from line 66, col 1.
+        write(u''' ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 66, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 66, col 9.
+        write(u''' = ''')
+        _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 66, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 66, col 19.
+        write(u'''[0];
+#define d''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 67, col 10
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 67, col 10.
+        write(u''' (''')
+        _v = VFFSL(SL,"stepSizeArrayName",True) # u'${stepSizeArrayName}' on line 67, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepSizeArrayName}')) # from line 67, col 19.
+        write(u'''[0] * (''')
+        _v = VFFSL(SL,"volumePrefactor",True) # u'${volumePrefactor}' on line 67, col 46
+        if _v is not None: write(_filter(_v, rawExpr=u'${volumePrefactor}')) # from line 67, col 46.
+        write(u'''))
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # BesselDimensionRepresentation.tmpl
+        # 
+        # Created by Graham Dennis on 2009-08-11.
+        # 
+        # Copyright (c) 2009-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    instanceAttributes = ['_maximum', '_order']
+
+    orderOffset = 0
+
+    _mainCheetahMethod_for_BesselDimensionRepresentation= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(BesselDimensionRepresentation, '_initCheetahAttributes'):
+    templateAPIClass = getattr(BesselDimensionRepresentation, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(BesselDimensionRepresentation)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=BesselDimensionRepresentation()).run()
+
+
diff --git a/xpdeint/Geometry/BesselDimensionRepresentation.tmpl b/xpdeint/Geometry/BesselDimensionRepresentation.tmpl
new file mode 100644
index 0000000..9d2fbc6
--- /dev/null
+++ b/xpdeint/Geometry/BesselDimensionRepresentation.tmpl
@@ -0,0 +1,69 @@
+@*
+BesselDimensionRepresentation.tmpl
+
+Created by Graham Dennis on 2009-08-11.
+
+Copyright (c) 2009-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Geometry.NonUniformDimensionRepresentation
+
+ at attr $instanceAttributes = ['_maximum', '_order']
+
+ at attr $orderOffset = 0
+
+ at def besselJFunctionCall($order, $argument)
+  @if $order in [0, 1]
+j${order}($argument)@slurp
+  @else
+jn(${order}, ${argument})@slurp
+  @end if
+ at end def
+
+ at def gridAndStepAtIndex($index)
+  @#
+const real besselFactor = ${besselJFunctionCall($_order + 1, c'_normbesseljzeros_${parent.name}[${index}] * _besseljnorm_${parent.name}')};
+const real ${name}_max = ${_maximum};
+  @#
+  @super(index)
+  @#
+ at end def
+
+ at def gridAtIndex($index)
+  @#
+_normbesseljzeros_${parent.name}[$index] * ${name}_max at slurp
+  @#
+ at end def
+
+ at def stepWeightAtIndex($index)
+  @#
+2.0 / (besselFactor * besselFactor * _besseljnorm_${parent.name} * _besseljnorm_${parent.name}) * ${name}_max * ${name}_max at slurp
+  @#
+ at end def
+
+ at def indexForSinglePointSample
+  @#
+  @# Take the first point, which is close to r=0
+0 at slurp
+  @#
+ at end def
+
+ at def createCoordinateVariableForSinglePointSample
+  @#
+${type} ${name} = ${arrayName}[0];
+#define d${name} (${stepSizeArrayName}[0] * (${volumePrefactor}))
+  @#
+ at end def
diff --git a/xpdeint/Geometry/DimensionRepresentation.py b/xpdeint/Geometry/DimensionRepresentation.py
new file mode 100644
index 0000000..273d231
--- /dev/null
+++ b/xpdeint/Geometry/DimensionRepresentation.py
@@ -0,0 +1,300 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Geometry._DimensionRepresentation import _DimensionRepresentation
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.759103
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Geometry/DimensionRepresentation.tmpl'
+__CHEETAH_srcLastModified__ = 'Tue May 22 16:27:12 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class DimensionRepresentation(_DimensionRepresentation):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(DimensionRepresentation, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def defines(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def defines at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(DimensionRepresentation, self).defines()
+        if _v is not None: write(_filter(_v))
+        if VFFSL(SL,"silent",True): # generated from line 27, col 3
+            return _dummyTrans and trans.response().getvalue() or ""
+        # 
+        write(u'''#define ''')
+        _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 31, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 31, col 9.
+        write(u''' ((int)''')
+        _v = VFFSL(SL,"runtimeLattice",True) # u'${runtimeLattice}' on line 31, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'${runtimeLattice}')) # from line 31, col 32.
+        write(u''')
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def globals at line 35, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(DimensionRepresentation, self).globals()
+        if _v is not None: write(_filter(_v))
+        # 
+        if VFFSL(SL,"silent",True): # generated from line 39, col 3
+            return _dummyTrans and trans.response().getvalue() or ""
+        # 
+        #  Note: Here we just *define* the variables for which we're going to
+        #  allocate space later (in allocate() below). This is needed in case the
+        #  lattice size is specified at runtime - if we allocate space here, it
+        #  will use the default argument lattice size, rather than the one set
+        #  in the argument processing code in the main() function.
+        # 
+        #  Make sure we don't create a variable for the propagtion direction dimension
+        if VFFSL(SL,"runtimeLattice",True): # generated from line 50, col 3
+            _v = VFFSL(SL,"type",True) # u'${type}' on line 51, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${type}')) # from line 51, col 1.
+            write(u'''* ''')
+            _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 51, col 10
+            if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 51, col 10.
+            write(u''' = NULL;
+''')
+        # 
+        if VFFSL(SL,"hasLocalOffset",True): # generated from line 54, col 3
+            write(u'''ptrdiff_t ''')
+            _v = VFFSL(SL,"localLattice",True) # u'$localLattice' on line 55, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'$localLattice')) # from line 55, col 11.
+            write(u''' = 0;
+ptrdiff_t ''')
+            _v = VFFSL(SL,"localOffset",True) # u'$localOffset' on line 56, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'$localOffset')) # from line 56, col 11.
+            write(u''' = 0;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def allocate(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def allocate(self) at line 61, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        if VFFSL(SL,"silent",True): # generated from line 62, col 3
+            return _dummyTrans and trans.response().getvalue() or ""
+        #  We allocate an extra point just in case
+        #  Also make sure we don't create a variable for the propagtion direction dimension
+        if VFFSL(SL,"runtimeLattice",True): # generated from line 67, col 3
+            _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 68, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 68, col 1.
+            write(u''' = (''')
+            _v = VFFSL(SL,"type",True) # u'${type}' on line 68, col 17
+            if _v is not None: write(_filter(_v, rawExpr=u'${type}')) # from line 68, col 17.
+            write(u'''*) xmds_malloc(sizeof(''')
+            _v = VFFSL(SL,"type",True) # u'${type}' on line 68, col 46
+            if _v is not None: write(_filter(_v, rawExpr=u'${type}')) # from line 68, col 46.
+            write(u''') * (''')
+            _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 68, col 58
+            if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 68, col 58.
+            write(u'''+1));
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # DimensionRepresentation.tmpl
+        # 
+        # Created by Graham Dennis on 2008-08-01.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_DimensionRepresentation= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(DimensionRepresentation, '_initCheetahAttributes'):
+    templateAPIClass = getattr(DimensionRepresentation, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(DimensionRepresentation)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=DimensionRepresentation()).run()
+
+
diff --git a/xpdeint/Geometry/DimensionRepresentation.tmpl b/xpdeint/Geometry/DimensionRepresentation.tmpl
new file mode 100644
index 0000000..e197426
--- /dev/null
+++ b/xpdeint/Geometry/DimensionRepresentation.tmpl
@@ -0,0 +1,71 @@
+@*
+DimensionRepresentation.tmpl
+
+Created by Graham Dennis on 2008-08-01.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Geometry._DimensionRepresentation
+
+ at def defines
+  @#
+  @super
+  @if $silent
+    @stop
+  @end if
+  @#
+#define ${globalLattice} ((int)${runtimeLattice})
+  @#
+ at end def
+
+ at def globals
+  @#
+  @super
+  @#
+  @if $silent
+    @stop
+  @end if
+  @#
+  @# Note: Here we just *define* the variables for which we're going to
+  @# allocate space later (in allocate() below). This is needed in case the
+  @# lattice size is specified at runtime - if we allocate space here, it
+  @# will use the default argument lattice size, rather than the one set
+  @# in the argument processing code in the main() function.
+  @#
+  @# Make sure we don't create a variable for the propagtion direction dimension
+  @if $runtimeLattice
+${type}* ${arrayName} = NULL;
+  @end if
+  @#
+  @if $hasLocalOffset
+ptrdiff_t $localLattice = 0;
+ptrdiff_t $localOffset = 0;
+  @end if
+  @#
+ at end def
+
+ at def allocate(self)
+  @if $silent
+    @stop
+  @end if
+  @# We allocate an extra point just in case
+  @# Also make sure we don't create a variable for the propagtion direction dimension
+  @if $runtimeLattice
+${arrayName} = (${type}*) xmds_malloc(sizeof(${type}) * (${globalLattice}+1));
+  @end if
+ at end def
+
diff --git a/xpdeint/Geometry/FieldElement.py b/xpdeint/Geometry/FieldElement.py
new file mode 100644
index 0000000..f2e1030
--- /dev/null
+++ b/xpdeint/Geometry/FieldElement.py
@@ -0,0 +1,229 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Geometry._FieldElement import _FieldElement
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.760514
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Geometry/FieldElement.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class FieldElement(_FieldElement):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(FieldElement, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: field $name at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''field ''')
+        _v = VFFSL(SL,"name",True) # u'$name' on line 27, col 25
+        if _v is not None: write(_filter(_v, rawExpr=u'$name')) # from line 27, col 25.
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def defines(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def defines at line 32, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(FieldElement, self).defines()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''#define _''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 36, col 10
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 36, col 10.
+        write(u'''_ndims ''')
+        _v = VFFSL(SL,"len",False)(VFFSL(SL,"dimensions",True)) # u'${len($dimensions)}' on line 36, col 24
+        if _v is not None: write(_filter(_v, rawExpr=u'${len($dimensions)}')) # from line 36, col 24.
+        write(u'''
+
+''')
+        #  Child defines will go here
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # FieldElement.tmpl
+        # 
+        # Created by Graham Dennis on 2007-08-28.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+''')
+        # 
+        #   Description of template
+        write(u'''
+''')
+        # 
+        #   Defines needed at the start of the simulation
+        write(u'''
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_FieldElement= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(FieldElement, '_initCheetahAttributes'):
+    templateAPIClass = getattr(FieldElement, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(FieldElement)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=FieldElement()).run()
+
+
diff --git a/xpdeint/Geometry/FieldElement.tmpl b/xpdeint/Geometry/FieldElement.tmpl
new file mode 100644
index 0000000..3498b57
--- /dev/null
+++ b/xpdeint/Geometry/FieldElement.tmpl
@@ -0,0 +1,40 @@
+@*
+FieldElement.tmpl
+
+Created by Graham Dennis on 2007-08-28.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Geometry._FieldElement
+
+@*
+  Description of template
+*@
+ at def description: field $name
+
+@*
+  Defines needed at the start of the simulation
+*@
+ at def defines
+  @#
+  @super
+  @#
+#define _${name}_ndims ${len($dimensions)}
+
+  @# Child defines will go here
+ at end def
+
diff --git a/xpdeint/Geometry/GeometryElement.py b/xpdeint/Geometry/GeometryElement.py
new file mode 100644
index 0000000..12bb5c7
--- /dev/null
+++ b/xpdeint/Geometry/GeometryElement.py
@@ -0,0 +1,187 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Geometry._FieldElement import _FieldElement
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.7714
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Geometry/GeometryElement.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class GeometryElement(_FieldElement):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(GeometryElement, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Geometry at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Geometry''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # GeometryElement.tmpl
+        # 
+        # Created by Graham Dennis on 2007-08-28.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+''')
+        # 
+        #   Description of template
+        write(u'''
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    name = "geometry"
+
+    globalNameSpaceName = "geometry"
+
+    _mainCheetahMethod_for_GeometryElement= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(GeometryElement, '_initCheetahAttributes'):
+    templateAPIClass = getattr(GeometryElement, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(GeometryElement)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=GeometryElement()).run()
+
+
diff --git a/xpdeint/Geometry/GeometryElement.tmpl b/xpdeint/Geometry/GeometryElement.tmpl
new file mode 100644
index 0000000..107cfd8
--- /dev/null
+++ b/xpdeint/Geometry/GeometryElement.tmpl
@@ -0,0 +1,30 @@
+@*
+GeometryElement.tmpl
+
+Created by Graham Dennis on 2007-08-28.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Geometry._FieldElement
+
+@*
+  Description of template
+*@
+ at def description: Geometry
+ at attr $name = "geometry"
+ at attr $globalNameSpaceName = "geometry"
+
diff --git a/xpdeint/Geometry/HermiteGaussDimensionRepresentation.py b/xpdeint/Geometry/HermiteGaussDimensionRepresentation.py
new file mode 100644
index 0000000..3fd8267
--- /dev/null
+++ b/xpdeint/Geometry/HermiteGaussDimensionRepresentation.py
@@ -0,0 +1,328 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Geometry.NonUniformDimensionRepresentation import NonUniformDimensionRepresentation
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.781387
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Geometry/HermiteGaussDimensionRepresentation.tmpl'
+__CHEETAH_srcLastModified__ = 'Wed Jul 11 19:41:11 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class HermiteGaussDimensionRepresentation(NonUniformDimensionRepresentation):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(HermiteGaussDimensionRepresentation, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def gridAtIndex(self, index, **KWS):
+
+
+
+        ## CHEETAH: generated from @def gridAtIndex($index) at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''_hermite_zeros_''')
+        _v = VFFSL(SL,"parent.name",True) # u'${parent.name}' on line 29, col 16
+        if _v is not None: write(_filter(_v, rawExpr=u'${parent.name}')) # from line 29, col 16.
+        write(u'''[''')
+        _v = VFFSL(SL,"index",True) # u'$index' on line 29, col 31
+        if _v is not None: write(_filter(_v, rawExpr=u'$index')) # from line 29, col 31.
+        write(u'''] * ''')
+        _v = VFFSL(SL,"_maximum",True) # u'${_maximum}' on line 29, col 41
+        if _v is not None: write(_filter(_v, rawExpr=u'${_maximum}')) # from line 29, col 41.
+        write(u''' / sqrt(''')
+        _v = VFFSL(SL,"fieldCount",True) / 2.0 # u'${fieldCount / 2.0}' on line 29, col 60
+        if _v is not None: write(_filter(_v, rawExpr=u'${fieldCount / 2.0}')) # from line 29, col 60.
+        write(u''')''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def stepWeightAtIndex(self, index, **KWS):
+
+
+
+        ## CHEETAH: generated from @def stepWeightAtIndex($index) at line 33, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''_hermite_gauss_weights_''')
+        _v = VFFSL(SL,"parent.name",True) # u'${parent.name}' on line 35, col 24
+        if _v is not None: write(_filter(_v, rawExpr=u'${parent.name}')) # from line 35, col 24.
+        write(u'''[''')
+        _v = VFFSL(SL,"index",True) # u'$index' on line 35, col 39
+        if _v is not None: write(_filter(_v, rawExpr=u'$index')) # from line 35, col 39.
+        write(u'''] * ''')
+        _v = VFFSL(SL,"_maximum",True) # u'${_maximum}' on line 35, col 49
+        if _v is not None: write(_filter(_v, rawExpr=u'${_maximum}')) # from line 35, col 49.
+        write(u''' / sqrt(''')
+        _v = VFFSL(SL,"fieldCount",True) / 2.0 # u'${fieldCount / 2.0}' on line 35, col 68
+        if _v is not None: write(_filter(_v, rawExpr=u'${fieldCount / 2.0}')) # from line 35, col 68.
+        write(u''')''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def indexForSinglePointSample(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def indexForSinglePointSample at line 39, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  Take the middle point, which is in the middle of the array
+        _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 42, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 42, col 1.
+        write(u'''/2''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def createCoordinateVariableForSinglePointSample(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def createCoordinateVariableForSinglePointSample at line 46, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"type",True) # u'${type}' on line 48, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${type}')) # from line 48, col 1.
+        write(u''' ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 48, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 48, col 9.
+        write(u''' = ''')
+        _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 48, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 48, col 19.
+        write(u'''[''')
+        _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 48, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 48, col 32.
+        write(u'''/2];
+#define d''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 49, col 10
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 49, col 10.
+        write(u''' (''')
+        _v = VFFSL(SL,"stepSizeArrayName",True) # u'${stepSizeArrayName}' on line 49, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepSizeArrayName}')) # from line 49, col 19.
+        write(u'''[''')
+        _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 49, col 40
+        if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 49, col 40.
+        write(u'''/2]  * (''')
+        _v = VFFSL(SL,"volumePrefactor",True) # u'${volumePrefactor}' on line 49, col 64
+        if _v is not None: write(_filter(_v, rawExpr=u'${volumePrefactor}')) # from line 49, col 64.
+        write(u'''))
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # HermiteGaussDimensionRepresentation.tmpl
+        # 
+        # Created by Graham Dennis on 2009-08-12.
+        # 
+        # Copyright (c) 2009-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    instanceAttributes = ['_maximum', 'fieldCount']
+
+    instanceDefaults = {'fieldCount': 2.0}
+
+    _mainCheetahMethod_for_HermiteGaussDimensionRepresentation= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(HermiteGaussDimensionRepresentation, '_initCheetahAttributes'):
+    templateAPIClass = getattr(HermiteGaussDimensionRepresentation, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(HermiteGaussDimensionRepresentation)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=HermiteGaussDimensionRepresentation()).run()
+
+
diff --git a/xpdeint/Geometry/HermiteGaussDimensionRepresentation.tmpl b/xpdeint/Geometry/HermiteGaussDimensionRepresentation.tmpl
new file mode 100644
index 0000000..b78c4cd
--- /dev/null
+++ b/xpdeint/Geometry/HermiteGaussDimensionRepresentation.tmpl
@@ -0,0 +1,51 @@
+@*
+HermiteGaussDimensionRepresentation.tmpl
+
+Created by Graham Dennis on 2009-08-12.
+
+Copyright (c) 2009-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Geometry.NonUniformDimensionRepresentation
+
+ at attr $instanceAttributes = ['_maximum', 'fieldCount']
+ at attr $instanceDefaults = {'fieldCount': 2.0}
+
+ at def gridAtIndex($index)
+  @#
+_hermite_zeros_${parent.name}[$index] * ${_maximum} / sqrt(${fieldCount / 2.0})@slurp
+  @#
+ at end def
+
+ at def stepWeightAtIndex($index)
+  @#
+_hermite_gauss_weights_${parent.name}[$index] * ${_maximum} / sqrt(${fieldCount / 2.0})@slurp
+  @#
+ at end def
+
+ at def indexForSinglePointSample
+  @#
+  @# Take the middle point, which is in the middle of the array
+${globalLattice}/2 at slurp
+  @#
+ at end def
+
+ at def createCoordinateVariableForSinglePointSample
+  @#
+${type} ${name} = ${arrayName}[${globalLattice}/2];
+#define d${name} (${stepSizeArrayName}[${globalLattice}/2]  * (${volumePrefactor}))
+  @#
+ at end def
diff --git a/xpdeint/Geometry/NonUniformDimensionRepresentation.py b/xpdeint/Geometry/NonUniformDimensionRepresentation.py
new file mode 100644
index 0000000..1741cb2
--- /dev/null
+++ b/xpdeint/Geometry/NonUniformDimensionRepresentation.py
@@ -0,0 +1,571 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Geometry._NonUniformDimensionRepresentation import _NonUniformDimensionRepresentation
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.831625
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Geometry/NonUniformDimensionRepresentation.tmpl'
+__CHEETAH_srcLastModified__ = 'Tue May 22 16:27:12 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class NonUniformDimensionRepresentation(_NonUniformDimensionRepresentation):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(NonUniformDimensionRepresentation, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def defines(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def defines at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        if VFFSL(SL,"silent",True): # generated from line 26, col 3
+            return _dummyTrans and trans.response().getvalue() or ""
+        if VFFSL(SL,"runtimeLattice",True): # generated from line 29, col 3
+            _v = super(NonUniformDimensionRepresentation, self).defines()
+            if _v is not None: write(_filter(_v))
+            write(u'''#define ''')
+            _v = VFFSL(SL,"minimum",True) # u'${minimum}' on line 31, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${minimum}')) # from line 31, col 9.
+            write(u'''     (''')
+            _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 31, col 25
+            if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 31, col 25.
+            write(u'''[0])
+#define ''')
+            _v = VFFSL(SL,"maximum",True) # u'${maximum}' on line 32, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${maximum}')) # from line 32, col 9.
+            write(u'''     (''')
+            _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 32, col 25
+            if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 32, col 25.
+            write(u'''[''')
+            _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 32, col 38
+            if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 32, col 38.
+            write(u'''-1])
+''')
+            if not VFFSL(SL,"stepSizeArray",True): # generated from line 33, col 5
+                write(u'''#define ''')
+                _v = VFFSL(SL,"stepSize",True) # u'${stepSize}' on line 34, col 9
+                if _v is not None: write(_filter(_v, rawExpr=u'${stepSize}')) # from line 34, col 9.
+                write(u'''        (''')
+                _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 34, col 29
+                if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 34, col 29.
+                write(u'''[''')
+                _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 34, col 42
+                if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 34, col 42.
+                write(u'''+1]-''')
+                _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 34, col 58
+                if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 34, col 58.
+                write(u'''[''')
+                _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 34, col 71
+                if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 34, col 71.
+                write(u'''])
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def globals at line 40, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        if VFFSL(SL,"silent",True): # generated from line 42, col 3
+            return _dummyTrans and trans.response().getvalue() or ""
+        # 
+        _v = super(NonUniformDimensionRepresentation, self).globals()
+        if _v is not None: write(_filter(_v))
+        # 
+        if VFFSL(SL,"runtimeLattice",True): # generated from line 48, col 3
+            if VFFSL(SL,"stepSizeArray",True): # generated from line 49, col 5
+                _v = VFFSL(SL,"type",True) # u'${type}' on line 50, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${type}')) # from line 50, col 1.
+                write(u'''* ''')
+                _v = VFFSL(SL,"stepSizeArrayName",True) # u'${stepSizeArrayName}' on line 50, col 10
+                if _v is not None: write(_filter(_v, rawExpr=u'${stepSizeArrayName}')) # from line 50, col 10.
+                write(u''' = (''')
+                _v = VFFSL(SL,"type",True) # u'${type}' on line 50, col 34
+                if _v is not None: write(_filter(_v, rawExpr=u'${type}')) # from line 50, col 34.
+                write(u'''*) xmds_malloc(sizeof(''')
+                _v = VFFSL(SL,"type",True) # u'${type}' on line 50, col 63
+                if _v is not None: write(_filter(_v, rawExpr=u'${type}')) # from line 50, col 63.
+                write(u''') * (''')
+                _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 50, col 75
+                if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 50, col 75.
+                write(u'''));
+''')
+            else: # generated from line 51, col 5
+                write(u'''unsigned long ''')
+                _v = VFFSL(SL,"index",True) # u'${index}' on line 52, col 15
+                if _v is not None: write(_filter(_v, rawExpr=u'${index}')) # from line 52, col 15.
+                write(u''' = 0;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def openLoopAscending(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def openLoopAscending at line 58, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''#define ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 60, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 60, col 9.
+        write(u''' ''')
+        _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 60, col 17
+        if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 60, col 17.
+        write(u'''[''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 60, col 30
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 60, col 30.
+        write(u''' + ''')
+        _v = VFFSL(SL,"localOffset",True) # u'${localOffset}' on line 60, col 45
+        if _v is not None: write(_filter(_v, rawExpr=u'${localOffset}')) # from line 60, col 45.
+        write(u''']
+''')
+        if VFFSL(SL,"stepSizeArray",True): # generated from line 61, col 3
+            write(u'''#define d''')
+            _v = VFFSL(SL,"name",True) # u'${name}' on line 62, col 10
+            if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 62, col 10.
+            write(u''' (''')
+            _v = VFFSL(SL,"stepSizeArrayName",True) # u'${stepSizeArrayName}' on line 62, col 19
+            if _v is not None: write(_filter(_v, rawExpr=u'${stepSizeArrayName}')) # from line 62, col 19.
+            write(u'''[''')
+            _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 62, col 40
+            if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 62, col 40.
+            write(u''' + ''')
+            _v = VFFSL(SL,"localOffset",True) # u'${localOffset}' on line 62, col 55
+            if _v is not None: write(_filter(_v, rawExpr=u'${localOffset}')) # from line 62, col 55.
+            write(u'''] * (''')
+            _v = VFFSL(SL,"volumePrefactor",True) # u'${volumePrefactor}' on line 62, col 74
+            if _v is not None: write(_filter(_v, rawExpr=u'${volumePrefactor}')) # from line 62, col 74.
+            write(u'''))
+''')
+        write(u'''
+for (long ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 65, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 65, col 11.
+        write(u''' = 0; ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 65, col 29
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 65, col 29.
+        write(u''' < ''')
+        _v = VFFSL(SL,"localLattice",True) # u'${localLattice}' on line 65, col 44
+        if _v is not None: write(_filter(_v, rawExpr=u'${localLattice}')) # from line 65, col 44.
+        write(u'''; ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 65, col 61
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 65, col 61.
+        write(u'''++) {
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def closeLoopAscending(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def closeLoopAscending at line 68, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''}
+#undef ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 71, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 71, col 8.
+        write(u'''
+''')
+        if VFFSL(SL,"stepSizeArray",True): # generated from line 72, col 3
+            write(u'''#undef d''')
+            _v = VFFSL(SL,"name",True) # u'${name}' on line 73, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 73, col 9.
+            write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def localIndexFromIndexForDimensionRep(self, dimRep, **KWS):
+
+
+
+        ## CHEETAH: generated from @def localIndexFromIndexForDimensionRep($dimRep) at line 78, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''(''')
+        _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 80, col 2
+        if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 80, col 2.
+        write(u''' + ''')
+        _v = VFFSL(SL,"dimRep.localOffset",True) # u'${dimRep.localOffset}' on line 80, col 24
+        if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.localOffset}')) # from line 80, col 24.
+        write(u''') * (''')
+        _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 80, col 50
+        if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 80, col 50.
+        write(u'''/''')
+        _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 80, col 67
+        if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 80, col 67.
+        write(u''') - ''')
+        _v = VFFSL(SL,"localOffset",True) # u'${localOffset}' on line 80, col 94
+        if _v is not None: write(_filter(_v, rawExpr=u'${localOffset}')) # from line 80, col 94.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def strictlyAscendingGlobalIndex(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def strictlyAscendingGlobalIndex at line 84, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 86, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 86, col 1.
+        write(u''' + ''')
+        _v = VFFSL(SL,"localOffset",True) # u'${localOffset}' on line 86, col 16
+        if _v is not None: write(_filter(_v, rawExpr=u'${localOffset}')) # from line 86, col 16.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def initialiseArray(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def initialiseArray at line 90, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        if VFFSL(SL,"stepSizeArray",True): # generated from line 92, col 3
+            write(u'''for (long ''')
+            _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 93, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 93, col 11.
+            write(u''' = 0; ''')
+            _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 93, col 29
+            if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 93, col 29.
+            write(u''' < ''')
+            _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 93, col 44
+            if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 93, col 44.
+            write(u'''; ''')
+            _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 93, col 62
+            if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 93, col 62.
+            write(u'''++) {
+  ''')
+            _v = VFFSL(SL,"gridAndStepAtIndex",False)(self.loopIndex) # u'${gridAndStepAtIndex(self.loopIndex), autoIndent=True}' on line 94, col 3
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${gridAndStepAtIndex(self.loopIndex), autoIndent=True}')) # from line 94, col 3.
+            write(u'''}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def gridAndStepAtIndex(self, index, **KWS):
+
+
+
+        ## CHEETAH: generated from @def gridAndStepAtIndex($index) at line 100, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 102, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 102, col 1.
+        write(u'''[''')
+        _v = VFFSL(SL,"index",True) # u'$index' on line 102, col 14
+        if _v is not None: write(_filter(_v, rawExpr=u'$index')) # from line 102, col 14.
+        write(u'''] = ''')
+        _v = VFFSL(SL,"gridAtIndex",False)(index) # u'${gridAtIndex(index)}' on line 102, col 24
+        if _v is not None: write(_filter(_v, rawExpr=u'${gridAtIndex(index)}')) # from line 102, col 24.
+        write(u''';
+''')
+        _v = VFFSL(SL,"stepSizeArrayName",True) # u'${stepSizeArrayName}' on line 103, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepSizeArrayName}')) # from line 103, col 1.
+        write(u'''[''')
+        _v = VFFSL(SL,"index",True) # u'$index' on line 103, col 22
+        if _v is not None: write(_filter(_v, rawExpr=u'$index')) # from line 103, col 22.
+        write(u'''] = ''')
+        _v = VFFSL(SL,"stepWeightAtIndex",False)(index) # u'${stepWeightAtIndex(index)}' on line 103, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepWeightAtIndex(index)}')) # from line 103, col 32.
+        write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # NonUniformDimensionRepresentation.tmpl
+        # 
+        # Created by Graham Dennis on 2008-07-30.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_NonUniformDimensionRepresentation= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(NonUniformDimensionRepresentation, '_initCheetahAttributes'):
+    templateAPIClass = getattr(NonUniformDimensionRepresentation, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(NonUniformDimensionRepresentation)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=NonUniformDimensionRepresentation()).run()
+
+
diff --git a/xpdeint/Geometry/NonUniformDimensionRepresentation.tmpl b/xpdeint/Geometry/NonUniformDimensionRepresentation.tmpl
new file mode 100644
index 0000000..84d7e35
--- /dev/null
+++ b/xpdeint/Geometry/NonUniformDimensionRepresentation.tmpl
@@ -0,0 +1,105 @@
+@*
+NonUniformDimensionRepresentation.tmpl
+
+Created by Graham Dennis on 2008-07-30.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Geometry._NonUniformDimensionRepresentation
+
+ at def defines
+  @#
+  @if $silent
+    @stop
+  @end if
+  @if $runtimeLattice
+    @super
+#define ${minimum}     (${arrayName}[0])
+#define ${maximum}     (${arrayName}[${globalLattice}-1])
+    @if not $stepSizeArray
+#define ${stepSize}        (${arrayName}[${loopIndex}+1]-${arrayName}[${loopIndex}])
+    @end if
+  @end if
+  @#
+ at end def
+
+ at def globals
+  @#
+  @if $silent
+    @stop
+  @end if
+  @#
+  @super
+  @#
+  @if $runtimeLattice
+    @if $stepSizeArray
+${type}* ${stepSizeArrayName} = (${type}*) xmds_malloc(sizeof(${type}) * (${globalLattice}));
+    @else
+unsigned long ${index} = 0;
+    @end if
+  @end if
+  @#
+ at end def
+
+ at def openLoopAscending
+  @#
+#define ${name} ${arrayName}[${loopIndex} + ${localOffset}]
+  @if $stepSizeArray
+#define d${name} (${stepSizeArrayName}[${loopIndex} + ${localOffset}] * (${volumePrefactor}))
+  @end if
+
+for (long ${loopIndex} = 0; ${loopIndex} < ${localLattice}; ${loopIndex}++) {
+ at end def
+
+ at def closeLoopAscending
+  @#
+}
+#undef ${name}
+  @if $stepSizeArray
+#undef d${name}
+  @end if
+  @#
+ at end def
+
+ at def localIndexFromIndexForDimensionRep($dimRep)
+  @#
+(${dimRep.loopIndex} + ${dimRep.localOffset}) * (${globalLattice}/${dimRep.globalLattice}) - ${localOffset}@slurp
+  @#
+ at end def
+
+ at def strictlyAscendingGlobalIndex
+  @#
+${loopIndex} + ${localOffset}@slurp
+  @#
+ at end def
+
+ at def initialiseArray
+  @#
+  @if $stepSizeArray
+for (long ${loopIndex} = 0; ${loopIndex} < ${globalLattice}; ${loopIndex}++) {
+  ${gridAndStepAtIndex(self.loopIndex), autoIndent=True}@slurp
+}
+  @end if
+  @#
+ at end def
+
+ at def gridAndStepAtIndex($index)
+  @#
+${arrayName}[$index] = ${gridAtIndex(index)};
+${stepSizeArrayName}[$index] = ${stepWeightAtIndex(index)};
+  @#
+ at end def
diff --git a/xpdeint/Geometry/SphericalBesselDimensionRepresentation.py b/xpdeint/Geometry/SphericalBesselDimensionRepresentation.py
new file mode 100644
index 0000000..da9fb59
--- /dev/null
+++ b/xpdeint/Geometry/SphericalBesselDimensionRepresentation.py
@@ -0,0 +1,283 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Geometry.BesselDimensionRepresentation import BesselDimensionRepresentation
+from xpdeint.CallOnceGuards import callOnceGuard
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.795984
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Geometry/SphericalBesselDimensionRepresentation.tmpl'
+__CHEETAH_srcLastModified__ = 'Fri Sep 14 16:04:46 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class SphericalBesselDimensionRepresentation(BesselDimensionRepresentation):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(SphericalBesselDimensionRepresentation, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    @callOnceGuard
+    def includes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def includes at line 31, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''#include <gsl/gsl_sf_bessel.h>
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def besselJFunctionCall(self, order, argument, **KWS):
+
+
+
+        ## CHEETAH: generated from @def besselJFunctionCall($order, $argument) at line 37, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''sqrt(1.0/M_PI_2) * ''')
+        if VFFSL(SL,"order",True) in [0, 1, 2]: # generated from line 39, col 3
+            write(u'''gsl_sf_bessel_j''')
+            _v = VFFSL(SL,"order",True) # u'${order}' on line 40, col 16
+            if _v is not None: write(_filter(_v, rawExpr=u'${order}')) # from line 40, col 16.
+            write(u'''(''')
+            _v = VFFSL(SL,"argument",True) # u'$argument' on line 40, col 25
+            if _v is not None: write(_filter(_v, rawExpr=u'$argument')) # from line 40, col 25.
+            write(u''')''')
+        else: # generated from line 41, col 3
+            write(u'''gsl_sf_bessel_jl(''')
+            _v = VFFSL(SL,"order",True) # u'$order' on line 42, col 18
+            if _v is not None: write(_filter(_v, rawExpr=u'$order')) # from line 42, col 18.
+            write(u''', ''')
+            _v = VFFSL(SL,"argument",True) # u'$argument' on line 42, col 26
+            if _v is not None: write(_filter(_v, rawExpr=u'$argument')) # from line 42, col 26.
+            write(u''')''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def stepWeightAtIndex(self, index, **KWS):
+
+
+
+        ## CHEETAH: generated from @def stepWeightAtIndex($index) at line 46, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''2.0 / (besselFactor * besselFactor * _besseljnorm_''')
+        _v = VFFSL(SL,"parent.name",True) # u'${parent.name}' on line 48, col 51
+        if _v is not None: write(_filter(_v, rawExpr=u'${parent.name}')) # from line 48, col 51.
+        write(u''' * _besseljnorm_''')
+        _v = VFFSL(SL,"parent.name",True) # u'${parent.name}' on line 48, col 81
+        if _v is not None: write(_filter(_v, rawExpr=u'${parent.name}')) # from line 48, col 81.
+        write(u''' * _besseljnorm_''')
+        _v = VFFSL(SL,"parent.name",True) # u'${parent.name}' on line 48, col 111
+        if _v is not None: write(_filter(_v, rawExpr=u'${parent.name}')) # from line 48, col 111.
+        write(u''') * ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 48, col 129
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 48, col 129.
+        write(u'''_max * ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 48, col 143
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 48, col 143.
+        write(u'''_max * ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 48, col 157
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 48, col 157.
+        write(u'''_max''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # SphericalBesselDimensionRepresentation.tmpl
+        # 
+        # Created by Graham Dennis on 2009-08-11.
+        # 
+        # Copyright (c) 2009-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    uslib = ['gsl']
+
+    orderOffset = 0.5
+
+    _mainCheetahMethod_for_SphericalBesselDimensionRepresentation= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(SphericalBesselDimensionRepresentation, '_initCheetahAttributes'):
+    templateAPIClass = getattr(SphericalBesselDimensionRepresentation, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(SphericalBesselDimensionRepresentation)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=SphericalBesselDimensionRepresentation()).run()
+
+
diff --git a/xpdeint/Geometry/SphericalBesselDimensionRepresentation.tmpl b/xpdeint/Geometry/SphericalBesselDimensionRepresentation.tmpl
new file mode 100644
index 0000000..238fde1
--- /dev/null
+++ b/xpdeint/Geometry/SphericalBesselDimensionRepresentation.tmpl
@@ -0,0 +1,50 @@
+@*
+SphericalBesselDimensionRepresentation.tmpl
+
+Created by Graham Dennis on 2009-08-11.
+
+Copyright (c) 2009-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Geometry.BesselDimensionRepresentation
+
+ at from xpdeint.CallOnceGuards import callOnceGuard
+
+ at attr $uslib = ['gsl']
+
+ at attr $orderOffset = 0.5
+
+@@callOnceGuard
+ at def includes
+  @#
+#include <gsl/gsl_sf_bessel.h>
+  @#
+ at end def
+
+ at def besselJFunctionCall($order, $argument)
+sqrt(1.0/M_PI_2) * @slurp
+  @if $order in [0, 1, 2]
+gsl_sf_bessel_j${order}($argument)@slurp
+  @else
+gsl_sf_bessel_jl($order, $argument)@slurp
+  @end if
+ at end def
+
+ at def stepWeightAtIndex($index)
+  @#
+2.0 / (besselFactor * besselFactor * _besseljnorm_${parent.name} * _besseljnorm_${parent.name} * _besseljnorm_${parent.name}) * ${name}_max * ${name}_max * ${name}_max at slurp
+  @#
+ at end def
diff --git a/xpdeint/Geometry/SplitUniformDimensionRepresentation.py b/xpdeint/Geometry/SplitUniformDimensionRepresentation.py
new file mode 100644
index 0000000..5e222c8
--- /dev/null
+++ b/xpdeint/Geometry/SplitUniformDimensionRepresentation.py
@@ -0,0 +1,717 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Geometry._SplitUniformDimensionRepresentation import _SplitUniformDimensionRepresentation
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.917479
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Geometry/SplitUniformDimensionRepresentation.tmpl'
+__CHEETAH_srcLastModified__ = 'Fri Jul 13 16:21:46 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class SplitUniformDimensionRepresentation(_SplitUniformDimensionRepresentation):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(SplitUniformDimensionRepresentation, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def defines(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def defines at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(SplitUniformDimensionRepresentation, self).defines()
+        if _v is not None: write(_filter(_v))
+        if VFFSL(SL,"silent",True): # generated from line 27, col 3
+            return _dummyTrans and trans.response().getvalue() or ""
+        # 
+        write(u'''#define ''')
+        _v = VFFSL(SL,"stepSize",True) # u'${stepSize}' on line 31, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepSize}')) # from line 31, col 9.
+        write(u'''        (2.0*M_PI/(''')
+        _v = VFFSL(SL,"_range",True) # u'$_range' on line 31, col 39
+        if _v is not None: write(_filter(_v, rawExpr=u'$_range')) # from line 31, col 39.
+        write(u'''))
+#define ''')
+        _v = VFFSL(SL,"minimum",True) # u'${minimum}' on line 32, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${minimum}')) # from line 32, col 9.
+        write(u'''     (-(''')
+        _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 32, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 32, col 27.
+        write(u'''/2) * ''')
+        _v = VFFSL(SL,"stepSize",True) # u'${stepSize}' on line 32, col 49
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepSize}')) # from line 32, col 49.
+        write(u''')
+#define ''')
+        _v = VFFSL(SL,"maximum",True) # u'${maximum}' on line 33, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${maximum}')) # from line 33, col 9.
+        write(u'''     ((''')
+        _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 33, col 26
+        if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 33, col 26.
+        write(u''' - 1)/2 * ''')
+        _v = VFFSL(SL,"stepSize",True) # u'${stepSize}' on line 33, col 52
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepSize}')) # from line 33, col 52.
+        write(u''')
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def openLoopMemoryOrder(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def openLoopMemoryOrder at line 37, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''#define ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 39, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 39, col 9.
+        write(u''' ''')
+        _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 39, col 17
+        if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 39, col 17.
+        write(u'''[''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 39, col 30
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 39, col 30.
+        write(u''' + ''')
+        _v = VFFSL(SL,"localOffset",True) # u'${localOffset}' on line 39, col 45
+        if _v is not None: write(_filter(_v, rawExpr=u'${localOffset}')) # from line 39, col 45.
+        write(u''']
+#define d''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 40, col 10
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 40, col 10.
+        write(u''' (''')
+        _v = VFFSL(SL,"stepSize",True) # u'${stepSize}' on line 40, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepSize}')) # from line 40, col 19.
+        write(u''' * (''')
+        _v = VFFSL(SL,"volumePrefactor",True) # u'${volumePrefactor}' on line 40, col 34
+        if _v is not None: write(_filter(_v, rawExpr=u'${volumePrefactor}')) # from line 40, col 34.
+        write(u'''))
+
+for (long ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 42, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 42, col 11.
+        write(u''' = 0; ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 42, col 29
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 42, col 29.
+        write(u''' < ''')
+        _v = VFFSL(SL,"localLattice",True) # u'${localLattice}' on line 42, col 44
+        if _v is not None: write(_filter(_v, rawExpr=u'${localLattice}')) # from line 42, col 44.
+        write(u'''; ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 42, col 61
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 42, col 61.
+        write(u'''++) {
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def closeLoopMemoryOrder(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def closeLoopMemoryOrder at line 46, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''}
+#undef ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 49, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 49, col 8.
+        write(u'''
+#undef d''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 50, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 50, col 9.
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def openLoopAscending(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def openLoopAscending at line 54, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''#define ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 56, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 56, col 9.
+        write(u''' ''')
+        _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 56, col 17
+        if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 56, col 17.
+        write(u'''[''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 56, col 30
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 56, col 30.
+        write(u''' + ''')
+        _v = VFFSL(SL,"localOffset",True) # u'${localOffset}' on line 56, col 45
+        if _v is not None: write(_filter(_v, rawExpr=u'${localOffset}')) # from line 56, col 45.
+        write(u''']
+#define d''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 57, col 10
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 57, col 10.
+        write(u''' (''')
+        _v = VFFSL(SL,"stepSize",True) # u'${stepSize}' on line 57, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepSize}')) # from line 57, col 19.
+        write(u''' * (''')
+        _v = VFFSL(SL,"volumePrefactor",True) # u'${volumePrefactor}' on line 57, col 34
+        if _v is not None: write(_filter(_v, rawExpr=u'${volumePrefactor}')) # from line 57, col 34.
+        write(u'''))
+
+for (long ''')
+        _v = VFFSL(SL,"alternateLoopIndex",True) # u'${alternateLoopIndex}' on line 59, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'${alternateLoopIndex}')) # from line 59, col 11.
+        write(u''' = -(''')
+        _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 59, col 37
+        if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 59, col 37.
+        write(u'''/2); ''')
+        _v = VFFSL(SL,"alternateLoopIndex",True) # u'${alternateLoopIndex}' on line 59, col 58
+        if _v is not None: write(_filter(_v, rawExpr=u'${alternateLoopIndex}')) # from line 59, col 58.
+        write(u''' < (''')
+        _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 59, col 83
+        if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 59, col 83.
+        write(u''' + 1)/2; ''')
+        _v = VFFSL(SL,"alternateLoopIndex",True) # u'${alternateLoopIndex}' on line 59, col 108
+        if _v is not None: write(_filter(_v, rawExpr=u'${alternateLoopIndex}')) # from line 59, col 108.
+        write(u'''++) {
+  long ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 60, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 60, col 8.
+        write(u''' = ''')
+        _v = VFFSL(SL,"alternateLoopIndex",True) # u'${alternateLoopIndex}' on line 60, col 23
+        if _v is not None: write(_filter(_v, rawExpr=u'${alternateLoopIndex}')) # from line 60, col 23.
+        write(u''';
+  if (''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 61, col 7
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 61, col 7.
+        write(u''' < 0)
+    ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 62, col 5
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 62, col 5.
+        write(u''' += ''')
+        _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 62, col 21
+        if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 62, col 21.
+        write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def closeLoopAscending(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def closeLoopAscending at line 66, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''}
+#undef ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 69, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 69, col 8.
+        write(u'''
+#undef d''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 70, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 70, col 9.
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def localIndexFromIndexForDimensionRep(self, dimRep, **KWS):
+
+
+
+        ## CHEETAH: generated from @def localIndexFromIndexForDimensionRep($dimRep) at line 74, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        #  Check that our lattice has more points than the other lattice (provided we
+        #  know how many points each lattice actually has - if the lattice is defined
+        #  at runtime we'll just have string rather than a number, so we can't judge).
+        assert isinstance(VFFSL(SL,"runtimeLattice",True), basestring) or isinstance(dimRep.runtimeLattice, basestring) or VFFSL(SL,"runtimeLattice",True) >= dimRep.runtimeLattice
+        # 
+        _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 80, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 80, col 1.
+        write(u''' + ''')
+        _v = VFFSL(SL,"dimRep.localOffset",True) # u'${dimRep.localOffset}' on line 80, col 23
+        if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.localOffset}')) # from line 80, col 23.
+        write(u''' - ''')
+        _v = VFFSL(SL,"localOffset",True) # u'${localOffset}' on line 80, col 47
+        if _v is not None: write(_filter(_v, rawExpr=u'${localOffset}')) # from line 80, col 47.
+        write(u''' + (signbit(''')
+        _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 80, col 73
+        if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 80, col 73.
+        write(u''') ? (''')
+        _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 80, col 92
+        if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 80, col 92.
+        write(u''' - ''')
+        _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 80, col 111
+        if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 80, col 111.
+        write(u''') : 0)''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def strictlyAscendingGlobalIndex(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def strictlyAscendingGlobalIndex at line 84, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        if not VFFSL(SL,"hasLocalOffset",True): # generated from line 86, col 3
+            _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 87, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 87, col 1.
+            write(u''' + (signbit(''')
+            _v = VFFSL(SL,"name",True) # u'${name}' on line 87, col 25
+            if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 87, col 25.
+            write(u''') ? -(''')
+            _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 87, col 38
+            if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 87, col 38.
+            write(u'''+1)/2 : ''')
+            _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 87, col 62
+            if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 87, col 62.
+            write(u'''/2)''')
+        else: # generated from line 88, col 3
+            write(u'''lround(''')
+            _v = VFFSL(SL,"name",True) # u'${name}' on line 89, col 8
+            if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 89, col 8.
+            write(u'''/''')
+            _v = VFFSL(SL,"stepSize",True) # u'${stepSize}' on line 89, col 16
+            if _v is not None: write(_filter(_v, rawExpr=u'${stepSize}')) # from line 89, col 16.
+            write(u''') + ''')
+            _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 89, col 31
+            if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 89, col 31.
+            write(u'''/2''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def indexForSinglePointSample(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def indexForSinglePointSample at line 94, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  We want to sample the middle, as that is just the first point in memory, return 0
+        #  (Don't worry about multiplication by zero, any smart compiler will optimise that out)
+        write(u'''0''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def createCoordinateVariableForSinglePointSample(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def createCoordinateVariableForSinglePointSample at line 102, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"type",True) # u'${type}' on line 104, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${type}')) # from line 104, col 1.
+        write(u''' ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 104, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 104, col 9.
+        write(u''' = 0.0;
+#define d''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 105, col 10
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 105, col 10.
+        write(u''' (''')
+        _v = VFFSL(SL,"stepSize",True) # u'${stepSize}' on line 105, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepSize}')) # from line 105, col 19.
+        write(u''' * (''')
+        _v = VFFSL(SL,"volumePrefactor",True) # u'${volumePrefactor}' on line 105, col 34
+        if _v is not None: write(_filter(_v, rawExpr=u'${volumePrefactor}')) # from line 105, col 34.
+        write(u'''))
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def initialiseArray(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def initialiseArray at line 109, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''for (long ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 111, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 111, col 11.
+        write(u''' = 0; ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 111, col 29
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 111, col 29.
+        write(u''' < (''')
+        _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 111, col 45
+        if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 111, col 45.
+        write(u'''+1)/2; ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 111, col 68
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 111, col 68.
+        write(u'''++)
+  ''')
+        _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 112, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 112, col 3.
+        write(u'''[''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 112, col 16
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 112, col 16.
+        write(u'''] = ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 112, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 112, col 32.
+        write(u'''*''')
+        _v = VFFSL(SL,"stepSize",True) # u'${stepSize}' on line 112, col 45
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepSize}')) # from line 112, col 45.
+        write(u''';
+for (long ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 113, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 113, col 11.
+        write(u''' = (''')
+        _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 113, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 113, col 27.
+        write(u'''+1)/2; ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 113, col 50
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 113, col 50.
+        write(u''' < ''')
+        _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 113, col 65
+        if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 113, col 65.
+        write(u'''; ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 113, col 83
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 113, col 83.
+        write(u'''++)
+  ''')
+        _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 114, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 114, col 3.
+        write(u'''[''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 114, col 16
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 114, col 16.
+        write(u'''] = -(''')
+        _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 114, col 34
+        if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 114, col 34.
+        write(u''' - ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 114, col 53
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 114, col 53.
+        write(u''') * ''')
+        _v = VFFSL(SL,"stepSize",True) # u'${stepSize}' on line 114, col 69
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepSize}')) # from line 114, col 69.
+        write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # SplitUniformDimensionRepresentation.tmpl
+        # 
+        # Created by Graham Dennis on 2008-07-31.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_SplitUniformDimensionRepresentation= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(SplitUniformDimensionRepresentation, '_initCheetahAttributes'):
+    templateAPIClass = getattr(SplitUniformDimensionRepresentation, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(SplitUniformDimensionRepresentation)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=SplitUniformDimensionRepresentation()).run()
+
+
diff --git a/xpdeint/Geometry/SplitUniformDimensionRepresentation.tmpl b/xpdeint/Geometry/SplitUniformDimensionRepresentation.tmpl
new file mode 100644
index 0000000..8753151
--- /dev/null
+++ b/xpdeint/Geometry/SplitUniformDimensionRepresentation.tmpl
@@ -0,0 +1,117 @@
+@*
+SplitUniformDimensionRepresentation.tmpl
+
+Created by Graham Dennis on 2008-07-31.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Geometry._SplitUniformDimensionRepresentation
+
+ at def defines
+  @#
+  @super
+  @if $silent
+    @stop
+  @end if
+  @#
+#define ${stepSize}        (2.0*M_PI/($_range))
+#define ${minimum}     (-(${globalLattice}/2) * ${stepSize})
+#define ${maximum}     ((${globalLattice} - 1)/2 * ${stepSize})
+  @#
+ at end def
+
+ at def openLoopMemoryOrder
+  @#
+#define ${name} ${arrayName}[${loopIndex} + ${localOffset}]
+#define d${name} (${stepSize} * (${volumePrefactor}))
+
+for (long ${loopIndex} = 0; ${loopIndex} < ${localLattice}; ${loopIndex}++) {
+  @#
+ at end def
+
+ at def closeLoopMemoryOrder
+  @#
+}
+#undef ${name}
+#undef d${name}
+  @#
+ at end def
+
+ at def openLoopAscending
+  @#
+#define ${name} ${arrayName}[${loopIndex} + ${localOffset}]
+#define d${name} (${stepSize} * (${volumePrefactor}))
+
+for (long ${alternateLoopIndex} = -(${globalLattice}/2); ${alternateLoopIndex} < (${globalLattice} + 1)/2; ${alternateLoopIndex}++) {
+  long ${loopIndex} = ${alternateLoopIndex};
+  if (${loopIndex} < 0)
+    ${loopIndex} += ${globalLattice};
+  @#
+ at end def
+
+ at def closeLoopAscending
+  @#
+}
+#undef ${name}
+#undef d${name}
+  @#
+ at end def
+
+ at def localIndexFromIndexForDimensionRep($dimRep)
+  @# Check that our lattice has more points than the other lattice (provided we
+  @# know how many points each lattice actually has - if the lattice is defined
+  @# at runtime we'll just have string rather than a number, so we can't judge).
+  @assert isinstance($runtimeLattice, basestring) or isinstance(dimRep.runtimeLattice, basestring) or $runtimeLattice >= dimRep.runtimeLattice
+  @#
+${dimRep.loopIndex} + ${dimRep.localOffset} - ${localOffset} + (signbit(${dimRep.name}) ? (${globalLattice} - ${dimRep.globalLattice}) : 0)@slurp
+  @#
+ at end def
+
+ at def strictlyAscendingGlobalIndex
+  @#
+  @if not $hasLocalOffset
+${loopIndex} + (signbit(${name}) ? -(${globalLattice}+1)/2 : ${globalLattice}/2)@slurp
+  @else
+lround(${name}/${stepSize}) + ${globalLattice}/2 at slurp
+  @end if
+  @#
+ at end def
+
+ at def indexForSinglePointSample
+  @#
+  @# We want to sample the middle, as that is just the first point in memory, return 0
+  @# (Don't worry about multiplication by zero, any smart compiler will optimise that out)
+0 at slurp
+  @#
+ at end def
+
+ at def createCoordinateVariableForSinglePointSample
+  @#
+${type} ${name} = 0.0;
+#define d${name} (${stepSize} * (${volumePrefactor}))
+  @#
+ at end def
+
+ at def initialiseArray
+  @#
+for (long ${loopIndex} = 0; ${loopIndex} < (${globalLattice}+1)/2; ${loopIndex}++)
+  ${arrayName}[${loopIndex}] = ${loopIndex}*${stepSize};
+for (long ${loopIndex} = (${globalLattice}+1)/2; ${loopIndex} < ${globalLattice}; ${loopIndex}++)
+  ${arrayName}[${loopIndex}] = -(${globalLattice} - ${loopIndex}) * ${stepSize};
+  @#
+ at end def
+
diff --git a/xpdeint/Geometry/UniformDimensionRepresentation.py b/xpdeint/Geometry/UniformDimensionRepresentation.py
new file mode 100644
index 0000000..1992ea7
--- /dev/null
+++ b/xpdeint/Geometry/UniformDimensionRepresentation.py
@@ -0,0 +1,671 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Geometry._UniformDimensionRepresentation import _UniformDimensionRepresentation
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.925564
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Geometry/UniformDimensionRepresentation.tmpl'
+__CHEETAH_srcLastModified__ = 'Fri Jul 13 16:21:46 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class UniformDimensionRepresentation(_UniformDimensionRepresentation):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(UniformDimensionRepresentation, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def defines(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def defines at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(UniformDimensionRepresentation, self).defines()
+        if _v is not None: write(_filter(_v))
+        if VFFSL(SL,"silent",True): # generated from line 27, col 3
+            return _dummyTrans and trans.response().getvalue() or ""
+        # 
+        write(u'''#define ''')
+        _v = VFFSL(SL,"minimum",True) # u'${minimum}' on line 31, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${minimum}')) # from line 31, col 9.
+        write(u'''     ((''')
+        _v = VFFSL(SL,"type",True) # u'$type' on line 31, col 26
+        if _v is not None: write(_filter(_v, rawExpr=u'$type')) # from line 31, col 26.
+        write(u''')''')
+        _v = VFFSL(SL,"_minimum",True) # u'${_minimum}' on line 31, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'${_minimum}')) # from line 31, col 32.
+        write(u''')
+#define ''')
+        _v = VFFSL(SL,"maximum",True) # u'${maximum}' on line 32, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${maximum}')) # from line 32, col 9.
+        write(u'''     ((''')
+        _v = VFFSL(SL,"type",True) # u'$type' on line 32, col 26
+        if _v is not None: write(_filter(_v, rawExpr=u'$type')) # from line 32, col 26.
+        write(u''')''')
+        _v = VFFSL(SL,"_maximum",True) # u'${_maximum}' on line 32, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'${_maximum}')) # from line 32, col 32.
+        write(u''')
+#define ''')
+        _v = VFFSL(SL,"stepSize",True) # u'${stepSize}' on line 33, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepSize}')) # from line 33, col 9.
+        write(u'''        ((''')
+        _v = VFFSL(SL,"type",True) # u'$type' on line 33, col 30
+        if _v is not None: write(_filter(_v, rawExpr=u'$type')) # from line 33, col 30.
+        write(u''')''')
+        _v = VFFSL(SL,"stepSizeString",True) # u'${stepSizeString}' on line 33, col 36
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepSizeString}')) # from line 33, col 36.
+        write(u''')
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def openLoopAscending(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def openLoopAscending at line 37, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''#define ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 39, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 39, col 9.
+        write(u''' ''')
+        _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 39, col 17
+        if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 39, col 17.
+        write(u'''[''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 39, col 30
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 39, col 30.
+        write(u''' + ''')
+        _v = VFFSL(SL,"localOffset",True) # u'${localOffset}' on line 39, col 45
+        if _v is not None: write(_filter(_v, rawExpr=u'${localOffset}')) # from line 39, col 45.
+        write(u''']
+#define d''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 40, col 10
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 40, col 10.
+        write(u''' (''')
+        _v = VFFSL(SL,"stepSize",True) # u'${stepSize}' on line 40, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepSize}')) # from line 40, col 19.
+        write(u''' * (''')
+        _v = VFFSL(SL,"volumePrefactor",True) # u'${volumePrefactor}' on line 40, col 34
+        if _v is not None: write(_filter(_v, rawExpr=u'${volumePrefactor}')) # from line 40, col 34.
+        write(u'''))
+
+for (long ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 42, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 42, col 11.
+        write(u''' = 0; ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 42, col 29
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 42, col 29.
+        write(u''' < ''')
+        _v = VFFSL(SL,"localLattice",True) # u'${localLattice}' on line 42, col 44
+        if _v is not None: write(_filter(_v, rawExpr=u'${localLattice}')) # from line 42, col 44.
+        write(u'''; ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 42, col 61
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 42, col 61.
+        write(u'''++) {
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def closeLoopAscending(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def closeLoopAscending at line 46, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''}
+#undef ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 49, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 49, col 8.
+        write(u'''
+#undef d''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 50, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 50, col 9.
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def openLoopDescending(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def openLoopDescending at line 54, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''#define ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 56, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 56, col 9.
+        write(u''' ''')
+        _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 56, col 17
+        if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 56, col 17.
+        write(u'''[''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 56, col 30
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 56, col 30.
+        write(u''' + ''')
+        _v = VFFSL(SL,"localOffset",True) # u'${localOffset}' on line 56, col 45
+        if _v is not None: write(_filter(_v, rawExpr=u'${localOffset}')) # from line 56, col 45.
+        write(u''']
+#define d''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 57, col 10
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 57, col 10.
+        write(u''' (''')
+        _v = VFFSL(SL,"stepSize",True) # u'${stepSize}' on line 57, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepSize}')) # from line 57, col 19.
+        write(u''' * (''')
+        _v = VFFSL(SL,"volumePrefactor",True) # u'${volumePrefactor}' on line 57, col 34
+        if _v is not None: write(_filter(_v, rawExpr=u'${volumePrefactor}')) # from line 57, col 34.
+        write(u'''))
+
+for (long ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 59, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 59, col 11.
+        write(u''' = ''')
+        _v = VFFSL(SL,"localLattice",True) # u'${localLattice}' on line 59, col 26
+        if _v is not None: write(_filter(_v, rawExpr=u'${localLattice}')) # from line 59, col 26.
+        write(u'''-1; ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 59, col 45
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 59, col 45.
+        write(u''' >= 0; ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 59, col 64
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 59, col 64.
+        write(u'''--) {
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def closeLoopDescending(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def closeLoopDescending at line 63, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''}
+#undef ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 66, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 66, col 8.
+        write(u'''
+#undef d''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 67, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 67, col 9.
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def localIndexFromIndexForDimensionRep(self, dimRep, **KWS):
+
+
+
+        ## CHEETAH: generated from @def localIndexFromIndexForDimensionRep($dimRep) at line 71, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        if VFFSL(SL,"dimRep.runtimeLattice",True) == VFFSL(SL,"runtimeLattice",True) or VFFSL(SL,"dimRep.reductionMethod",True) == VFFSL(SL,"ReductionMethod.fixedStep",True): # generated from line 72, col 3
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 73, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 73, col 1.
+            write(u''' + ''')
+            _v = VFFSL(SL,"dimRep.localOffset",True) # u'${dimRep.localOffset}' on line 73, col 23
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.localOffset}')) # from line 73, col 23.
+            write(u''' - ''')
+            _v = VFFSL(SL,"localOffset",True) # u'${localOffset}' on line 73, col 47
+            if _v is not None: write(_filter(_v, rawExpr=u'${localOffset}')) # from line 73, col 47.
+        elif VFFSL(SL,"dimRep.reductionMethod",True) == VFFSL(SL,"ReductionMethod.fixedRange",True): # generated from line 74, col 3
+            #  We are using a fixed-range reduction method.
+            # 
+            write(u'''(''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 77, col 2
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 77, col 2.
+            write(u''' + ''')
+            _v = VFFSL(SL,"dimRep.localOffset",True) # u'${dimRep.localOffset}' on line 77, col 24
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.localOffset}')) # from line 77, col 24.
+            write(u''') * (''')
+            _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 77, col 50
+            if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 77, col 50.
+            write(u'''/''')
+            _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 77, col 67
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 77, col 67.
+            write(u''') - ''')
+            _v = VFFSL(SL,"localOffset",True) # u'${localOffset}' on line 77, col 94
+            if _v is not None: write(_filter(_v, rawExpr=u'${localOffset}')) # from line 77, col 94.
+        else: # generated from line 78, col 3
+            assert False
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def strictlyAscendingGlobalIndex(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def strictlyAscendingGlobalIndex at line 84, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        if not VFFSL(SL,"hasLocalOffset",True): # generated from line 86, col 3
+            return VFFSL(SL,"loopIndex",True)
+        else: # generated from line 88, col 3
+            write(u'''lround((''')
+            _v = VFFSL(SL,"name",True) # u'${name}' on line 89, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 89, col 9.
+            write(u''' - ''')
+            _v = VFFSL(SL,"minimum",True) # u'${minimum}' on line 89, col 19
+            if _v is not None: write(_filter(_v, rawExpr=u'${minimum}')) # from line 89, col 19.
+            write(u''')/''')
+            _v = VFFSL(SL,"stepSize",True) # u'${stepSize}' on line 89, col 31
+            if _v is not None: write(_filter(_v, rawExpr=u'${stepSize}')) # from line 89, col 31.
+            write(u''')''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def indexForSinglePointSample(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def indexForSinglePointSample at line 94, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  Take the middle point, which is in the middle of the array
+        _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 97, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 97, col 1.
+        write(u'''/2''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def createCoordinateVariableForSinglePointSample(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def createCoordinateVariableForSinglePointSample at line 101, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"type",True) # u'${type}' on line 103, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${type}')) # from line 103, col 1.
+        write(u''' ''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 103, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 103, col 9.
+        write(u''' = ''')
+        _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 103, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 103, col 19.
+        write(u'''[''')
+        _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 103, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 103, col 32.
+        write(u'''/2];
+#define d''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 104, col 10
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 104, col 10.
+        write(u''' (''')
+        _v = VFFSL(SL,"stepSize",True) # u'${stepSize}' on line 104, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepSize}')) # from line 104, col 19.
+        write(u''' * (''')
+        _v = VFFSL(SL,"volumePrefactor",True) # u'${volumePrefactor}' on line 104, col 34
+        if _v is not None: write(_filter(_v, rawExpr=u'${volumePrefactor}')) # from line 104, col 34.
+        write(u'''))
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def initialiseArray(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def initialiseArray at line 108, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''for (long ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 110, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 110, col 11.
+        write(u''' = 0; ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 110, col 29
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 110, col 29.
+        write(u''' < ''')
+        _v = VFFSL(SL,"globalLattice",True) # u'${globalLattice}' on line 110, col 44
+        if _v is not None: write(_filter(_v, rawExpr=u'${globalLattice}')) # from line 110, col 44.
+        write(u'''; ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 110, col 62
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 110, col 62.
+        write(u'''++)
+  ''')
+        _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 111, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 111, col 3.
+        write(u'''[''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 111, col 16
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 111, col 16.
+        write(u'''] = ''')
+        _v = VFFSL(SL,"minimum",True) # u'${minimum}' on line 111, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'${minimum}')) # from line 111, col 32.
+        write(u''' + ''')
+        _v = VFFSL(SL,"loopIndex",True) # u'${loopIndex}' on line 111, col 45
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopIndex}')) # from line 111, col 45.
+        write(u'''*''')
+        _v = VFFSL(SL,"stepSize",True) # u'${stepSize}' on line 111, col 58
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepSize}')) # from line 111, col 58.
+        write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # UniformDimensionRepresentation.tmpl
+        # 
+        # Created by Graham Dennis on 2008-07-31.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_UniformDimensionRepresentation= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(UniformDimensionRepresentation, '_initCheetahAttributes'):
+    templateAPIClass = getattr(UniformDimensionRepresentation, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(UniformDimensionRepresentation)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=UniformDimensionRepresentation()).run()
+
+
diff --git a/xpdeint/Geometry/UniformDimensionRepresentation.tmpl b/xpdeint/Geometry/UniformDimensionRepresentation.tmpl
new file mode 100644
index 0000000..1431efb
--- /dev/null
+++ b/xpdeint/Geometry/UniformDimensionRepresentation.tmpl
@@ -0,0 +1,113 @@
+@*
+UniformDimensionRepresentation.tmpl
+
+Created by Graham Dennis on 2008-07-31.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Geometry._UniformDimensionRepresentation
+
+ at def defines
+  @#
+  @super
+  @if $silent
+    @stop
+  @end if
+  @#
+#define ${minimum}     (($type)${_minimum})
+#define ${maximum}     (($type)${_maximum})
+#define ${stepSize}        (($type)${stepSizeString})
+  @#
+ at end def
+
+ at def openLoopAscending
+  @#
+#define ${name} ${arrayName}[${loopIndex} + ${localOffset}]
+#define d${name} (${stepSize} * (${volumePrefactor}))
+
+for (long ${loopIndex} = 0; ${loopIndex} < ${localLattice}; ${loopIndex}++) {
+  @#
+ at end def
+
+ at def closeLoopAscending
+  @#
+}
+#undef ${name}
+#undef d${name}
+  @#
+ at end def
+
+ at def openLoopDescending
+  @#
+#define ${name} ${arrayName}[${loopIndex} + ${localOffset}]
+#define d${name} (${stepSize} * (${volumePrefactor}))
+
+for (long ${loopIndex} = ${localLattice}-1; ${loopIndex} >= 0; ${loopIndex}--) {
+  @#
+ at end def
+
+ at def closeLoopDescending
+  @#
+}
+#undef ${name}
+#undef d${name}
+  @#
+ at end def
+
+ at def localIndexFromIndexForDimensionRep($dimRep)
+  @if $dimRep.runtimeLattice == $runtimeLattice or $dimRep.reductionMethod == $ReductionMethod.fixedStep
+${dimRep.loopIndex} + ${dimRep.localOffset} - ${localOffset}@slurp
+  @elif $dimRep.reductionMethod == $ReductionMethod.fixedRange
+    @# We are using a fixed-range reduction method.
+    @#
+(${dimRep.loopIndex} + ${dimRep.localOffset}) * (${globalLattice}/${dimRep.globalLattice}) - ${localOffset}@slurp
+  @else
+    @assert False
+  @end if
+  @#
+ at end def
+
+ at def strictlyAscendingGlobalIndex
+  @#
+  @if not $hasLocalOffset
+    @return $loopIndex
+  @else
+lround((${name} - ${minimum})/${stepSize})@slurp
+  @end if
+  @#
+ at end def
+
+ at def indexForSinglePointSample
+  @#
+  @# Take the middle point, which is in the middle of the array
+${globalLattice}/2 at slurp
+  @#
+ at end def
+
+ at def createCoordinateVariableForSinglePointSample
+  @#
+${type} ${name} = ${arrayName}[${globalLattice}/2];
+#define d${name} (${stepSize} * (${volumePrefactor}))
+  @#
+ at end def
+
+ at def initialiseArray
+  @#
+for (long ${loopIndex} = 0; ${loopIndex} < ${globalLattice}; ${loopIndex}++)
+  ${arrayName}[${loopIndex}] = ${minimum} + ${loopIndex}*${stepSize};
+  @#
+ at end def
diff --git a/xpdeint/Geometry/_Dimension.py b/xpdeint/Geometry/_Dimension.py
new file mode 100755
index 0000000..c0e57f1
--- /dev/null
+++ b/xpdeint/Geometry/_Dimension.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_Dimension.py
+
+Created by Graham Dennis on 2008-02-02.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.ScriptElement import ScriptElement
+from xpdeint.Utilities import lazy_property
+
+class _Dimension(ScriptElement):
+  """
+  The idea here is that a dimension represents a given coordinate, 'x' say. And this
+  coordinate may have a number of numerical 'representations' in terms of a grid. For
+  example, the dimension 'x' may be represented by a uniformly spaced grid. The dimension
+  could also be represented in terms of a transformed (e.g. fourier-transformed) coordinate
+  'kx' that may also be uniformly spaced, but the in-memory layout of this grid will be
+  different. Alternatively, 'x' may be represented by a non-uniformly spaced grid. All of these
+  details are handled by the `DimensionRepresentation` classes of which a given dimension is
+  permitted to have at most two instances at present. One instance should be the 'untransformed'
+  dimension, while the other (if present) is the transformed representation of this dimension.
+  In this way, different transforms can create the appropriate representations for a given dimension
+  instead of hardcoding the assumption that the untransformed dimension is always uniformly spaced
+  and the transformed dimension is always uniformly spaced, but the memory layout is split.
+  
+  This kind of separation is particularly important for things like Hankel transforms which require
+  non-uniformly spaced grids, but will also be useful for discrete cosine/sine transforms which have
+  a transformed coordinate that is strictly positive.
+  """
+  
+  def __init__(self, *args, **KWs):
+    localKWs = self.extractLocalKWs(['name', 'transverse','transform', 'aliases', 'volumePrefactor'], KWs)
+    ScriptElement.__init__(self, *args, **KWs)
+    
+    self.name = localKWs['name']
+    self.transverse = localKWs.get('transverse', True)
+    self.transform = localKWs.get('transform')
+    self.aliases = localKWs.get('aliases', set())
+    self.aliases.add(self.name)
+    self.volumePrefactor = localKWs.get('volumePrefactor')
+    self.volumePrefactor = self.volumePrefactor if self.volumePrefactor else '1.0'
+    
+    self.representations = []
+  
+  def preflight(self):
+    # FIXME: DODGY. When we go to the 'basis' concept from the 'spaces' concept, this should go away
+    basisNameMap = dict([(rep.name, set()) for rep in self.representations if rep])
+    for rep in [rep for rep in self.representations if rep]:
+      basisNameMap[rep.name].add(rep)
+    for repName, repSet in basisNameMap.iteritems():
+      if len(repSet) > 1:
+        for rep in [rep for rep in repSet if not rep.hasLocalOffset]:
+          rep.silent = True
+  
+  @lazy_property
+  def prefix(self):
+    return self.parent.prefix
+  
+  @lazy_property
+  def isTransformable(self):
+    return len(self.representations) >= 2
+  
+  def inBasis(self, basis):
+    for rep in self.representations:
+      if rep and rep.canonicalName in basis: return rep
+    assert False
+  
+  def addRepresentation(self, rep):
+    self.representations.append(rep)
+    self._children.append(rep)
+  
+  def invalidateRepresentationsOtherThan(self, mainRep):
+    for idx, rep in enumerate(self.representations[:]):
+      if id(rep) != id(mainRep):
+        if rep: rep.remove()
+        self.representations[idx] = None
+  
+  def invalidateRepresentation(self, oldRep):
+    for idx, rep in enumerate(self.representations[:]):
+      if id(rep) == id(oldRep):
+        if rep: rep.remove()
+        self.representations[idx] = None
+  
+  def setReducedLatticeInBasis(self, newLattice, basis):
+    dimRep = self.inBasis(basis)
+    reductionMethod = dimRep.reductionMethod
+    assert dimRep.ReductionMethod.validate(reductionMethod)
+    if dimRep.runtimeLattice == newLattice: return
+    newDimRep = dimRep.copy(parent = self)
+    newDimRep.runtimeLattice = newLattice
+    self._children.append(newDimRep)
+    self.representations[self.representations.index(dimRep)] = newDimRep
+    self.invalidateRepresentationsOtherThan(newDimRep)
+  
+  def firstDimRepWithTagName(self, tagName):
+    repList = [rep for rep in self.representations if rep and issubclass(rep.tag, rep.tagForName(tagName))]
+    return repList[0] if repList else None
+  
+  @lazy_property
+  def isDistributed(self):
+    return any([rep.hasLocalOffset for rep in self.representations if rep])
+  
+  def copy(self, parent):
+    newInstanceKeys = ['name', 'transverse', 'transform', 'aliases']
+    newInstanceDict = dict([(key, getattr(self, key)) for key in newInstanceKeys])
+    newInstanceDict.update(self.argumentsToTemplateConstructors)
+    newDim = self.__class__(parent = parent, **newInstanceDict)
+    newDim.representations = self.representations[:]
+    return newDim
+  
+  def __eq__(self, other):
+    try:
+      return (self.name == other.name and
+              self.transverse == other.transverse and
+              self.representations == other.representations)
+    except AttributeError:
+      return NotImplemented
+  
+  def __ne__(self, other):
+    eq = self.__eq__(other)
+    if eq is NotImplemented:
+      return NotImplemented
+    else:
+      return not eq
+  
diff --git a/xpdeint/Geometry/_DimensionRepresentation.py b/xpdeint/Geometry/_DimensionRepresentation.py
new file mode 100755
index 0000000..5eaf7a0
--- /dev/null
+++ b/xpdeint/Geometry/_DimensionRepresentation.py
@@ -0,0 +1,206 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_DimensionRepresentation.py
+
+Created by Graham Dennis on 2008-07-30.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.ScriptElement import ScriptElement
+from xpdeint.Utilities import lazy_property
+
+class _DimensionRepresentation(ScriptElement):
+  """
+  See the documentation for the `_Dimension` class for more details, but the idea here is that
+  the details of the geometry of a dimension in a given space are controlled by a dimension
+  'representation'. This class controls the creation of loops over the dimension, the creation
+  of variables for the lattice, minimum and maximum of the representation. Further things like
+  how exactly to split the dimension are controlled by the transform that created the representation.
+  """
+  
+  class ReductionMethod(object):
+    fixedRange = 0
+    fixedStep = 1
+    
+    @staticmethod
+    def validate(method):
+      return method in range(2)
+  
+  tags = {}
+  
+  # We define two lattice attributes: latticeEstimate and runtimeLattice.
+  # If the size of the geometry lattice is a number specified in the XMDS script, 
+  # both "latticeEstimate" and "runtimeLattice" are set to this value. If the size is undefined
+  # at parse time and specified at run time, "runtimeLattice" holds a string which is
+  # the C-code global variable that will give the lattice size at run time, and
+  # "latticeEstimate" is set to a sane numeric placeholder (e.g. 128) for parsing purposes.
+  
+  instanceAttributes = ['name',  'type', 'runtimeLattice', '_localVariablePrefix', 'reductionMethod', 'tag']
+  
+  instanceDefaults = dict(
+    runtimeLattice = 0,
+    reductionMethod = ReductionMethod.fixedRange,
+    tag = -1
+  )
+  
+  @classmethod
+  def registerTag(cls, tagName, parent = None):
+    parent = cls.tagForName(parent) if parent else object
+    tag = type(tagName, (parent,), {'tagName': tagName})
+    return cls.tags.setdefault(tagName, tag)
+  
+  @classmethod
+  def tagForName(cls, tagName):
+    return cls.tags[tagName]
+  
+  def __init__(self, **KWs):
+    localKWs = self.extractLocalKWs(self.combinedClassInfo('instanceAttributes'), KWs)
+    ScriptElement.__init__(self, **KWs)
+    
+    instanceDefaults = self.combinedClassInfo('instanceDefaults')
+    [setattr(self, attrName, localKWs[attrName] if attrName in localKWs else instanceDefaults.get(attrName))
+      for attrName in self.combinedClassInfo('instanceAttributes')]
+    
+    self.silent = False
+  
+  def __eq__(self, other):
+    try:
+      return all([getattr(self, attrName) == getattr(other, attrName) for attrName in self.combinedClassInfo('instanceAttributes')])
+    except AttributeError:
+      return NotImplemented
+  
+  def __ne__(self, other):
+    eq = self.__eq__(other)
+    if eq is NotImplemented:
+      return NotImplemented
+    else:
+      return not eq
+  
+  def combinedClassInfo(self, attrName):
+    attributeType = type(getattr(self, attrName))
+    result = {list: set}.get(attributeType, attributeType)()
+    [result.update(getattr(cls, attrName)) for cls in reversed(type(self).mro()) if hasattr(cls, attrName)]
+    return result
+  
+  def copy(self, parent):
+    newInstanceDict = dict([(attrName, getattr(self, attrName)) for attrName in self.combinedClassInfo('instanceAttributes')])
+    newInstanceDict.update(self.argumentsToTemplateConstructors)
+    return type(self)(parent = parent, **newInstanceDict)
+  
+  @lazy_property
+  def prefix(self):
+    return self.parent.prefix
+  
+  @lazy_property
+  def canonicalName(self):
+    return self.name if not self.hasLocalOffset else 'distributed ' + self.name
+  
+  @lazy_property
+  def globalLattice(self):
+    return self.prefix + '_lattice_' + self.name
+  
+  def setHasLocalOffset(self, localVariablePrefix = ''):
+    if localVariablePrefix == None:
+      self._localVariablePrefix = None
+    else:
+      self._localVariablePrefix = '_local'
+      if localVariablePrefix:
+        self._localVariablePrefix += '_' + localVariablePrefix
+    if 'hasLocalOffset' in self.__dict__:
+      del self.hasLocalOffset
+  
+  @lazy_property
+  def hasLocalOffset(self):
+    return self._localVariablePrefix != None
+  
+  @lazy_property
+  def localLattice(self):
+    if not self.hasLocalOffset:
+      return self.globalLattice
+    else:
+      return self.prefix + self._localVariablePrefix + '_lattice_' + self.name
+  
+  @lazy_property
+  def localOffset(self):
+    if not self.hasLocalOffset:
+      return '0'
+    else:
+      return self.prefix + self._localVariablePrefix + '_offset_' + self.name
+  
+  @lazy_property
+  def minimum(self):
+    return self.prefix + '_min_' + self.name
+  
+  @lazy_property
+  def maximum(self):
+    return self.prefix + '_max_' + self.name
+  
+  @lazy_property
+  def arrayName(self):
+    return self.prefix + '_' + self.name
+  
+  @lazy_property
+  def stepSize(self):
+    return self.prefix + '_d' + self.name
+  
+  @lazy_property
+  def loopIndex(self):
+    return '_index_' + self.name
+  
+  @property
+  def volumePrefactor(self):
+      return self.parent.volumePrefactor
+  
+  @property
+  def latticeEstimate(self):
+    # Note this will always be a number, even if runtimeLattice is a string
+    if isinstance(self.runtimeLattice, basestring):
+      return 128
+    else:
+      return self.runtimeLattice
+
+
+  def aliasRepresentationsForFieldInBasis(self, field, basis):
+    return set([field.dimensionWithName(aliasName).inBasis(basis) \
+                for aliasName in self.parent.aliases if field.hasDimensionName(aliasName)])
+  
+  def nonlocalAccessIndexFromStringForFieldInBasis(self, accessString, field, basis):
+    """
+    Return the string representing the index to be used for this dimension representation
+    when accessing it nonlocally with the string `accessString` and when looping over
+    `field` in `basis`.
+    """
+    # If we don't have any dimension aliases, then our subclasses will have to handle
+    # any other cases for nonlocal dimension access
+    if not len(self.parent.aliases) > 1: return
+    
+    aliasRepresentations = self.aliasRepresentationsForFieldInBasis(field, basis)
+    matchingAliasReps = [rep for rep in aliasRepresentations if rep.name == accessString]
+    if not matchingAliasReps: return
+    matchingAliasRep = matchingAliasReps[0]
+    # We are the dimRep for the vector being accessed nonlocally.  
+    # We need to return the index not in us, but in the corresponding dimRep in field (which is the looping field)
+    fieldDimRep = field.dimensionWithName(self.parent.name).inBasis(basis)
+    return fieldDimRep.localIndexFromIndexForDimensionRep(matchingAliasRep)
+    
+  
+
+_DimensionRepresentation.registerTag('coordinate')
+_DimensionRepresentation.registerTag('spectral')
+_DimensionRepresentation.registerTag('auxiliary')
diff --git a/xpdeint/Geometry/_FieldElement.py b/xpdeint/Geometry/_FieldElement.py
new file mode 100644
index 0000000..3a741cd
--- /dev/null
+++ b/xpdeint/Geometry/_FieldElement.py
@@ -0,0 +1,318 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_FieldElement.py
+
+This contains all the pure-python code for FieldElement.tmpl
+
+Created by Graham Dennis on 2007-10-17.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.ScriptElement import ScriptElement
+
+from xpdeint.ParserException import ParserException, parserWarning
+
+from xpdeint.Utilities import lazy_property, symbolsInString
+
+class _FieldElement (ScriptElement):
+  def __init__(self, *args, **KWs):
+    # The MomentGroup and GeometryElement subclasses define name properties
+    if not self.hasattr('name'):
+      self.name = KWs['name']
+      del KWs['name']
+    if not 'parent' in KWs: KWs['parent'] = self.simulation
+    ScriptElement.__init__(self, *args, **KWs)
+    
+    # Set default variables
+    self.managedVectors = set()
+    self.temporaryVectors = set()
+    self.dimensions = []
+    self._basisForBasisCache = {}
+    
+    self.getVar('fields').append(self)
+  
+  @property
+  def vectors(self):
+    returnValue = self.managedVectors.copy()
+    returnValue.update(self.temporaryVectors)
+    return returnValue
+  
+  @property
+  def children(self):
+    children = super(_FieldElement, self).children
+    children.extend(self.dimensions)
+    # Sort managed vectors by name
+    children.extend(self.managedVectors)
+    return children
+  
+  @lazy_property
+  def prefix(self):
+    return '_' + self.name if not self.name is 'geometry' else ''
+  
+  # Do we have the dimension?
+  def hasDimension(self, dimension):
+    return self.hasDimensionName(dimension.name)
+  
+  # Do we have a dimension matching dimensionName?
+  def hasDimensionName(self, dimensionName):
+    dimensionList = filter(lambda x: x.name == dimensionName, self.dimensions)
+    assert len(dimensionList) <= 1
+    
+    return len(dimensionList) == 1
+  
+  # Is the field a subset of another field (in terms of dimensions)
+  def isSubsetOfField(self, field):
+    """Return whether this field's dimensions are a subset of the dimensions of field `field`."""
+    for dimension in self.dimensions:
+      if not field.hasDimension(dimension):
+        return False
+    return True
+  
+  def isEquivalentToField(self, field):
+    """Return whether this field and field `field` have the same dimensions."""
+    return self.isSubsetOfField(field) and field.isSubsetOfField(self)
+  
+  # The index of the provided dimension
+  def indexOfDimension(self, dimension):
+    """Return the index (in the `dimensions` list) of the dimension corresponding to `dimension`."""
+    return self.indexOfDimensionName(dimension.name)
+  
+  # The index of the dimension with the name dimensionName
+  def indexOfDimensionName(self, dimensionName):
+    """Return the index (in the `dimensions` list) of the dimension that has the name `dimensionName`."""
+    dimensionList = filter(lambda x: x.name == dimensionName, self.dimensions)
+    assert len(dimensionList) == 1
+    return self.dimensions.index(dimensionList[0])
+  
+  def dimensionWithName(self, dimensionName):
+    """Return the dimension that has the name `dimensionName`."""
+    return self.dimensions[self.indexOfDimensionName(dimensionName)]
+  
+  def localPointsInDimensionsAfterDimRepInBasis(self, dimRep, basis):
+    dimReps = self.inBasis(basis)
+    # Grab everything after dimension
+    dimReps = dimReps[(dimReps.index(dimRep)+1):]
+    if not len(dimReps):
+      return '1'
+    return ' * '.join([dimRep.localLattice for dimRep in dimReps])
+  
+  @property
+  def transverseDimensions(self):
+    return filter(lambda x: x.transverse, self.dimensions)
+  
+  # Initialise field
+  def initialise(self):
+    return self.implementationsForChildren('initialise')
+  
+  # Allocate (and initialise active pointers)
+  def allocate(self):
+    return self.implementationsForChildren('allocate')
+  
+  # Free vectors
+  def free(self):
+    return self.implementationsForChildren('free')
+  
+  @lazy_property
+  def isDistributed(self):
+    return self._driver.isFieldDistributed(self)
+  
+  def sizeInBasis(self, basis):
+    return '(' + (' * '.join([dimRep.localLattice for dimRep in self.inBasis(basis)]) or '1') + ')'
+  
+  def sortDimensions(self):
+    """Sort the dimensions of the field into canonical (geometry element) order."""
+    geometryTemplate = self.getVar('geometry')
+    sortFunction = lambda x, y: cmp(geometryTemplate.indexOfDimension(x), geometryTemplate.indexOfDimension(y))
+    self.dimensions.sort(sortFunction)
+  
+  def basisForBasis(self, basis):
+    """
+    Return a basis that only contains the dimensions in this field.
+    It also handles the case in which a distributed basis becomes a non-distributed basis
+    after a dimension has been omitted.
+    We do not validate that such a transformation is possible.
+    
+    The results of this method are cached on a per-instance basis for speed.
+    """
+    if not basis in self._basisForBasisCache:
+      geometry = self.getVar('geometry')
+      dimRepNames = set([dr.canonicalName for dim in self.dimensions for dr in geometry.dimensionWithName(dim.name).representations])
+      if not len(dimRepNames.intersection(basis)) == len(self.dimensions):
+        raise ParserException(
+          None,
+          "Internal error: The basis provided (%s) contained insufficient information to generate the appropriate basis for a vector in this field (%s). A specification is required for all dimensions (%s). \n\nPlease report this error to %s." %
+          (', '.join(basis), self.name, ', '.join(dim.name for dim in self.dimensions), self.getVar('bugReportAddress'))
+        )
+      newBasis = tuple(b for b in basis if b in dimRepNames)
+      maxDistributedIdx = max([idx for idx, dimRepName in enumerate(newBasis) if dimRepName.startswith('distributed ')] + [-1])
+      orderedDimRepNames = [(idx, dimRep.canonicalName) 
+                                for idx, dim in enumerate(self.dimensions) 
+                                  for dimRep in geometry.dimensionWithName(dim.name).representations
+                                    if dimRep.canonicalName in newBasis[maxDistributedIdx+1:]]
+      orderedDimRepNames.sort()
+      newBasis = self._driver.canonicalBasisForBasis(newBasis[:maxDistributedIdx+1] + tuple([x[1] for x in orderedDimRepNames]))
+      self._basisForBasisCache[basis] = newBasis
+    return self._basisForBasisCache[basis]
+  
+  def completedBasisForBasis(self, basis, defaultBasis):
+    # If an incomplete basis is known for this field, it may be desirable to complete the basis using information from a default.
+    basis = basis or ()
+    geometry = self.getVar('geometry')
+    dimRepNameToDimMap = dict((dr.canonicalName, dim) for dim in self.dimensions for dr in geometry.dimensionWithName(dim.name).representations)
+    missingDimensions = set(self.dimensions)
+    for dimRepName in basis:
+      missingDimensions.discard(dimRepNameToDimMap[dimRepName])
+    # We now have the missing dimensions, now to find the corresponding dimRepName from the field's defaultCoordinateBasis
+    for dimRepName in defaultBasis:
+      dimension = dimRepNameToDimMap[dimRepName]
+      if dimension in missingDimensions:
+        missingDimensions.discard(dimension)
+        basis += (dimRepName,)
+    return basis
+  
+  def inBasis(self, basis):
+    """
+    Return a list of dimReps corresponding to the supplied basis. We cannot guarantee that the basis we are passed is directly appropriate
+    for this field. So we must pass it through basisForBasis.
+    """
+    basis = self.basisForBasis(basis)
+    dimRepNameMap = dict([(dimRep.canonicalName, dimRep) for dim in self.dimensions for dimRep in dim.representations if dimRep])
+    return [dimRepNameMap[b] for b in basis]
+  
+  def basisFromString(self, basisString, xmlElement = None):
+    """
+    Return the basis given `basisString`.
+    """
+    xmlElement = xmlElement or self.xmlElement
+    
+    basis = set(symbolsInString(basisString, xmlElement = xmlElement))
+    
+    geometry = self.getVar('geometry')
+    validNames = set([dimRep.name for dim in self.dimensions for dimRep in geometry.dimensionWithName(dim.name).representations])
+    if basis.difference(validNames):
+      raise ParserException(
+        xmlElement,
+        "The following names are not valid basis specifiers: %s." % ', '.join(basis.difference(validNames))
+      )
+    # Now we know we don't have any specifiers that we can't identify, 
+    # so we just need to check that we don't have two specifiers for the same dimension.
+    dimToDimRepMap = dict([(dim.name, [dimRep.name for dimRep in geometry.dimensionWithName(dim.name).representations]) for dim in self.dimensions])
+    
+    for dimName, dimRepNames in dimToDimRepMap.items():
+      basisNamesInDimRepNames = basis.intersection(dimRepNames)
+      if len(basisNamesInDimRepNames) > 1:
+        raise ParserException(
+          xmlElement,
+          "There is more than one basis specifier for dimension '%s'. The conflict is between %s." \
+            % (dimName, ' and '.join(basis.intersection(dimRepNames)))
+        )
+      elif len(basisNamesInDimRepNames) == 1:
+        # Use the map to now list the actual chosen dimRep name
+        dimToDimRepMap[dimName] = list(basisNamesInDimRepNames)[0]
+      else:
+        # This dimension doesn't have a rep specified. Default to the first rep.
+        dimToDimRepMap[dimName] = dimRepNames[0]
+      if dimToDimRepMap[dimName] is None:
+        raise ParserException(
+          xmlElement,
+          "Internal Error: When turning string '%s' into a basis, we were unable to determine the correct dimension representation for the %s dimension. "
+          "Please report this error to %s" \
+            % (basisString, dimName, self.getVar('bugReportAddress'))
+        )
+    
+    # Now we just need to construct the basis
+    
+    basis = self._driver.canonicalBasisForBasis(tuple(dimToDimRepMap[dim.name] for dim in self.dimensions))
+    
+    return basis
+  
+  @lazy_property
+  def defaultCoordinateBasis(self):
+    # Grab the first rep for each dim whose tag is a 'coordinate' tag
+    # i.e. the tag is a subclass of the 'coordinate' tag.
+    return self._driver.canonicalBasisForBasis(
+      tuple([dim.firstDimRepWithTagName('coordinate').canonicalName for dim in self.dimensions])
+    )
+  
+  @lazy_property
+  def defaultSpectralBasis(self):
+    # Grab the first dim rep for each dim whose tag is 'spectral' if one exists
+    # Failing that, take the first one with a 'coordinate' tag.
+    reps = []
+    for dim in self.dimensions:
+      for tagName in ['spectral', 'coordinate']:
+        rep = dim.firstDimRepWithTagName(tagName)
+        if rep: break
+      assert rep, "We should have found a representation that was either spectral or coordinate but somehow failed"
+      reps.append(rep.canonicalName)
+    return self._driver.canonicalBasisForBasis(tuple(reps))
+  
+  @classmethod
+  def sortedFieldWithDimensionNames(cls, dimensionNames, xmlElement = None, createIfNeeded = True):
+    """
+    Return a field containing `dimensionNames` as the dimensions in canonical order.
+    This function will either return an existing field, or create one if necessary.
+    
+    Although this class method is defined on `_FieldElement`, it must be called as
+    ``FieldElement.sortedFieldWithDimensionNames`` in order to get a FieldElement
+    instance out.
+    """
+    globalNameSpace = cls.argumentsToTemplateConstructors['searchList'][0]
+    geometry = globalNameSpace['geometry']
+    fields = globalNameSpace['fields']
+    
+    dimensionNames = list(dimensionNames)
+    
+    # If we have an xmlElement, first check that all of the dimension names provided
+    # are valid dimension names
+    if xmlElement:
+      for dimensionName in dimensionNames:
+        if not geometry.hasDimensionName(dimensionName):
+          raise ParserException(xmlElement, "Don't recognise '%(dimensionName)s' as one of "
+                                            "the dimensions defined in the geometry element." % locals())
+    
+    dimensionNames.sort(lambda x, y: cmp(geometry.indexOfDimensionName(x), geometry.indexOfDimensionName(y)))
+    
+    fieldDimensions = [geometry.dimensionWithName(dimName) for dimName in dimensionNames]
+    
+    if len(dimensionNames):
+      fieldName = ''.join(dimensionNames)
+    else:
+      fieldName = 'dimensionless'
+    
+    potentialFields = filter(lambda x: x.dimensions == fieldDimensions and x.name == fieldName, fields)
+    
+    field = None
+    
+    if potentialFields:
+      # If there is a field already in existence that matches our requirements, use it
+      field = potentialFields[0]
+    elif createIfNeeded:
+      # Otherwise we need to construct our own
+      field = cls(name = fieldName, **cls.argumentsToTemplateConstructors)
+      # Copy in our dimensions
+      field.dimensions[:] = [dim.copy(parent = field) for dim in fieldDimensions]
+      
+      if xmlElement:
+        field.xmlElement = xmlElement
+    
+    return field
+  
+
+
diff --git a/xpdeint/Geometry/_NonUniformDimensionRepresentation.py b/xpdeint/Geometry/_NonUniformDimensionRepresentation.py
new file mode 100644
index 0000000..9e710f1
--- /dev/null
+++ b/xpdeint/Geometry/_NonUniformDimensionRepresentation.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_NonUniformDimensionRepresentation.py
+
+Created by Graham Dennis on 2008-07-30.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Geometry.DimensionRepresentation import DimensionRepresentation
+from xpdeint.Utilities import lazy_property
+
+class _NonUniformDimensionRepresentation(DimensionRepresentation):
+  """
+  This class represents a dimension with non-uniform spacing. This corresponds
+  to two main possibilities.
+  
+  The first is the propagation dimension where each point in this dimension
+  corresponds to a time at which sampling occurred. This isn't necessarily
+  uniform.
+  
+  The second is a Gauss-Lobotto grid for a transverse dimension in the problem.
+  In this case, the points will not be equally spaced in order to optimise
+  integration across the dimension. Also, the 'step size' variable in this case
+  corresponds to the Gauss-Lobotto weight for each grid point and is not directly
+  related to the separation of two neighbouring grid points. This is perfectly
+  sensible as the step size is only used as a weight when integrating across
+  dimensions, which is exactly where the weight should be used.
+  """
+  
+  instanceAttributes = ['stepSizeArray']
+  instanceDefaults = dict(
+    stepSizeArray = False
+  )
+  
+  @lazy_property
+  def index(self):
+    return self.prefix + '_index_' + self.name
+  
+  @lazy_property
+  def arrayName(self):
+    return self.prefix + '_' + self.name
+  
+  @lazy_property
+  def stepSizeArrayName(self):
+    return self.prefix + '_d' + self.name + '_array'
+  
+  @lazy_property
+  def stepSize(self):
+    if self.stepSizeArray:
+      # We can do this because the step size is only defined inside a loop as the 
+      # step size depends on position.
+      return 'd' + self.name
+    else:
+      return super(_NonUniformDimensionRepresentation, self).stepSize
+  
+  def openLoop(self, loopingOrder):
+    if loopingOrder in [self.LoopingOrder.MemoryOrder, self.LoopingOrder.StrictlyAscendingOrder]:
+      return self.openLoopAscending()
+    else:
+      raise NotImplemented
+  
+  def closeLoop(self, loopingOrder):
+    if loopingOrder in [self.LoopingOrder.MemoryOrder, self.LoopingOrder.StrictlyAscendingOrder]:
+      return self.closeLoopAscending()
+    else:
+      raise NotImplemented
+  
+
diff --git a/xpdeint/Geometry/_SplitUniformDimensionRepresentation.py b/xpdeint/Geometry/_SplitUniformDimensionRepresentation.py
new file mode 100644
index 0000000..5eea790
--- /dev/null
+++ b/xpdeint/Geometry/_SplitUniformDimensionRepresentation.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_SplitUniformDimensionRepresentation.py
+
+Created by Graham Dennis on 2008-07-30.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Geometry.DimensionRepresentation import DimensionRepresentation
+from xpdeint.Utilities import lazy_property
+
+class _SplitUniformDimensionRepresentation(DimensionRepresentation):
+  instanceAttributes = ['_range']
+  
+  @lazy_property
+  def alternateLoopIndex(self):
+    return '_j_' + self.name
+  
+  def openLoop(self, loopingOrder):
+    if loopingOrder == self.LoopingOrder.MemoryOrder:
+      return self.openLoopMemoryOrder()
+    elif loopingOrder == self.LoopingOrder.StrictlyAscendingOrder:
+      assert not self.hasLocalOffset
+      return self.openLoopAscending()
+    else:
+      raise NotImplemented
+  
+  def closeLoop(self, loopingOrder):
+    if loopingOrder == self.LoopingOrder.MemoryOrder:
+      return self.closeLoopMemoryOrder()
+    elif loopingOrder == self.LoopingOrder.StrictlyAscendingOrder:
+      return self.closeLoopAscending()
+    else:
+      raise NotImplemented
+  
+  def nonlocalAccessIndexFromStringForFieldInBasis(self, accessString, field, basis):
+    result = super(_SplitUniformDimensionRepresentation, self).nonlocalAccessIndexFromStringForFieldInBasis(accessString, field, basis)
+    if result: return result
+    # We only support access with the negative of the dimension variable. e.g. -kx
+    name = self.name
+    aliasRepresentations = self.aliasRepresentationsForFieldInBasis(field, basis)
+    matchingAliasReps = [dimRep for dimRep in aliasRepresentations if accessString == ('-' + dimRep.name)]
+    assert len(matchingAliasReps) <= 1
+    if not matchingAliasReps: return
+    matchingAliasRep = matchingAliasReps[0]
+    
+    # We only support the case where the global number of points in the looping dimension and the
+    # accessing dimension are the same. i.e. no sub-sampling and non-local access at the same time.
+    if not field.hasDimensionName(matchingAliasRep.parent.name): return
+    loopDimRep = field.dimensionWithName(matchingAliasRep.parent.name).inBasis(basis)
+    if not matchingAliasRep.runtimeLattice == loopDimRep.runtimeLattice: return
+    loopingIndex = loopDimRep.loopIndex
+    globalLattice = matchingAliasRep.globalLattice
+    return '(%(globalLattice)s - %(loopingIndex)s) %% %(globalLattice)s' % locals()
+  
+
+
+
+
diff --git a/xpdeint/Geometry/_UniformDimensionRepresentation.py b/xpdeint/Geometry/_UniformDimensionRepresentation.py
new file mode 100644
index 0000000..b96b6ba
--- /dev/null
+++ b/xpdeint/Geometry/_UniformDimensionRepresentation.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_UniformDimensionRepresentation.py
+
+Created by Graham Dennis on 2008-07-30.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Geometry.DimensionRepresentation import DimensionRepresentation
+
+class _UniformDimensionRepresentation(DimensionRepresentation):
+  instanceAttributes = ['_minimum',  '_maximum', '_stepSize']
+  
+  @property
+  def stepSizeString(self):
+    if self._stepSize:
+      return self._stepSize
+    else:
+      return '((%(maximum)s - %(minimum)s)/%(globalLattice)s)' % dict(
+        minimum = self.minimum,
+        maximum = self.maximum,
+        globalLattice = self.globalLattice
+      )
+  
+  def openLoop(self, loopingOrder):
+    if loopingOrder in [self.LoopingOrder.MemoryOrder, self.LoopingOrder.StrictlyAscendingOrder]:
+      return self.openLoopAscending()
+    elif loopingOrder == self.LoopingOrder.StrictlyDescendingOrder:
+      return self.openLoopDescending()
+    else:
+      raise NotImplemented
+  
+  def closeLoop(self, loopingOrder):
+    if loopingOrder in [self.LoopingOrder.MemoryOrder, self.LoopingOrder.StrictlyAscendingOrder]:
+      return self.closeLoopAscending()
+    elif loopingOrder == self.LoopingOrder.StrictlyDescendingOrder:
+      return self.closeLoopDescending()
+    else:
+      raise NotImplemented
+  
+  def nonlocalAccessIndexFromStringForFieldInBasis(self, accessString, field, basis):
+    result = super(_UniformDimensionRepresentation, self).nonlocalAccessIndexFromStringForFieldInBasis(accessString, field, basis)
+    if result: return result
+    # We only support non-local access for integer-valued dimensions, or access to the minimum value
+    minimum = self.minimum
+    # We shouldn't be called if we are distributed, but let's check just to be safe.
+    if self.hasLocalOffset: return
+    
+    if not self.type == 'long':
+      if not self._stepSize and accessString == self._minimum:
+        return '0'
+      elif accessString == ('-' + self.name):
+        canAccessNegativeVariable = False
+        if self._minimum == ('-' + self._maximum):
+          canAccessNegativeVariable = True
+        elif 'Validation' in self.getVar('features'):
+          canAccessNegativeVariable = True
+          validationFeature = self.getVar('features')['Validation']
+          validationFeature.validationChecks.append("""
+          if (fabs(%(maximum)s + %(minimum)s) > 0.1 * %(stepSize)s)
+            _LOG(_ERROR_LOG_LEVEL, "ERROR: Nonlocal access of dimension '%(dimRepName)s' using '-%(dimRepName)s' is only valid for dimensions symmetric about zero.\\n");\n""" % {'maximum': self.maximum, 'minimum': self.minimum, 'dimRepName': self.name, 'stepSize': self.stepSize})
+        
+        if canAccessNegativeVariable:
+          lattice = self.globalLattice
+          loopIndex = self.loopIndex
+          return '(%(lattice)s - %(loopIndex)s) %% %(lattice)s' % locals()
+      return
+    return '(%(accessString)s) - %(minimum)s' % locals()
+  
+
diff --git a/xpdeint/Geometry/__init__.py b/xpdeint/Geometry/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/xpdeint/HDF5.py b/xpdeint/HDF5.py
new file mode 100644
index 0000000..b5e3808
--- /dev/null
+++ b/xpdeint/HDF5.py
@@ -0,0 +1,699 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.ScriptElement import ScriptElement
+from xpdeint.Geometry.SplitUniformDimensionRepresentation import SplitUniformDimensionRepresentation
+from xpdeint.CallOnceGuards import callOnceGuard
+from itertools import chain
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.949527
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/HDF5.tmpl'
+__CHEETAH_srcLastModified__ = 'Mon Apr 23 13:26:13 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class HDF5(ScriptElement):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(HDF5, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    @callOnceGuard
+    def includes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def includes at line 31, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(HDF5, self).includes()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u"""#define H5_USE_16_API
+#include <hdf5.h>
+
+#if !defined(HAVE_H5LEXISTS)
+htri_t H5Lexists(hid_t loc_id, const char *name, hid_t lapl_id)
+{
+  H5E_auto_t error_func;
+  void* error_client_data;
+  // Squelch errors generated by H5Gget_objinfo. It will report errors when it can't find an object
+  // but that's the purpose of calling it.
+  H5Eget_auto(&error_func, &error_client_data);
+  H5Eset_auto(NULL, NULL);
+  herr_t err = H5Gget_objinfo(loc_id, name, false, NULL);
+  H5Eset_auto(error_func, error_client_data);
+  if (err >= 0)
+    return true;
+  else
+    return false;
+}
+#endif
+
+#define H5T_NATIVE_REAL H5T_NATIVE_""")
+        _v = {'double': 'DOUBLE', 'single': 'FLOAT'}[VFFSL(SL,"precision",True)] # u"${{'double': 'DOUBLE', 'single': 'FLOAT'}[$precision]}" on line 56, col 36
+        if _v is not None: write(_filter(_v, rawExpr=u"${{'double': 'DOUBLE', 'single': 'FLOAT'}[$precision]}")) # from line 56, col 36.
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def processData(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def processData(dict) at line 60, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        field = dict['field']
+        basis = dict['basis']
+        operation = dict['operation']
+        assert operation in ['read', 'write']
+        variables = dict['variables']
+        dimensionOffsets = dict.get('dimensionOffsets', {})
+        componentCount = 0
+        for variable in VFFSL(SL,"variables",True): # generated from line 68, col 3
+            componentCount += len(VFFSL(SL,"variable.vector.components",True))
+            if VFFSL(SL,"variable.vector.type",True) == 'complex': # generated from line 70, col 5
+                componentCount += len(VFFSL(SL,"variable.vector.components",True))
+        dict['componentCount'] = componentCount
+        write(u'''/* Create the data space */
+''')
+        dimensionCount = len(field.dimensions)
+        #  File dim reps must be in dimension order as that is the order we desire for write-out
+        fileDimReps = [dim.inBasis(basis) for dim in field.dimensions]
+        memDimReps = field.inBasis(basis)
+        #  Construct a list of (fileDimNum, memDimNum, dimRep) tuples. This is necessary
+        #  for the case where we are using a distributed MPI driver with FFT's
+        #  and the first two dimensions are transformed. In this situation, the
+        #  first and second dimensions are transposed.
+        # 
+        dimRepOrdering = [(fileDimNum, memDimReps.index(dimRep), dimRep)                          for fileDimNum, dimRep in enumerate(fileDimReps)]
+        # 
+        write(u'''hsize_t file_start[''')
+        _v = VFFSL(SL,"dimensionCount",True) # u'${dimensionCount}' on line 88, col 20
+        if _v is not None: write(_filter(_v, rawExpr=u'${dimensionCount}')) # from line 88, col 20.
+        write(u'''] = {''')
+        _v = ', '.join(dimRep.localOffset for dimRep in fileDimReps) # u"${', '.join(dimRep.localOffset for dimRep in fileDimReps)}" on line 88, col 42
+        if _v is not None: write(_filter(_v, rawExpr=u"${', '.join(dimRep.localOffset for dimRep in fileDimReps)}")) # from line 88, col 42.
+        write(u'''};
+hsize_t mem_dims[''')
+        _v = VFFSL(SL,"dimensionCount",True)+1 # u'${dimensionCount+1}' on line 89, col 18
+        if _v is not None: write(_filter(_v, rawExpr=u'${dimensionCount+1}')) # from line 89, col 18.
+        write(u'''] = {''')
+        _v = ', '.join(chain((dimRep.localLattice for dimRep in memDimReps), ['1'])) # u"${', '.join(chain((dimRep.localLattice for dimRep in memDimReps), ['1']))}" on line 89, col 42
+        if _v is not None: write(_filter(_v, rawExpr=u"${', '.join(chain((dimRep.localLattice for dimRep in memDimReps), ['1']))}")) # from line 89, col 42.
+        write(u'''};
+hsize_t mem_start[''')
+        _v = VFFSL(SL,"dimensionCount",True)+1 # u'${dimensionCount+1}' on line 90, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${dimensionCount+1}')) # from line 90, col 19.
+        write(u'''] = {''')
+        _v = ', '.join(['0']*(dimensionCount+1)) # u"${', '.join(['0']*(dimensionCount+1))}" on line 90, col 43
+        if _v is not None: write(_filter(_v, rawExpr=u"${', '.join(['0']*(dimensionCount+1))}")) # from line 90, col 43.
+        write(u'''};
+hsize_t mem_stride[''')
+        _v = VFFSL(SL,"dimensionCount",True)+1 # u'${dimensionCount+1}' on line 91, col 20
+        if _v is not None: write(_filter(_v, rawExpr=u'${dimensionCount+1}')) # from line 91, col 20.
+        write(u'''] = {''')
+        _v = ', '.join(['1']*(dimensionCount+1)) # u"${', '.join(['1']*(dimensionCount+1))}" on line 91, col 44
+        if _v is not None: write(_filter(_v, rawExpr=u"${', '.join(['1']*(dimensionCount+1))}")) # from line 91, col 44.
+        write(u'''};
+hsize_t mem_count[''')
+        _v = VFFSL(SL,"dimensionCount",True)+1 # u'${dimensionCount+1}' on line 92, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${dimensionCount+1}')) # from line 92, col 19.
+        write(u'''] = {''')
+        _v = ', '.join(chain((dimRep.localLattice for dimRep in memDimReps), ['1'])) # u"${', '.join(chain((dimRep.localLattice for dimRep in memDimReps), ['1']))}" on line 92, col 43
+        if _v is not None: write(_filter(_v, rawExpr=u"${', '.join(chain((dimRep.localLattice for dimRep in memDimReps), ['1']))}")) # from line 92, col 43.
+        write(u'''};
+
+''')
+        for fileDimNum, memDimNum, dimRep in dimRepOrdering: # generated from line 94, col 3
+            if dimRep.name in dimensionOffsets and not isinstance(dimRep, SplitUniformDimensionRepresentation): # generated from line 95, col 5
+                offset = dimensionOffsets[dimRep.name]
+                write(u'''if (file_start[''')
+                _v = VFFSL(SL,"fileDimNum",True) # u'${fileDimNum}' on line 97, col 16
+                if _v is not None: write(_filter(_v, rawExpr=u'${fileDimNum}')) # from line 97, col 16.
+                write(u'''] < ''')
+                _v = VFFSL(SL,"offset",True) # u'${offset}' on line 97, col 33
+                if _v is not None: write(_filter(_v, rawExpr=u'${offset}')) # from line 97, col 33.
+                write(u''') {
+  if (mem_count[''')
+                _v = VFFSL(SL,"memDimNum",True) # u'${memDimNum}' on line 98, col 17
+                if _v is not None: write(_filter(_v, rawExpr=u'${memDimNum}')) # from line 98, col 17.
+                write(u'''] < ''')
+                _v = VFFSL(SL,"offset",True) # u'${offset}' on line 98, col 33
+                if _v is not None: write(_filter(_v, rawExpr=u'${offset}')) # from line 98, col 33.
+                write(u''' - file_start[''')
+                _v = VFFSL(SL,"fileDimNum",True) # u'${fileDimNum}' on line 98, col 56
+                if _v is not None: write(_filter(_v, rawExpr=u'${fileDimNum}')) # from line 98, col 56.
+                write(u'''])
+    mem_count[''')
+                _v = VFFSL(SL,"memDimNum",True) # u'${memDimNum}' on line 99, col 15
+                if _v is not None: write(_filter(_v, rawExpr=u'${memDimNum}')) # from line 99, col 15.
+                write(u'''] = 0;
+  else {
+    mem_count[''')
+                _v = VFFSL(SL,"memDimNum",True) # u'${memDimNum}' on line 101, col 15
+                if _v is not None: write(_filter(_v, rawExpr=u'${memDimNum}')) # from line 101, col 15.
+                write(u'''] -= ''')
+                _v = VFFSL(SL,"offset",True) # u'${offset}' on line 101, col 32
+                if _v is not None: write(_filter(_v, rawExpr=u'${offset}')) # from line 101, col 32.
+                write(u''' - file_start[''')
+                _v = VFFSL(SL,"fileDimNum",True) # u'${fileDimNum}' on line 101, col 55
+                if _v is not None: write(_filter(_v, rawExpr=u'${fileDimNum}')) # from line 101, col 55.
+                write(u'''];
+    mem_start[''')
+                _v = VFFSL(SL,"memDimNum",True) # u'${memDimNum}' on line 102, col 15
+                if _v is not None: write(_filter(_v, rawExpr=u'${memDimNum}')) # from line 102, col 15.
+                write(u'''] += ''')
+                _v = VFFSL(SL,"offset",True) # u'${offset}' on line 102, col 32
+                if _v is not None: write(_filter(_v, rawExpr=u'${offset}')) # from line 102, col 32.
+                write(u''' - file_start[''')
+                _v = VFFSL(SL,"fileDimNum",True) # u'${fileDimNum}' on line 102, col 55
+                if _v is not None: write(_filter(_v, rawExpr=u'${fileDimNum}')) # from line 102, col 55.
+                write(u'''];
+  }
+  file_start[''')
+                _v = VFFSL(SL,"fileDimNum",True) # u'${fileDimNum}' on line 104, col 14
+                if _v is not None: write(_filter(_v, rawExpr=u'${fileDimNum}')) # from line 104, col 14.
+                write(u'''] = 0;
+} else {
+  file_start[''')
+                _v = VFFSL(SL,"fileDimNum",True) # u'${fileDimNum}' on line 106, col 14
+                if _v is not None: write(_filter(_v, rawExpr=u'${fileDimNum}')) # from line 106, col 14.
+                write(u'''] -= ''')
+                _v = VFFSL(SL,"offset",True) # u'${offset}' on line 106, col 32
+                if _v is not None: write(_filter(_v, rawExpr=u'${offset}')) # from line 106, col 32.
+                write(u''';
+}
+
+if (mem_count[''')
+                _v = VFFSL(SL,"memDimNum",True) # u'$memDimNum' on line 109, col 15
+                if _v is not None: write(_filter(_v, rawExpr=u'$memDimNum')) # from line 109, col 15.
+                write(u'''] > file_dims[''')
+                _v = VFFSL(SL,"fileDimNum",True) # u'$fileDimNum' on line 109, col 39
+                if _v is not None: write(_filter(_v, rawExpr=u'$fileDimNum')) # from line 109, col 39.
+                write(u''']) {
+  mem_count[''')
+                _v = VFFSL(SL,"memDimNum",True) # u'$memDimNum' on line 110, col 13
+                if _v is not None: write(_filter(_v, rawExpr=u'$memDimNum')) # from line 110, col 13.
+                write(u'''] = file_dims[''')
+                _v = VFFSL(SL,"fileDimNum",True) # u'$fileDimNum' on line 110, col 37
+                if _v is not None: write(_filter(_v, rawExpr=u'$fileDimNum')) # from line 110, col 37.
+                write(u'''];
+}
+''')
+        write(u'''
+hid_t mem_dataspace;
+''')
+        for variable in variables: # generated from line 116, col 3
+            components = VFFSL(SL,"variable.separatedComponents",True)
+            write(u'''mem_dims[''')
+            _v = VFFSL(SL,"dimensionCount",True) # u'${dimensionCount}' on line 118, col 10
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimensionCount}')) # from line 118, col 10.
+            write(u'''] = ''')
+            _v = VFFSL(SL,"len",False)(components) # u'${len(components)}' on line 118, col 31
+            if _v is not None: write(_filter(_v, rawExpr=u'${len(components)}')) # from line 118, col 31.
+            write(u''';
+mem_dataspace = H5Screate_simple(''')
+            _v = VFFSL(SL,"dimensionCount",True)+1 # u'${dimensionCount+1}' on line 119, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimensionCount+1}')) # from line 119, col 34.
+            write(u''', mem_dims, NULL);
+mem_stride[''')
+            _v = VFFSL(SL,"dimensionCount",True) # u'${dimensionCount}' on line 120, col 12
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimensionCount}')) # from line 120, col 12.
+            write(u'''] = ''')
+            _v = VFFSL(SL,"len",False)(components) # u'${len(components)}' on line 120, col 33
+            if _v is not None: write(_filter(_v, rawExpr=u'${len(components)}')) # from line 120, col 33.
+            write(u''';
+
+''')
+            ## START CAPTURE REGION: _30798580 writeLoopContents at line 122, col 5 in the source.
+            _orig_trans_30798580 = trans
+            _wasBuffering_30798580 = self._CHEETAH__isBuffering
+            self._CHEETAH__isBuffering = True
+            trans = _captureCollector_30798580 = DummyTransaction()
+            write = _captureCollector_30798580.response().write
+            for offset, componentName in components: # generated from line 123, col 7
+                write(u'''mem_start[''')
+                _v = VFFSL(SL,"dimensionCount",True) # u'${dimensionCount}' on line 124, col 11
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimensionCount}')) # from line 124, col 11.
+                write(u'''] = ''')
+                _v = VFFSL(SL,"offset",True) # u'$offset' on line 124, col 32
+                if _v is not None: write(_filter(_v, rawExpr=u'$offset')) # from line 124, col 32.
+                write(u''';
+H5Sselect_hyperslab(mem_dataspace, H5S_SELECT_SET, mem_start, mem_stride, mem_count, NULL);
+''')
+                #  
+                #   This looks like a typo because 'mem_stride' and 'mem_count' are used with 'file_start' are used here.
+                #   But it isn't a typo. The idea here is that the selection we want to make in the file has the same
+                #   number of elements in each dimension and the same stride as in memory (but ignoring the last dimension).
+                #   The only difference is the starting position for the selection.
+                # 
+                if fileDimReps: # generated from line 132, col 9
+                    #  We can only do a selection in the file if the output data is more than zero-dimensional
+                    write(u'''H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, file_start, mem_stride, mem_count, NULL);
+''')
+                write(u'''
+if (dataset_''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 137, col 13
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 137, col 13.
+                write(u''')
+  H5D''')
+                _v = VFFSL(SL,"operation",True) # u'${operation}' on line 138, col 6
+                if _v is not None: write(_filter(_v, rawExpr=u'${operation}')) # from line 138, col 6.
+                write(u'''(dataset_''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 138, col 27
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 138, col 27.
+                write(u''', H5T_NATIVE_REAL, mem_dataspace, file_dataspace, H5P_DEFAULT, ''')
+                _v = VFFSL(SL,"variable.arrayName",True) # u'${variable.arrayName}' on line 138, col 106
+                if _v is not None: write(_filter(_v, rawExpr=u'${variable.arrayName}')) # from line 138, col 106.
+                write(u''');
+''')
+            trans = _orig_trans_30798580
+            write = trans.response().write
+            self._CHEETAH__isBuffering = _wasBuffering_30798580 
+            writeLoopContents = _captureCollector_30798580.response().getvalue()
+            del _orig_trans_30798580
+            del _captureCollector_30798580
+            del _wasBuffering_30798580
+            # 
+            #  Permit the driver to modify the writeLoopContents
+            featureOrdering = ['Driver']
+            dict = {'writeLoopContents': writeLoopContents,                  'dimRepOrdering': dimRepOrdering}
+            VFFSL(SL,"insertCodeForFeatures",False)('writeDataHDF5ModifyLoopContents', featureOrdering, dict)
+            writeLoopContents = dict['writeLoopContents']
+            # 
+            #  The object passed as the first argument to this next call is a 
+            write(u'''// Select hyperslabs of memory and file data spaces for data transfer operation
+''')
+            _v = VFFSL(SL,"splitUniformDataSelect",False)(dimRepOrdering[:], writeLoopContents, dimensionOffsets) # u'${splitUniformDataSelect(dimRepOrdering[:], writeLoopContents, dimensionOffsets)}' on line 151, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${splitUniformDataSelect(dimRepOrdering[:], writeLoopContents, dimensionOffsets)}')) # from line 151, col 1.
+            write(u'''
+H5Sclose(mem_dataspace);
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def splitUniformDataSelect(self, remainingDimReps, writeLoopContents, dimensionOffsets, **KWS):
+
+
+
+        ## CHEETAH: generated from @def splitUniformDataSelect(remainingDimReps, writeLoopContents, dimensionOffsets) at line 157, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        if not remainingDimReps: # generated from line 158, col 3
+            _v = VFFSL(SL,"writeLoopContents",True) # u'${writeLoopContents}' on line 159, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${writeLoopContents}')) # from line 159, col 1.
+        else: # generated from line 160, col 3
+            fileDimNum, memDimNum, dimRep = remainingDimReps.pop(0)
+            if isinstance(dimRep, SplitUniformDimensionRepresentation): # generated from line 162, col 5
+                write(u'''for (bool _positive_''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 163, col 21
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 163, col 21.
+                write(u''' = true; ; _positive_''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 163, col 56
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 163, col 56.
+                write(u''' = false) {
+  if (_positive_''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 164, col 17
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 164, col 17.
+                write(u''') {
+    mem_start[''')
+                _v = VFFSL(SL,"memDimNum",True) # u'$memDimNum' on line 165, col 15
+                if _v is not None: write(_filter(_v, rawExpr=u'$memDimNum')) # from line 165, col 15.
+                write(u'''] = 0;
+    if (''')
+                _v = VFFSL(SL,"dimRep.localOffset",True) # u'$dimRep.localOffset' on line 166, col 9
+                if _v is not None: write(_filter(_v, rawExpr=u'$dimRep.localOffset')) # from line 166, col 9.
+                write(u''' >= ((''')
+                _v = VFFSL(SL,"dimRep.globalLattice",True) # u'$dimRep.globalLattice' on line 166, col 34
+                if _v is not None: write(_filter(_v, rawExpr=u'$dimRep.globalLattice')) # from line 166, col 34.
+                write(u'''-1)/2 +1)) // No positive values are stored in this rank.
+      continue;
+    mem_count[''')
+                _v = VFFSL(SL,"memDimNum",True) # u'$memDimNum' on line 168, col 15
+                if _v is not None: write(_filter(_v, rawExpr=u'$memDimNum')) # from line 168, col 15.
+                write(u'''] = MIN(((''')
+                _v = VFFSL(SL,"dimRep.globalLattice",True) # u'$dimRep.globalLattice' on line 168, col 35
+                if _v is not None: write(_filter(_v, rawExpr=u'$dimRep.globalLattice')) # from line 168, col 35.
+                write(u'''-1)/2 +1) - ''')
+                _v = VFFSL(SL,"dimRep.localOffset",True) # u'$dimRep.localOffset' on line 168, col 68
+                if _v is not None: write(_filter(_v, rawExpr=u'$dimRep.localOffset')) # from line 168, col 68.
+                write(u''', ''')
+                _v = VFFSL(SL,"dimRep.localLattice",True) # u'$dimRep.localLattice' on line 168, col 89
+                if _v is not None: write(_filter(_v, rawExpr=u'$dimRep.localLattice')) # from line 168, col 89.
+                write(u''');
+    file_start[''')
+                _v = VFFSL(SL,"fileDimNum",True) # u'$fileDimNum' on line 169, col 16
+                if _v is not None: write(_filter(_v, rawExpr=u'$fileDimNum')) # from line 169, col 16.
+                write(u'''] = file_dims[''')
+                _v = VFFSL(SL,"fileDimNum",True) # u'$fileDimNum' on line 169, col 41
+                if _v is not None: write(_filter(_v, rawExpr=u'$fileDimNum')) # from line 169, col 41.
+                write(u''']/2 + ''')
+                _v = VFFSL(SL,"dimRep.localOffset",True) # u'$dimRep.localOffset' on line 169, col 58
+                if _v is not None: write(_filter(_v, rawExpr=u'$dimRep.localOffset')) # from line 169, col 58.
+                write(u''';
+''')
+                if dimRep.name in dimensionOffsets: # generated from line 170, col 7
+                    write(u'''    if (''')
+                    _v = VFFSL(SL,"dimRep.localOffset",True) # u'$dimRep.localOffset' on line 171, col 9
+                    if _v is not None: write(_filter(_v, rawExpr=u'$dimRep.localOffset')) # from line 171, col 9.
+                    write(u''' > ((file_dims[''')
+                    _v = VFFSL(SL,"fileDimNum",True) # u'$fileDimNum' on line 171, col 43
+                    if _v is not None: write(_filter(_v, rawExpr=u'$fileDimNum')) # from line 171, col 43.
+                    write(u''']-1)/2 +1))
+      continue;
+    mem_count[''')
+                    _v = VFFSL(SL,"memDimNum",True) # u'$memDimNum' on line 173, col 15
+                    if _v is not None: write(_filter(_v, rawExpr=u'$memDimNum')) # from line 173, col 15.
+                    write(u'''] = MIN(mem_count[''')
+                    _v = VFFSL(SL,"memDimNum",True) # u'$memDimNum' on line 173, col 43
+                    if _v is not None: write(_filter(_v, rawExpr=u'$memDimNum')) # from line 173, col 43.
+                    write(u'''], ((file_dims[''')
+                    _v = VFFSL(SL,"fileDimNum",True) # u'$fileDimNum' on line 173, col 68
+                    if _v is not None: write(_filter(_v, rawExpr=u'$fileDimNum')) # from line 173, col 68.
+                    write(u''']-1)/2 +1) - ''')
+                    _v = VFFSL(SL,"dimRep.localOffset",True) # u'$dimRep.localOffset' on line 173, col 92
+                    if _v is not None: write(_filter(_v, rawExpr=u'$dimRep.localOffset')) # from line 173, col 92.
+                    write(u''');
+''')
+                write(u'''  } else {
+    if ((''')
+                _v = VFFSL(SL,"dimRep.globalLattice",True) # u'$dimRep.globalLattice' on line 176, col 10
+                if _v is not None: write(_filter(_v, rawExpr=u'$dimRep.globalLattice')) # from line 176, col 10.
+                write(u'''-1)/2+1 < ''')
+                _v = VFFSL(SL,"dimRep.localOffset",True) # u'$dimRep.localOffset' on line 176, col 41
+                if _v is not None: write(_filter(_v, rawExpr=u'$dimRep.localOffset')) # from line 176, col 41.
+                write(u''') // Only negative values are stored in this rank.
+      mem_start[''')
+                _v = VFFSL(SL,"memDimNum",True) # u'$memDimNum' on line 177, col 17
+                if _v is not None: write(_filter(_v, rawExpr=u'$memDimNum')) # from line 177, col 17.
+                write(u'''] = 0;
+    else
+      mem_start[''')
+                _v = VFFSL(SL,"memDimNum",True) # u'$memDimNum' on line 179, col 17
+                if _v is not None: write(_filter(_v, rawExpr=u'$memDimNum')) # from line 179, col 17.
+                write(u'''] = (''')
+                _v = VFFSL(SL,"dimRep.globalLattice",True) # u'$dimRep.globalLattice' on line 179, col 32
+                if _v is not None: write(_filter(_v, rawExpr=u'$dimRep.globalLattice')) # from line 179, col 32.
+                write(u'''-1)/2+1 - ''')
+                _v = VFFSL(SL,"dimRep.localOffset",True) # u'$dimRep.localOffset' on line 179, col 63
+                if _v is not None: write(_filter(_v, rawExpr=u'$dimRep.localOffset')) # from line 179, col 63.
+                write(u''';
+    file_start[''')
+                _v = VFFSL(SL,"fileDimNum",True) # u'$fileDimNum' on line 180, col 16
+                if _v is not None: write(_filter(_v, rawExpr=u'$fileDimNum')) # from line 180, col 16.
+                write(u'''] = mem_start[''')
+                _v = VFFSL(SL,"memDimNum",True) # u'$memDimNum' on line 180, col 41
+                if _v is not None: write(_filter(_v, rawExpr=u'$memDimNum')) # from line 180, col 41.
+                write(u'''] + ''')
+                _v = VFFSL(SL,"dimRep.localOffset",True) # u'$dimRep.localOffset' on line 180, col 55
+                if _v is not None: write(_filter(_v, rawExpr=u'$dimRep.localOffset')) # from line 180, col 55.
+                write(u''' - ((''')
+                _v = VFFSL(SL,"dimRep.globalLattice",True) # u'$dimRep.globalLattice' on line 180, col 79
+                if _v is not None: write(_filter(_v, rawExpr=u'$dimRep.globalLattice')) # from line 180, col 79.
+                write(u'''-1)/2+1);
+    if (''')
+                _v = VFFSL(SL,"dimRep.localLattice",True) # u'$dimRep.localLattice' on line 181, col 9
+                if _v is not None: write(_filter(_v, rawExpr=u'$dimRep.localLattice')) # from line 181, col 9.
+                write(u''' <= mem_start[''')
+                _v = VFFSL(SL,"memDimNum",True) # u'$memDimNum' on line 181, col 43
+                if _v is not None: write(_filter(_v, rawExpr=u'$memDimNum')) # from line 181, col 43.
+                write(u''']) // No negative values are stored in this rank.
+      break; // end loop over this dimension
+    mem_count[''')
+                _v = VFFSL(SL,"memDimNum",True) # u'$memDimNum' on line 183, col 15
+                if _v is not None: write(_filter(_v, rawExpr=u'$memDimNum')) # from line 183, col 15.
+                write(u'''] = ''')
+                _v = VFFSL(SL,"dimRep.localLattice",True) # u'$dimRep.localLattice' on line 183, col 29
+                if _v is not None: write(_filter(_v, rawExpr=u'$dimRep.localLattice')) # from line 183, col 29.
+                write(u''' - mem_start[''')
+                _v = VFFSL(SL,"memDimNum",True) # u'$memDimNum' on line 183, col 62
+                if _v is not None: write(_filter(_v, rawExpr=u'$memDimNum')) # from line 183, col 62.
+                write(u''']; // To the end of this dimension
+''')
+                if dimRep.name in dimensionOffsets: # generated from line 184, col 7
+                    write(u'''    if ((long)file_start[''')
+                    _v = VFFSL(SL,"fileDimNum",True) # u'$fileDimNum' on line 185, col 26
+                    if _v is not None: write(_filter(_v, rawExpr=u'$fileDimNum')) # from line 185, col 26.
+                    write(u'''] > ''')
+                    _v = VFFSL(SL,"dimensionOffsets",True)[dimRep.name] # u'${dimensionOffsets[dimRep.name]}' on line 185, col 41
+                    if _v is not None: write(_filter(_v, rawExpr=u'${dimensionOffsets[dimRep.name]}')) # from line 185, col 41.
+                    write(u''')
+      file_start[''')
+                    _v = VFFSL(SL,"fileDimNum",True) # u'$fileDimNum' on line 186, col 18
+                    if _v is not None: write(_filter(_v, rawExpr=u'$fileDimNum')) # from line 186, col 18.
+                    write(u'''] -= ''')
+                    _v = VFFSL(SL,"dimensionOffsets",True)[dimRep.name] # u'${dimensionOffsets[dimRep.name]}' on line 186, col 34
+                    if _v is not None: write(_filter(_v, rawExpr=u'${dimensionOffsets[dimRep.name]}')) # from line 186, col 34.
+                    write(u''';
+    else {
+      mem_start[''')
+                    _v = VFFSL(SL,"memDimNum",True) # u'$memDimNum' on line 188, col 17
+                    if _v is not None: write(_filter(_v, rawExpr=u'$memDimNum')) # from line 188, col 17.
+                    write(u'''] += ''')
+                    _v = VFFSL(SL,"dimensionOffsets",True)[dimRep.name] # u'${dimensionOffsets[dimRep.name]}' on line 188, col 32
+                    if _v is not None: write(_filter(_v, rawExpr=u'${dimensionOffsets[dimRep.name]}')) # from line 188, col 32.
+                    write(u''' - file_start[''')
+                    _v = VFFSL(SL,"fileDimNum",True) # u'$fileDimNum' on line 188, col 78
+                    if _v is not None: write(_filter(_v, rawExpr=u'$fileDimNum')) # from line 188, col 78.
+                    write(u'''];
+      if (mem_count[''')
+                    _v = VFFSL(SL,"memDimNum",True) # u'$memDimNum' on line 189, col 21
+                    if _v is not None: write(_filter(_v, rawExpr=u'$memDimNum')) # from line 189, col 21.
+                    write(u'''] > ''')
+                    _v = VFFSL(SL,"dimensionOffsets",True)[dimRep.name] # u'${dimensionOffsets[dimRep.name]}' on line 189, col 35
+                    if _v is not None: write(_filter(_v, rawExpr=u'${dimensionOffsets[dimRep.name]}')) # from line 189, col 35.
+                    write(u''' - file_start[''')
+                    _v = VFFSL(SL,"fileDimNum",True) # u'$fileDimNum' on line 189, col 81
+                    if _v is not None: write(_filter(_v, rawExpr=u'$fileDimNum')) # from line 189, col 81.
+                    write(u'''])
+        mem_count[''')
+                    _v = VFFSL(SL,"memDimNum",True) # u'$memDimNum' on line 190, col 19
+                    if _v is not None: write(_filter(_v, rawExpr=u'$memDimNum')) # from line 190, col 19.
+                    write(u'''] -= ''')
+                    _v = VFFSL(SL,"dimensionOffsets",True)[dimRep.name] # u'${dimensionOffsets[dimRep.name]}' on line 190, col 34
+                    if _v is not None: write(_filter(_v, rawExpr=u'${dimensionOffsets[dimRep.name]}')) # from line 190, col 34.
+                    write(u''' - file_start[''')
+                    _v = VFFSL(SL,"fileDimNum",True) # u'$fileDimNum' on line 190, col 80
+                    if _v is not None: write(_filter(_v, rawExpr=u'$fileDimNum')) # from line 190, col 80.
+                    write(u'''];
+      else
+        break; // end loop over this dimension
+      file_start[''')
+                    _v = VFFSL(SL,"fileDimNum",True) # u'$fileDimNum' on line 193, col 18
+                    if _v is not None: write(_filter(_v, rawExpr=u'$fileDimNum')) # from line 193, col 18.
+                    write(u'''] = 0;
+    }
+''')
+                write(u'''  }
+  
+  ''')
+                _v = VFFSL(SL,"splitUniformDataSelect",False)(remainingDimReps, writeLoopContents, dimensionOffsets) # u'${splitUniformDataSelect(remainingDimReps, writeLoopContents, dimensionOffsets), autoIndent=True}' on line 198, col 3
+                if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${splitUniformDataSelect(remainingDimReps, writeLoopContents, dimensionOffsets), autoIndent=True}')) # from line 198, col 3.
+                write(u'''  
+  if (!_positive_''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 200, col 18
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 200, col 18.
+                write(u''')
+    break;
+}
+''')
+            else: # generated from line 203, col 5
+                _v = VFFSL(SL,"splitUniformDataSelect",False)(remainingDimReps, writeLoopContents, dimensionOffsets) # u'${splitUniformDataSelect(remainingDimReps, writeLoopContents, dimensionOffsets)}' on line 204, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${splitUniformDataSelect(remainingDimReps, writeLoopContents, dimensionOffsets)}')) # from line 204, col 1.
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # HDF5.tmpl
+        # 
+        # Created by Graham Dennis on 2008-03-28.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    uselib = ['hdf5']
+
+    _mainCheetahMethod_for_HDF5= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(HDF5, '_initCheetahAttributes'):
+    templateAPIClass = getattr(HDF5, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(HDF5)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=HDF5()).run()
+
+
diff --git a/xpdeint/HDF5.tmpl b/xpdeint/HDF5.tmpl
new file mode 100644
index 0000000..ff2c7df
--- /dev/null
+++ b/xpdeint/HDF5.tmpl
@@ -0,0 +1,207 @@
+@*
+HDF5.tmpl
+
+Created by Graham Dennis on 2008-03-28.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.ScriptElement
+
+ at from xpdeint.Geometry.SplitUniformDimensionRepresentation import SplitUniformDimensionRepresentation
+ at from xpdeint.CallOnceGuards import callOnceGuard
+ at from itertools import chain
+
+ at attr $uselib = ['hdf5']
+
+@@callOnceGuard
+ at def includes
+  @#
+  @super
+  @#
+#define H5_USE_16_API
+#include <hdf5.h>
+
+#if !defined(HAVE_H5LEXISTS)
+htri_t H5Lexists(hid_t loc_id, const char *name, hid_t lapl_id)
+{
+  H5E_auto_t error_func;
+  void* error_client_data;
+  // Squelch errors generated by H5Gget_objinfo. It will report errors when it can't find an object
+  // but that's the purpose of calling it.
+  H5Eget_auto(&error_func, &error_client_data);
+  H5Eset_auto(NULL, NULL);
+  herr_t err = H5Gget_objinfo(loc_id, name, false, NULL);
+  H5Eset_auto(error_func, error_client_data);
+  if (err >= 0)
+    return true;
+  else
+    return false;
+}
+#endif
+
+#define H5T_NATIVE_REAL H5T_NATIVE_${{'double': 'DOUBLE', 'single': 'FLOAT'}[$precision]}
+  @#
+ at end def
+
+ at def processData(dict)
+  @set $field = dict['field']
+  @set $basis = dict['basis']
+  @set $operation = dict['operation']
+  @assert operation in ['read', 'write']
+  @set $variables = dict['variables']
+  @set $dimensionOffsets = dict.get('dimensionOffsets', {})
+  @set $componentCount = 0
+  @for $variable in $variables
+    @set $componentCount += len($variable.vector.components)
+    @if $variable.vector.type == 'complex'
+      @set $componentCount += len($variable.vector.components)
+    @end if
+  @end for
+  @set dict['componentCount'] = componentCount
+/* Create the data space */
+  @set $dimensionCount = len(field.dimensions)
+  @# File dim reps must be in dimension order as that is the order we desire for write-out
+  @set $fileDimReps = [dim.inBasis(basis) for dim in field.dimensions]
+  @set $memDimReps = field.inBasis(basis)
+  @# Construct a list of (fileDimNum, memDimNum, dimRep) tuples. This is necessary
+  @# for the case where we are using a distributed MPI driver with FFT's
+  @# and the first two dimensions are transformed. In this situation, the
+  @# first and second dimensions are transposed.
+  @#
+  @set dimRepOrdering = [(fileDimNum, memDimReps.index(dimRep), dimRep) \
+                         for fileDimNum, dimRep in enumerate(fileDimReps)]
+  @#
+hsize_t file_start[${dimensionCount}] = {${', '.join(dimRep.localOffset for dimRep in fileDimReps)}};
+hsize_t mem_dims[${dimensionCount+1}] = {${', '.join(chain((dimRep.localLattice for dimRep in memDimReps), ['1']))}};
+hsize_t mem_start[${dimensionCount+1}] = {${', '.join(['0']*(dimensionCount+1))}};
+hsize_t mem_stride[${dimensionCount+1}] = {${', '.join(['1']*(dimensionCount+1))}};
+hsize_t mem_count[${dimensionCount+1}] = {${', '.join(chain((dimRep.localLattice for dimRep in memDimReps), ['1']))}};
+
+  @for fileDimNum, memDimNum, dimRep in dimRepOrdering
+    @if dimRep.name in dimensionOffsets and not isinstance(dimRep, SplitUniformDimensionRepresentation)
+      @set offset = dimensionOffsets[dimRep.name]
+if (file_start[${fileDimNum}] < ${offset}) {
+  if (mem_count[${memDimNum}] < ${offset} - file_start[${fileDimNum}])
+    mem_count[${memDimNum}] = 0;
+  else {
+    mem_count[${memDimNum}] -= ${offset} - file_start[${fileDimNum}];
+    mem_start[${memDimNum}] += ${offset} - file_start[${fileDimNum}];
+  }
+  file_start[${fileDimNum}] = 0;
+} else {
+  file_start[${fileDimNum}] -= ${offset};
+}
+
+if (mem_count[$memDimNum] > file_dims[$fileDimNum]) {
+  mem_count[$memDimNum] = file_dims[$fileDimNum];
+}
+    @end if
+  @end for
+
+hid_t mem_dataspace;
+  @for variable in variables
+    @set $components = $variable.separatedComponents
+mem_dims[${dimensionCount}] = ${len(components)};
+mem_dataspace = H5Screate_simple(${dimensionCount+1}, mem_dims, NULL);
+mem_stride[${dimensionCount}] = ${len(components)};
+
+    @capture writeLoopContents
+      @for offset, componentName in components
+mem_start[${dimensionCount}] = $offset;
+H5Sselect_hyperslab(mem_dataspace, H5S_SELECT_SET, mem_start, mem_stride, mem_count, NULL);
+        @# 
+        @#  This looks like a typo because 'mem_stride' and 'mem_count' are used with 'file_start' are used here.
+        @#  But it isn't a typo. The idea here is that the selection we want to make in the file has the same
+        @#  number of elements in each dimension and the same stride as in memory (but ignoring the last dimension).
+        @#  The only difference is the starting position for the selection.
+        @#
+        @if fileDimReps
+          @# We can only do a selection in the file if the output data is more than zero-dimensional
+H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, file_start, mem_stride, mem_count, NULL);
+        @end if
+
+if (dataset_${componentName})
+  H5D${operation}(dataset_${componentName}, H5T_NATIVE_REAL, mem_dataspace, file_dataspace, H5P_DEFAULT, ${variable.arrayName});
+      @end for
+    @end capture
+    @#
+    @# Permit the driver to modify the writeLoopContents
+    @set $featureOrdering = ['Driver']
+    @set $dict = {'writeLoopContents': writeLoopContents,
+                  'dimRepOrdering': dimRepOrdering}
+    @silent $insertCodeForFeatures('writeDataHDF5ModifyLoopContents', featureOrdering, dict)
+    @set $writeLoopContents = dict['writeLoopContents']
+    @#
+    @# The object passed as the first argument to this next call is a 
+// Select hyperslabs of memory and file data spaces for data transfer operation
+${splitUniformDataSelect(dimRepOrdering[:], writeLoopContents, dimensionOffsets)}@slurp
+
+H5Sclose(mem_dataspace);
+  @end for
+ at end def
+
+ at def splitUniformDataSelect(remainingDimReps, writeLoopContents, dimensionOffsets)
+  @if not remainingDimReps
+${writeLoopContents}@slurp
+  @else
+    @set fileDimNum, memDimNum, dimRep = remainingDimReps.pop(0)
+    @if isinstance(dimRep, SplitUniformDimensionRepresentation)
+for (bool _positive_${dimRep.name} = true; ; _positive_${dimRep.name} = false) {
+  if (_positive_${dimRep.name}) {
+    mem_start[$memDimNum] = 0;
+    if ($dimRep.localOffset >= (($dimRep.globalLattice-1)/2 +1)) // No positive values are stored in this rank.
+      continue;
+    mem_count[$memDimNum] = MIN((($dimRep.globalLattice-1)/2 +1) - $dimRep.localOffset, $dimRep.localLattice);
+    file_start[$fileDimNum] = file_dims[$fileDimNum]/2 + $dimRep.localOffset;
+      @if dimRep.name in dimensionOffsets
+    if ($dimRep.localOffset > ((file_dims[$fileDimNum]-1)/2 +1))
+      continue;
+    mem_count[$memDimNum] = MIN(mem_count[$memDimNum], ((file_dims[$fileDimNum]-1)/2 +1) - $dimRep.localOffset);
+      @end if
+  } else {
+    if (($dimRep.globalLattice-1)/2+1 < $dimRep.localOffset) // Only negative values are stored in this rank.
+      mem_start[$memDimNum] = 0;
+    else
+      mem_start[$memDimNum] = ($dimRep.globalLattice-1)/2+1 - $dimRep.localOffset;
+    file_start[$fileDimNum] = mem_start[$memDimNum] + $dimRep.localOffset - (($dimRep.globalLattice-1)/2+1);
+    if ($dimRep.localLattice <= mem_start[$memDimNum]) // No negative values are stored in this rank.
+      break; // end loop over this dimension
+    mem_count[$memDimNum] = $dimRep.localLattice - mem_start[$memDimNum]; // To the end of this dimension
+      @if dimRep.name in dimensionOffsets
+    if ((long)file_start[$fileDimNum] > ${dimensionOffsets[dimRep.name]})
+      file_start[$fileDimNum] -= ${dimensionOffsets[dimRep.name]};
+    else {
+      mem_start[$memDimNum] += ${dimensionOffsets[dimRep.name]} - file_start[$fileDimNum];
+      if (mem_count[$memDimNum] > ${dimensionOffsets[dimRep.name]} - file_start[$fileDimNum])
+        mem_count[$memDimNum] -= ${dimensionOffsets[dimRep.name]} - file_start[$fileDimNum];
+      else
+        break; // end loop over this dimension
+      file_start[$fileDimNum] = 0;
+    }
+      @end if
+  }
+  
+  ${splitUniformDataSelect(remainingDimReps, writeLoopContents, dimensionOffsets), autoIndent=True}@slurp
+  
+  if (!_positive_${dimRep.name})
+    break;
+}
+    @else
+${splitUniformDataSelect(remainingDimReps, writeLoopContents, dimensionOffsets)}@slurp
+    @end if
+  @end if
+ at end def
diff --git a/xpdeint/IndentFilter.py b/xpdeint/IndentFilter.py
new file mode 100644
index 0000000..bb56903
--- /dev/null
+++ b/xpdeint/IndentFilter.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+IndentFilter.py
+
+Created by Graham Dennis on 2007-08-29.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from Cheetah.Filters import Filter
+
+import sys
+
+class IndentFilter(Filter):
+  def filter(self, val, **kw):
+    """
+    Cheetah filter for indenting code.
+    
+    This is oh-so-hackish. I say this because ``trans`` is a transaction
+    that is designed to be used when Cheetah is used in WebWare
+    servlets. Fortunately for me, a dummy transaction is always
+    available that buffers output for every function, so I can just
+    ask the transaction for the buffer, and extract the last line to get
+    the context for this replacement. If it is pure whitespace, then I
+    know that each line of the replacement text (except the first)
+    should begin with that whitespace. The first line doesn't need the
+    whitespace because it was there before the call.
+    
+    The result of all this is that if you want auto-indentation, you just
+    need to call the filter with the argument ``autoIndent=True``. The following is
+    an example of typical usage::
+    
+        <some whitespace>${someRandomVariableOrFunction, autoIndent=True}@slurp
+    
+    This way, the whitespace before the variable replacement will be used for each
+    line of the replacement text.
+    
+    The transaction is obtained from the calling frame using Python's introspection
+    capabilities. (Go Python!)
+    
+    Additionally, the option ``extraIndent=n`` can be passed which increases
+    the indent by ``n`` spaces.
+    """
+    # Quickly check for the case where we have nothing to do
+    if not (kw.get('autoIndent') or kw.get('extraIndent')):
+      return super(IndentFilter, self).filter(val, **kw)
+    trans = None
+    indentString = ''
+    firstLineIndent = ''
+    # Add the extra indent spaces
+    if kw.get('extraIndent'):
+      indentString += ' '*kw['extraIndent']
+      firstLineIndent += ' '*kw['extraIndent']
+    
+    replacementString = super(IndentFilter, self).filter(val, **kw)
+    
+    # If the replacement string is just space, just use an empty string instead.
+    if replacementString == None or replacementString.isspace():
+      replacementString = ''
+    
+    if kw.get('autoIndent'):
+      # Grab the transaction object from our caller's frame. Yay introspection.
+      callerFrame = sys._getframe(1)
+      trans = callerFrame.f_locals['trans']
+      del callerFrame
+      
+      temp = trans.response().getvalue().rsplit('\n', 1)
+      everythingBeforeLastLine = temp[0]
+      lastLine = temp[-1]
+      
+      # Only add the contents of the last line to the indent string if it is only whitespace
+      if lastLine.isspace():
+        indentString += lastLine
+      
+      # Erase the last line and return an empty string if we have no replacement
+      # But only if the last line consists of pure whitespace
+      if len(replacementString) == 0 and lastLine.isspace():
+        del trans.response()._outputChunks[:]
+        trans.response()._outputChunks.append(everythingBeforeLastLine + '\n')
+        return ''
+    
+    # if either the indent string or the replacement string is empty, there's nothing to do
+    if len(indentString) == 0 or len(replacementString) == 0:
+      return replacementString
+    
+    # split the replacement string into lines (keeping the newline characters)
+    replacementLines = replacementString.splitlines(True)
+    
+    # we don't do anything to the first line (except add the firstLineIndent),
+    # so if there's only one, we're pretty much done
+    if len(replacementLines) == 1:
+      return firstLineIndent + replacementString
+    
+    # add the firstLineIndent to the first line.
+    if len(firstLineIndent):
+      replacementLines[0] = firstLineIndent + replacementLines[0]
+    
+    # add the indentString to the start of each line (except the first). (Yay Python)
+    replacementLines[1:] = map(lambda x: indentString + x, replacementLines[1:])
+    return "".join(replacementLines)
+  
diff --git a/xpdeint/Makefile b/xpdeint/Makefile
new file mode 100644
index 0000000..2b6aa3d
--- /dev/null
+++ b/xpdeint/Makefile
@@ -0,0 +1,22 @@
+.PHONY: all update clean check distclean
+
+all: wscript waf_extensions/cheetah.py c4che
+	@waf/waf-light build
+	@sh version.sh
+
+update:
+	@(cd ..; $(MAKE) $(MFLAGS) update;)
+
+c4che: wscript waf_extensions/cheetah.py
+	@waf/waf-light configure
+
+clean:
+	@waf/waf-light clean
+
+# check examples compile
+check:
+	@for i in examples/*.xmds; do \
+	echo $$i; xmds2 $$i; done
+
+distclean:
+	@waf/waf-light distclean
diff --git a/xpdeint/MomentGroupElement.py b/xpdeint/MomentGroupElement.py
new file mode 100644
index 0000000..ad20f01
--- /dev/null
+++ b/xpdeint/MomentGroupElement.py
@@ -0,0 +1,457 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint._MomentGroupElement import _MomentGroupElement
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322831.985987
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:31 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/MomentGroupElement.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 13:11:27 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class MomentGroupElement(_MomentGroupElement):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(MomentGroupElement, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: moment group $number at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''moment group ''')
+        _v = VFFSL(SL,"number",True) # u'$number' on line 27, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'$number')) # from line 27, col 32.
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def sampleFunctionContents(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def sampleFunctionContents($function) at line 33, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        #  Evaluate any computed vectors we have that either we or one
+        #  of our operators depends on
+        featureOrdering = ['ChunkedOutput']
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('sampleFunctionBegin', VFFSL(SL,"featureOrdering",True)) # u"${insertCodeForFeatures('sampleFunctionBegin', $featureOrdering), autoIndent=True}" on line 37, col 1
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeatures('sampleFunctionBegin', $featureOrdering), autoIndent=True}")) # from line 37, col 1.
+        computedVectorDependencies = VFN(VFN(VFFSL(SL,"codeBlocks",True)['sampling'],"dependencies",True),"copy",False)()
+        computedVectorDependencies.update(VFFSL(SL,"dynamicVectorsNeedingPrecalculationForOperatorContainers",False)(VFFSL(SL,"operatorContainers",True)))
+        _v = VFFSL(SL,"evaluateComputedVectors",False)(computedVectorDependencies) # u'${evaluateComputedVectors(computedVectorDependencies)}' on line 40, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${evaluateComputedVectors(computedVectorDependencies)}')) # from line 40, col 1.
+        # 
+        #  Execute any operatorContainers
+        for operatorContainer in VFFSL(SL,"operatorContainers",True): # generated from line 43, col 3
+            write(u'''
+''')
+            _v = VFN(VFFSL(SL,"operatorContainer",True),"evaluateOperators",False)(parentFunction=function) # u'${operatorContainer.evaluateOperators(parentFunction=function)}' on line 45, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${operatorContainer.evaluateOperators(parentFunction=function)}')) # from line 45, col 1.
+        write(u'''
+''')
+        # 
+        #  Now actually begin the loop
+        _v = VFN(VFFSL(SL,"codeBlocks",True)['sampling'],"loop",False)(self.insideSamplingLoops) # u"${codeBlocks['sampling'].loop(self.insideSamplingLoops)}" on line 50, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${codeBlocks['sampling'].loop(self.insideSamplingLoops)}")) # from line 50, col 1.
+        #  That's the end of the loop, magic eh?
+        # 
+        if VFN(VFFSL(SL,"outputField",True),"hasDimensionName",False)(VFFSL(SL,"propagationDimension",True)): # generated from line 53, col 3
+            write(u'''
+''')
+            _v = VFFSL(SL,"propDimRep.arrayName",True) # u'${propDimRep.arrayName}' on line 55, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${propDimRep.arrayName}')) # from line 55, col 1.
+            write(u'''[''')
+            _v = VFFSL(SL,"propDimRep.localOffset",True) # u'${propDimRep.localOffset}' on line 55, col 25
+            if _v is not None: write(_filter(_v, rawExpr=u'${propDimRep.localOffset}')) # from line 55, col 25.
+            write(u''' + ''')
+            _v = VFFSL(SL,"propDimRep.index",True) # u'${propDimRep.index}' on line 55, col 53
+            if _v is not None: write(_filter(_v, rawExpr=u'${propDimRep.index}')) # from line 55, col 53.
+            write(u'''++] = ''')
+            _v = VFFSL(SL,"propagationDimension",True) # u'$propagationDimension' on line 55, col 78
+            if _v is not None: write(_filter(_v, rawExpr=u'$propagationDimension')) # from line 55, col 78.
+            write(u''';
+''')
+        write(u'''
+_LOG(_SAMPLE_LOG_LEVEL, "Sampled field (for moment group #''')
+        _v = VFFSL(SL,"number",True) + 1 # u'${number + 1}' on line 58, col 59
+        if _v is not None: write(_filter(_v, rawExpr=u'${number + 1}')) # from line 58, col 59.
+        write(u''') at ''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 58, col 77
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 58, col 77.
+        write(u''' = %e\\n", ''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 58, col 110
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 58, col 110.
+        write(u''');
+
+''')
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('sampleFunctionEnd', VFFSL(SL,"featureOrdering",True)) # u"${insertCodeForFeaturesInReverseOrder('sampleFunctionEnd', $featureOrdering), autoIndent=True}" on line 60, col 1
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeaturesInReverseOrder('sampleFunctionEnd', $featureOrdering), autoIndent=True}")) # from line 60, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideSamplingLoops(self, codeString, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideSamplingLoops($codeString) at line 67, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''#define _SAMPLE_COMPLEX(variable) \\
+          variable ## R = variable.Re(); variable ## I = variable.Im();
+
+// *************** Sampling code ****************
+''')
+        _v = VFFSL(SL,"codeString",True) # u'${codeString}' on line 73, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${codeString}')) # from line 73, col 1.
+        write(u'''// **********************************************
+
+#undef _SAMPLE_COMPLEX
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def processFunctionContents(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def processFunctionContents($function) at line 83, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        #  If we don't have any processing code then we don't need to do a complicated loop
+        if not self.hasattr('processingCode'): # generated from line 85, col 3
+            #  If we didn't allocate a raw vector, then there actually is no processing to do
+            #  at all.
+            if not VFFSL(SL,"rawVectorNeedsToBeAllocated",True): # generated from line 88, col 5
+                write(u'''// No post processing needs to be done
+''')
+            else: # generated from line 90, col 5
+                # 
+                #  Although we don't have any processing code, one of our features has
+                #  processing code that needs to run (but it is simple, right?)
+                _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)([VFFSL(SL,"rawVector",True)], VFFSL(SL,"insideProcessingLoopsNoProcessingCode",True), basis=VFFSL(SL,"outputBasis",True)) # u'${loopOverVectorsWithInnerContentTemplate([$rawVector], $insideProcessingLoopsNoProcessingCode, basis=$outputBasis)}' on line 94, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate([$rawVector], $insideProcessingLoopsNoProcessingCode, basis=$outputBasis)}')) # from line 94, col 1.
+        else: # generated from line 96, col 3
+            assert False, "Post processing of sampled data hasn't been implemented yet!"
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideProcessingLoopsNoProcessingCode(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideProcessingLoopsNoProcessingCode at line 102, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''_active_''')
+        _v = VFFSL(SL,"processedVector.id",True) # u'${processedVector.id}' on line 104, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${processedVector.id}')) # from line 104, col 9.
+        write(u'''[${index}] += _active_${vector.id}[${index}];
+''')
+        featureOrdering = ['Driver']
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('insideMomentGroupProcessingNoProcessingCodeLoop', VFFSL(SL,"featureOrdering",True)) # u"${insertCodeForFeatures('insideMomentGroupProcessingNoProcessingCodeLoop', $featureOrdering)}" on line 106, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('insideMomentGroupProcessingNoProcessingCodeLoop', $featureOrdering)}")) # from line 106, col 1.
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeOutFunctionContents(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def writeOutFunctionContents($function) at line 113, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        outputFieldVectorComponents = VFN(VFFSL(SL,"anyObject",False)(VFFSL(SL,"outputField.vectors",True)),"components",True)
+        dependentVariables = [{'vector': VFFSL(SL,"processedVector",True),                               'arrayName': ''.join([u'_active_',str(VFFSL(SL,"processedVector.id",True))]),                               'components': VFFSL(SL,"processedVector.components",True)}]
+        # 
+        #  Note that Driver must be last
+        featureOrdering = ['ErrorCheck', 'Driver']
+        dict = {'momentGroup': self, 'dependentVariables': VFFSL(SL,"dependentVariables",True)}
+        result = VFFSL(SL,"insertCodeForFeatures",False)('writeOutFunctionImplementationBegin', VFFSL(SL,"featureOrdering",True), VFFSL(SL,"dict",True))
+        dependentVariables = VFFSL(SL,"dict.dependentVariables",True)
+        componentCount = 0
+        for variable in VFFSL(SL,"dependentVariables",True): # generated from line 126, col 3
+            componentCount += len(VFFSL(SL,"variable.vector.components",True))
+            #  Technically, all these variables must be of type real...
+            if VFFSL(SL,"variable.vector.type",True) == 'complex': # generated from line 129, col 5
+                componentCount += len(VFFSL(SL,"variable.vector.components",True))
+        # 
+        #  The features can return Cheetah template code suitable for passing to loopOverVectorsWithInnerContentTemplate
+        #  in order to create their data. If any have, then we should actually create that loop and run that code.
+        if VFFSL(SL,"result",True): # generated from line 136, col 3
+            _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)([VFFSL(SL,"processedVector",True)], VFFSL(SL,"result",True), basis = VFFSL(SL,"outputBasis",True)) # u'${loopOverVectorsWithInnerContentTemplate([$processedVector], $result, basis = $outputBasis)}' on line 137, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate([$processedVector], $result, basis = $outputBasis)}')) # from line 137, col 1.
+        write(u'''
+''')
+        featureOrdering = ['ErrorCheck', 'Output']
+        dict = {'field': VFFSL(SL,"outputField",True),                'basis': VFFSL(SL,"outputBasis",True),                'fp': '_outfile',                'dependentVariables': VFFSL(SL,"dependentVariables",True),                'xsilElementName': ''.join([u'moment_group_',str(VFFSL(SL,"number",True) + 1)]),                'groupID': VFFSL(SL,"number",True)+1                }
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('writeOutFunctionImplementationBody', VFFSL(SL,"featureOrdering",True), VFFSL(SL,"dict",True)) # u"${insertCodeForFeatures('writeOutFunctionImplementationBody', $featureOrdering, $dict)}" on line 148, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('writeOutFunctionImplementationBody', $featureOrdering, $dict)}")) # from line 148, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # MomentGroupElement.tmpl
+        # 
+        # Created by Graham Dennis on 2007-09-05.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        # 
+        # 
+        #   Description of template
+        write(u'''
+
+''')
+        # 
+        #   Implementation of the moment group sample function
+        write(u'''
+''')
+        # 
+        #   This function provides the contents of the moment group sampling loop
+        write(u'''
+''')
+        # 
+        #   Process function implementation
+        write(u'''
+
+''')
+        # 
+        #   Write output function implementation
+        write(u'''
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_MomentGroupElement= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(MomentGroupElement, '_initCheetahAttributes'):
+    templateAPIClass = getattr(MomentGroupElement, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(MomentGroupElement)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=MomentGroupElement()).run()
+
+
diff --git a/xpdeint/MomentGroupElement.tmpl b/xpdeint/MomentGroupElement.tmpl
new file mode 100644
index 0000000..a7fd032
--- /dev/null
+++ b/xpdeint/MomentGroupElement.tmpl
@@ -0,0 +1,151 @@
+@*
+MomentGroupElement.tmpl
+
+Created by Graham Dennis on 2007-09-05.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint._MomentGroupElement
+@*
+
+  Description of template
+*@
+ at def description: moment group $number
+
+
+@*
+  Implementation of the moment group sample function
+*@
+ at def sampleFunctionContents($function)
+  @# Evaluate any computed vectors we have that either we or one
+  @# of our operators depends on
+  @set $featureOrdering = ['ChunkedOutput']
+${insertCodeForFeatures('sampleFunctionBegin', $featureOrdering), autoIndent=True}@slurp
+  @set $computedVectorDependencies = $codeBlocks['sampling'].dependencies.copy()
+  @silent computedVectorDependencies.update($dynamicVectorsNeedingPrecalculationForOperatorContainers($operatorContainers))
+${evaluateComputedVectors(computedVectorDependencies)}@slurp
+  @#
+  @# Execute any operatorContainers
+  @for $operatorContainer in $operatorContainers
+
+${operatorContainer.evaluateOperators(parentFunction=function)}@slurp
+  @end for
+
+  @#
+  @# Now actually begin the loop
+${codeBlocks['sampling'].loop(self.insideSamplingLoops)}@slurp
+  @# That's the end of the loop, magic eh?
+  @#
+  @if $outputField.hasDimensionName($propagationDimension)
+
+${propDimRep.arrayName}[${propDimRep.localOffset} + ${propDimRep.index}++] = $propagationDimension;
+  @end if
+
+_LOG(_SAMPLE_LOG_LEVEL, "Sampled field (for moment group #${number + 1}) at ${propagationDimension} = %e\n", ${propagationDimension});
+
+${insertCodeForFeaturesInReverseOrder('sampleFunctionEnd', $featureOrdering), autoIndent=True}@slurp
+  @#
+ at end def
+
+@*
+  This function provides the contents of the moment group sampling loop
+*@
+ at def insideSamplingLoops($codeString)
+  @#
+#define _SAMPLE_COMPLEX(variable) \
+          variable ## R = variable.Re(); variable ## I = variable.Im();
+
+// *************** Sampling code ****************
+${codeString}@slurp
+// **********************************************
+
+#undef _SAMPLE_COMPLEX
+  @#
+ at end def
+
+@*
+  Process function implementation
+*@
+ at def processFunctionContents($function)
+  @# If we don't have any processing code then we don't need to do a complicated loop
+  @if not self.hasattr('processingCode')
+    @# If we didn't allocate a raw vector, then there actually is no processing to do
+    @# at all.
+    @if not $rawVectorNeedsToBeAllocated
+// No post processing needs to be done
+    @else
+      @#
+      @# Although we don't have any processing code, one of our features has
+      @# processing code that needs to run (but it is simple, right?)
+${loopOverVectorsWithInnerContentTemplate([$rawVector], $insideProcessingLoopsNoProcessingCode, basis=$outputBasis)}@slurp
+    @end if
+  @else
+    @assert False, "Post processing of sampled data hasn't been implemented yet!"
+  @end if
+  @#
+ at end def
+
+ at def insideProcessingLoopsNoProcessingCode
+  @#
+_active_${processedVector.id}[\${index}] += _active_\${vector.id}[\${index}];
+  @set $featureOrdering = ['Driver']
+${insertCodeForFeatures('insideMomentGroupProcessingNoProcessingCodeLoop', $featureOrdering)}
+  @#
+ at end def
+
+@*
+  Write output function implementation
+*@
+ at def writeOutFunctionContents($function)
+  @#
+  @set $outputFieldVectorComponents = $anyObject($outputField.vectors).components
+  @set $dependentVariables = [{'vector': $processedVector,
+                               'arrayName': c'_active_${processedVector.id}',
+                               'components': $processedVector.components}]
+  @#
+  @# Note that Driver must be last
+  @set $featureOrdering = ['ErrorCheck', 'Driver']
+  @set $dict = {'momentGroup': self, 'dependentVariables': $dependentVariables}
+  @set $result = $insertCodeForFeatures('writeOutFunctionImplementationBegin', $featureOrdering, $dict)
+  @set $dependentVariables = $dict.dependentVariables
+  @set $componentCount = 0
+  @for $variable in $dependentVariables
+    @set $componentCount += len($variable.vector.components)
+    @# Technically, all these variables must be of type real...
+    @if $variable.vector.type == 'complex'
+      @set $componentCount += len($variable.vector.components)
+    @end if
+  @end for
+  @#
+  @# The features can return Cheetah template code suitable for passing to loopOverVectorsWithInnerContentTemplate
+  @# in order to create their data. If any have, then we should actually create that loop and run that code.
+  @if $result
+${loopOverVectorsWithInnerContentTemplate([$processedVector], $result, basis = $outputBasis)}@slurp
+  @end if
+
+  @set $featureOrdering = ['ErrorCheck', 'Output']
+  @set $dict = {'field': $outputField,
+                'basis': $outputBasis,
+                'fp': '_outfile',
+                'dependentVariables': $dependentVariables,
+                'xsilElementName': c'moment_group_${number + 1}',
+                'groupID': $number+1
+                }
+${insertCodeForFeatures('writeOutFunctionImplementationBody', $featureOrdering, $dict)}@slurp
+  @#
+ at end def
+
diff --git a/xpdeint/Operators/ConstantEXOperator.py b/xpdeint/Operators/ConstantEXOperator.py
new file mode 100644
index 0000000..c924357
--- /dev/null
+++ b/xpdeint/Operators/ConstantEXOperator.py
@@ -0,0 +1,349 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Operators._EXOperator import _EXOperator
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.002823
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Operators/ConstantEXOperator.tmpl'
+__CHEETAH_srcLastModified__ = 'Mon Jul 23 09:43:31 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class ConstantEXOperator(_EXOperator):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(ConstantEXOperator, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: EX transverse derivative operator for field $field.name at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''EX transverse derivative operator for field ''')
+        _v = VFFSL(SL,"field.name",True) # u'$field.name' on line 26, col 63
+        if _v is not None: write(_filter(_v, rawExpr=u'$field.name')) # from line 26, col 63.
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideCalculateOperatorFieldLoops(self, codeString, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideCalculateOperatorFieldLoops($codeString) at line 30, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"insideCalculateOperatorFieldLoopsBegin",True) # u'${insideCalculateOperatorFieldLoopsBegin}' on line 32, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${insideCalculateOperatorFieldLoopsBegin}')) # from line 32, col 1.
+        # 
+        write(u'''// ************** Operator code *****************
+''')
+        _v = VFFSL(SL,"codeString",True) # u'${codeString}' on line 35, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${codeString}')) # from line 35, col 1.
+        write(u'''// **********************************************
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def evaluateOperatorFunctionContentsWithoutCodeBlock(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def evaluateOperatorFunctionContentsWithoutCodeBlock($function) at line 40, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"optimisedOperatorCopyBegin",True) # u'${optimisedOperatorCopyBegin}' on line 42, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${optimisedOperatorCopyBegin}')) # from line 42, col 1.
+        # 
+        _v = super(ConstantEXOperator, self).evaluateOperatorFunctionContentsWithoutCodeBlock(function)
+        if _v is not None: write(_filter(_v))
+        # 
+        _v = VFFSL(SL,"optimisedOperatorCopyEnd",True) # u'${optimisedOperatorCopyEnd}' on line 46, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${optimisedOperatorCopyEnd}')) # from line 46, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def evaluateOperatorLoop(self, setOfVectorsToLoopOver, **KWS):
+
+
+
+        ## CHEETAH: generated from @def evaluateOperatorLoop($setOfVectorsToLoopOver) at line 50, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"loopOverVectorsInBasisWithInnerContent",False)(setOfVectorsToLoopOver, VFFSL(SL,"operatorBasis",True), VFFSL(SL,"insideEvaluateOperatorLoops",True)) # u'${loopOverVectorsInBasisWithInnerContent(setOfVectorsToLoopOver, $operatorBasis, $insideEvaluateOperatorLoops)}' on line 52, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsInBasisWithInnerContent(setOfVectorsToLoopOver, $operatorBasis, $insideEvaluateOperatorLoops)}')) # from line 52, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideEvaluateOperatorLoops(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideEvaluateOperatorLoops at line 56, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"insideEvaluateOperatorLoopsBegin",True) # u'${insideEvaluateOperatorLoopsBegin}' on line 58, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${insideEvaluateOperatorLoopsBegin}')) # from line 58, col 1.
+        # 
+        for operatorComponentNumber, (operatorComponentName, operatorComponentVectors) in enumerate(VFN(VFFSL(SL,"operatorComponents",True),"iteritems",False)()): # generated from line 60, col 3
+            for targetVectorComponents in operatorComponentVectors.itervalues(): # generated from line 61, col 5
+                for targetVectorComponent in targetVectorComponents: # generated from line 62, col 7
+                    write(u'''// ''')
+                    _v = VFFSL(SL,"operatorComponentName",True) # u'${operatorComponentName}' on line 63, col 4
+                    if _v is not None: write(_filter(_v, rawExpr=u'${operatorComponentName}')) # from line 63, col 4.
+                    write(u'''[''')
+                    _v = VFFSL(SL,"targetVectorComponent",True) # u'$targetVectorComponent' on line 63, col 29
+                    if _v is not None: write(_filter(_v, rawExpr=u'$targetVectorComponent')) # from line 63, col 29.
+                    write(u''']
+_''')
+                    _v = VFFSL(SL,"operatorComponentName",True) # u'${operatorComponentName}' on line 64, col 2
+                    if _v is not None: write(_filter(_v, rawExpr=u'${operatorComponentName}')) # from line 64, col 2.
+                    write(u'''_''')
+                    _v = VFFSL(SL,"targetVectorComponent",True) # u'${targetVectorComponent}' on line 64, col 27
+                    if _v is not None: write(_filter(_v, rawExpr=u'${targetVectorComponent}')) # from line 64, col 27.
+                    write(u''' = ''')
+                    _v = VFFSL(SL,"operatorComponentName",True) # u'$operatorComponentName' on line 64, col 54
+                    if _v is not None: write(_filter(_v, rawExpr=u'$operatorComponentName')) # from line 64, col 54.
+                    write(u''' * ''')
+                    _v = VFFSL(SL,"targetVectorComponent",True) # u'$targetVectorComponent' on line 64, col 79
+                    if _v is not None: write(_filter(_v, rawExpr=u'$targetVectorComponent')) # from line 64, col 79.
+                    write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # ConstantEXOperator.tmpl
+        # 
+        # Explicit-picture transverse derivative operator
+        # 
+        # Created by Graham Dennis on 2007-10-20.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    operatorKind = _EXOperator.OtherOperatorKind
+
+    calculateOperatorFieldFunctionArguments = []
+
+    _mainCheetahMethod_for_ConstantEXOperator= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(ConstantEXOperator, '_initCheetahAttributes'):
+    templateAPIClass = getattr(ConstantEXOperator, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(ConstantEXOperator)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=ConstantEXOperator()).run()
+
+
diff --git a/xpdeint/Operators/ConstantEXOperator.tmpl b/xpdeint/Operators/ConstantEXOperator.tmpl
new file mode 100644
index 0000000..8093caa
--- /dev/null
+++ b/xpdeint/Operators/ConstantEXOperator.tmpl
@@ -0,0 +1,69 @@
+@*
+ConstantEXOperator.tmpl
+
+Explicit-picture transverse derivative operator
+
+Created by Graham Dennis on 2007-10-20.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Operators._EXOperator
+
+ at def description: EX transverse derivative operator for field $field.name
+ at attr $operatorKind = _EXOperator.OtherOperatorKind
+ at attr $calculateOperatorFieldFunctionArguments = []
+
+ at def insideCalculateOperatorFieldLoops($codeString)
+  @#
+${insideCalculateOperatorFieldLoopsBegin}@slurp
+  @#
+// ************** Operator code *****************
+${codeString}@slurp
+// **********************************************
+  @#
+ at end def
+
+ at def evaluateOperatorFunctionContentsWithoutCodeBlock($function)
+  @#
+${optimisedOperatorCopyBegin}@slurp
+  @#
+  @super(function)
+  @#
+${optimisedOperatorCopyEnd}@slurp
+  @#
+ at end def
+
+ at def evaluateOperatorLoop($setOfVectorsToLoopOver)
+  @#
+${loopOverVectorsInBasisWithInnerContent(setOfVectorsToLoopOver, $operatorBasis, $insideEvaluateOperatorLoops)}@slurp
+  @#
+ at end def
+
+ at def insideEvaluateOperatorLoops
+  @#
+${insideEvaluateOperatorLoopsBegin}@slurp
+  @#
+  @for operatorComponentNumber, (operatorComponentName, operatorComponentVectors) in enumerate($operatorComponents.iteritems())
+    @for targetVectorComponents in operatorComponentVectors.itervalues()
+      @for targetVectorComponent in targetVectorComponents
+// ${operatorComponentName}[$targetVectorComponent]
+_${operatorComponentName}_${targetVectorComponent} = $operatorComponentName * $targetVectorComponent;
+      @end for
+    @end for
+  @end for
+  @#
+ at end def
diff --git a/xpdeint/Operators/ConstantIPOperator.py b/xpdeint/Operators/ConstantIPOperator.py
new file mode 100644
index 0000000..df4ef2a
--- /dev/null
+++ b/xpdeint/Operators/ConstantIPOperator.py
@@ -0,0 +1,370 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Operators._IPOperator import _IPOperator
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.025223
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Operators/ConstantIPOperator.tmpl'
+__CHEETAH_srcLastModified__ = 'Mon Jul 23 09:42:26 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class ConstantIPOperator(_IPOperator):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(ConstantIPOperator, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def calculateOperatorFieldFunctionContents(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def calculateOperatorFieldFunctionContents($function) at line 28, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"integrator.createStepVariable",True) # u'${integrator.createStepVariable}' on line 30, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${integrator.createStepVariable}')) # from line 30, col 1.
+        write(u'''
+''')
+        _v = super(ConstantIPOperator, self).calculateOperatorFieldFunctionContents(function)
+        if _v is not None: write(_filter(_v))
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideCalculateOperatorFieldLoops(self, codeString, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideCalculateOperatorFieldLoops($codeString) at line 37, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"insideCalculateOperatorFieldLoopsBegin",True) # u'${insideCalculateOperatorFieldLoopsBegin}' on line 39, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${insideCalculateOperatorFieldLoopsBegin}')) # from line 39, col 1.
+        # 
+        #  We expect the integrator to have defined '_step'
+        # 
+        write(u'''// ************** Operator code *****************
+''')
+        _v = VFFSL(SL,"codeString",True) # u'${codeString}' on line 44, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${codeString}')) # from line 44, col 1.
+        write(u'''// **********************************************
+''')
+        #  Loop over the propagation step fractions
+        for fractionIndex, propagationStepFraction in enumerate(VFFSL(SL,"integrator.ipPropagationStepFractions",True)): # generated from line 47, col 3
+            write(u'''    
+''')
+            #  Loop over each operator component
+            for operatorComponentNumber, operatorComponent in enumerate(VFN(VFFSL(SL,"operatorComponents",True),"iterkeys",False)()): # generated from line 50, col 5
+                offsetIndex = VFFSL(SL,"operatorComponentNumber",True) + VFFSL(SL,"fractionIndex",True) * len(VFFSL(SL,"operatorComponents",True))
+                write(u'''_''')
+                _v = VFFSL(SL,"operatorVector.id",True) # u'${operatorVector.id}' on line 52, col 2
+                if _v is not None: write(_filter(_v, rawExpr=u'${operatorVector.id}')) # from line 52, col 2.
+                write(u'''[_''')
+                _v = VFFSL(SL,"operatorVector.id",True) # u'${operatorVector.id}' on line 52, col 24
+                if _v is not None: write(_filter(_v, rawExpr=u'${operatorVector.id}')) # from line 52, col 24.
+                write(u'''_index_pointer + ''')
+                _v = VFFSL(SL,"offsetIndex",True) # u'${offsetIndex}' on line 52, col 61
+                if _v is not None: write(_filter(_v, rawExpr=u'${offsetIndex}')) # from line 52, col 61.
+                write(u'''] = ''')
+                _v = VFFSL(SL,"expFunction",True) # u'${expFunction}' on line 52, col 79
+                if _v is not None: write(_filter(_v, rawExpr=u'${expFunction}')) # from line 52, col 79.
+                write(u'''(''')
+                _v = VFFSL(SL,"operatorComponent",True) # u'${operatorComponent}' on line 52, col 94
+                if _v is not None: write(_filter(_v, rawExpr=u'${operatorComponent}')) # from line 52, col 94.
+                _v = VFFSL(SL,"valueSuffix",True) # u'${valueSuffix}' on line 52, col 114
+                if _v is not None: write(_filter(_v, rawExpr=u'${valueSuffix}')) # from line 52, col 114.
+                write(u''' * ''')
+                _v = VFFSL(SL,"propagationStepFraction",True) # u'$propagationStepFraction' on line 52, col 131
+                if _v is not None: write(_filter(_v, rawExpr=u'$propagationStepFraction')) # from line 52, col 131.
+                write(u''' * _step);
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def evaluateOperatorLoop(self, setOfVectorsToLoopOver, **KWS):
+
+
+
+        ## CHEETAH: generated from @def evaluateOperatorLoop($setOfVectorsToLoopOver) at line 58, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  We expect the integrator to have defined _exponent
+        # 
+        if len(VFFSL(SL,"integrator.ipPropagationStepFractions",True)) > 1: # generated from line 62, col 3
+            write(u'''unsigned long _exponentIndex = (abs(_exponent) - 1) * ''')
+            _v = VFFSL(SL,"len",False)(VFFSL(SL,"operatorComponents",True)) # u'$len($operatorComponents)' on line 63, col 55
+            if _v is not None: write(_filter(_v, rawExpr=u'$len($operatorComponents)')) # from line 63, col 55.
+            write(u''';
+
+''')
+        write(u'''if (_exponent > 0) {
+  ''')
+        _v = VFFSL(SL,"loopOverVectorsInBasisWithInnerContent",False)(VFFSL(SL,"setOfVectorsToLoopOver",True), VFFSL(SL,"operatorBasis",True), VFFSL(SL,"insideEvaluateOperatorLoops",False)('*')) # u"${loopOverVectorsInBasisWithInnerContent($setOfVectorsToLoopOver, $operatorBasis, $insideEvaluateOperatorLoops('*')), autoIndent=True}" on line 67, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${loopOverVectorsInBasisWithInnerContent($setOfVectorsToLoopOver, $operatorBasis, $insideEvaluateOperatorLoops('*')), autoIndent=True}")) # from line 67, col 3.
+        write(u'''} else {
+  ''')
+        _v = VFFSL(SL,"loopOverVectorsInBasisWithInnerContent",False)(VFFSL(SL,"setOfVectorsToLoopOver",True), VFFSL(SL,"operatorBasis",True), VFFSL(SL,"insideEvaluateOperatorLoops",False)('/')) # u"${loopOverVectorsInBasisWithInnerContent($setOfVectorsToLoopOver, $operatorBasis, $insideEvaluateOperatorLoops('/')), autoIndent=True}" on line 69, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${loopOverVectorsInBasisWithInnerContent($setOfVectorsToLoopOver, $operatorBasis, $insideEvaluateOperatorLoops('/')), autoIndent=True}")) # from line 69, col 3.
+        write(u'''}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideEvaluateOperatorLoops(self, operationString, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideEvaluateOperatorLoops($operationString) at line 74, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"insideEvaluateOperatorLoopsBegin",True) # u'${insideEvaluateOperatorLoopsBegin}' on line 76, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${insideEvaluateOperatorLoopsBegin}')) # from line 76, col 1.
+        # 
+        for operatorComponentNumber, (operatorComponentName, operatorComponentVectors) in enumerate(VFN(VFFSL(SL,"operatorComponents",True),"iteritems",False)()): # generated from line 78, col 3
+            for targetVectorComponents in operatorComponentVectors.itervalues(): # generated from line 79, col 5
+                for targetVectorComponent in targetVectorComponents: # generated from line 80, col 7
+                    write(u'''// ''')
+                    _v = VFFSL(SL,"operatorComponentName",True) # u'${operatorComponentName}' on line 81, col 4
+                    if _v is not None: write(_filter(_v, rawExpr=u'${operatorComponentName}')) # from line 81, col 4.
+                    write(u'''[''')
+                    _v = VFFSL(SL,"targetVectorComponent",True) # u'$targetVectorComponent' on line 81, col 29
+                    if _v is not None: write(_filter(_v, rawExpr=u'$targetVectorComponent')) # from line 81, col 29.
+                    write(u''']
+''')
+                    _v = VFFSL(SL,"targetVectorComponent",True) # u'$targetVectorComponent' on line 82, col 1
+                    if _v is not None: write(_filter(_v, rawExpr=u'$targetVectorComponent')) # from line 82, col 1.
+                    write(u''' ''')
+                    _v = VFFSL(SL,"operationString",True) # u'${operationString}' on line 82, col 24
+                    if _v is not None: write(_filter(_v, rawExpr=u'${operationString}')) # from line 82, col 24.
+                    write(u'''= _''')
+                    _v = VFFSL(SL,"operatorVector.id",True) # u'${operatorVector.id}' on line 82, col 45
+                    if _v is not None: write(_filter(_v, rawExpr=u'${operatorVector.id}')) # from line 82, col 45.
+                    write(u'''[_''')
+                    _v = VFFSL(SL,"operatorVector.id",True) # u'${operatorVector.id}' on line 82, col 67
+                    if _v is not None: write(_filter(_v, rawExpr=u'${operatorVector.id}')) # from line 82, col 67.
+                    write(u'''_index_pointer + ''')
+                    _v = VFFSL(SL,"operatorComponentNumber",True) # u'$operatorComponentNumber' on line 82, col 104
+                    if _v is not None: write(_filter(_v, rawExpr=u'$operatorComponentNumber')) # from line 82, col 104.
+                    if len(VFFSL(SL,"integrator.ipPropagationStepFractions",True)) > 1: # generated from line 83, col 9
+                        write(u''' + _exponentIndex''')
+                    write(u'''];
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # ConstantIPOperator.tmpl
+        # 
+        # Interaction-picture transverse derivative operator
+        # 
+        # Created by Graham Dennis on 2007-10-06.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    calculateOperatorFieldFunctionArguments = []
+
+    _mainCheetahMethod_for_ConstantIPOperator= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(ConstantIPOperator, '_initCheetahAttributes'):
+    templateAPIClass = getattr(ConstantIPOperator, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(ConstantIPOperator)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=ConstantIPOperator()).run()
+
+
diff --git a/xpdeint/Operators/ConstantIPOperator.tmpl b/xpdeint/Operators/ConstantIPOperator.tmpl
new file mode 100644
index 0000000..e3daae4
--- /dev/null
+++ b/xpdeint/Operators/ConstantIPOperator.tmpl
@@ -0,0 +1,91 @@
+@*
+ConstantIPOperator.tmpl
+
+Interaction-picture transverse derivative operator
+
+Created by Graham Dennis on 2007-10-06.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Operators._IPOperator
+
+ at attr $calculateOperatorFieldFunctionArguments = []
+
+ at def calculateOperatorFieldFunctionContents($function)
+  @#
+${integrator.createStepVariable}@slurp
+
+  @super(function)
+  @#
+ at end def
+
+
+ at def insideCalculateOperatorFieldLoops($codeString)
+  @#
+${insideCalculateOperatorFieldLoopsBegin}@slurp
+  @#
+  @# We expect the integrator to have defined '_step'
+  @#
+// ************** Operator code *****************
+${codeString}@slurp
+// **********************************************
+  @# Loop over the propagation step fractions
+  @for $fractionIndex, $propagationStepFraction in enumerate($integrator.ipPropagationStepFractions)
+    
+    @# Loop over each operator component
+    @for $operatorComponentNumber, $operatorComponent in enumerate($operatorComponents.iterkeys())
+      @set $offsetIndex = $operatorComponentNumber + $fractionIndex * len($operatorComponents)
+_${operatorVector.id}[_${operatorVector.id}_index_pointer + ${offsetIndex}] = ${expFunction}(${operatorComponent}${valueSuffix} * $propagationStepFraction * _step);
+    @end for
+  @end for
+  @#
+ at end def
+
+ at def evaluateOperatorLoop($setOfVectorsToLoopOver)
+  @#
+  @# We expect the integrator to have defined _exponent
+  @#
+  @if len($integrator.ipPropagationStepFractions) > 1
+unsigned long _exponentIndex = (abs(_exponent) - 1) * $len($operatorComponents);
+
+  @end if
+if (_exponent > 0) {
+  ${loopOverVectorsInBasisWithInnerContent($setOfVectorsToLoopOver, $operatorBasis, $insideEvaluateOperatorLoops('*')), autoIndent=True}@slurp
+} else {
+  ${loopOverVectorsInBasisWithInnerContent($setOfVectorsToLoopOver, $operatorBasis, $insideEvaluateOperatorLoops('/')), autoIndent=True}@slurp
+}
+  @#
+ at end def
+
+ at def insideEvaluateOperatorLoops($operationString)
+  @#
+${insideEvaluateOperatorLoopsBegin}@slurp
+  @#
+  @for operatorComponentNumber, (operatorComponentName, operatorComponentVectors) in enumerate($operatorComponents.iteritems())
+    @for targetVectorComponents in operatorComponentVectors.itervalues()
+      @for targetVectorComponent in targetVectorComponents
+// ${operatorComponentName}[$targetVectorComponent]
+$targetVectorComponent ${operationString}= _${operatorVector.id}[_${operatorVector.id}_index_pointer + $operatorComponentNumber at slurp
+        @if len($integrator.ipPropagationStepFractions) > 1
+ + _exponentIndex at slurp
+        @end if
+];
+      @end for
+    @end for
+  @end for
+  @#
+ at end def
diff --git a/xpdeint/Operators/CrossPropagationOperator.py b/xpdeint/Operators/CrossPropagationOperator.py
new file mode 100644
index 0000000..8945877
--- /dev/null
+++ b/xpdeint/Operators/CrossPropagationOperator.py
@@ -0,0 +1,221 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Operators._CrossPropagationOperator import _CrossPropagationOperator
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.032316
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Operators/CrossPropagationOperator.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class CrossPropagationOperator(_CrossPropagationOperator):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(CrossPropagationOperator, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Cross propagation operator field $field.name in dimension '${propagationDirection}${propagationDimension}' at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Cross propagation operator field ''')
+        _v = VFFSL(SL,"field.name",True) # u'$field.name' on line 24, col 52
+        if _v is not None: write(_filter(_v, rawExpr=u'$field.name')) # from line 24, col 52.
+        write(u""" in dimension '""")
+        _v = VFFSL(SL,"propagationDirection",True) # u'${propagationDirection}' on line 24, col 78
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDirection}')) # from line 24, col 78.
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 24, col 101
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 24, col 101.
+        write(u"""'""")
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def evaluateOperatorFunctionContents(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def evaluateOperatorFunctionContents($function) at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFN(VFN(VFFSL(SL,"crossPropagationIntegrator",True),"functions",True)['segment'],"call",False)(parentFunction=function) # u"${crossPropagationIntegrator.functions['segment'].call(parentFunction=function)}" on line 28, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${crossPropagationIntegrator.functions['segment'].call(parentFunction=function)}")) # from line 28, col 1.
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # CrossPropagationOperator.tmpl
+        # 
+        # Created by Graham Dennis on 2008-03-01.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_CrossPropagationOperator= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(CrossPropagationOperator, '_initCheetahAttributes'):
+    templateAPIClass = getattr(CrossPropagationOperator, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(CrossPropagationOperator)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=CrossPropagationOperator()).run()
+
+
diff --git a/xpdeint/Operators/CrossPropagationOperator.tmpl b/xpdeint/Operators/CrossPropagationOperator.tmpl
new file mode 100644
index 0000000..6517321
--- /dev/null
+++ b/xpdeint/Operators/CrossPropagationOperator.tmpl
@@ -0,0 +1,31 @@
+@*
+CrossPropagationOperator.tmpl
+
+Created by Graham Dennis on 2008-03-01.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Operators._CrossPropagationOperator
+
+ at def description: Cross propagation operator field $field.name in dimension '${propagationDirection}${propagationDimension}'
+
+ at def evaluateOperatorFunctionContents($function)
+  @#
+${crossPropagationIntegrator.functions['segment'].call(parentFunction=function)}
+  @#
+ at end def
+
diff --git a/xpdeint/Operators/DeltaAOperator.py b/xpdeint/Operators/DeltaAOperator.py
new file mode 100644
index 0000000..11034d6
--- /dev/null
+++ b/xpdeint/Operators/DeltaAOperator.py
@@ -0,0 +1,348 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Operators._DeltaAOperator import _DeltaAOperator
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.087216
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Operators/DeltaAOperator.tmpl'
+__CHEETAH_srcLastModified__ = 'Mon Jul 23 09:42:26 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class DeltaAOperator(_DeltaAOperator):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(DeltaAOperator, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Delta A propagation operator for field $field.name at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Delta A propagation operator for field ''')
+        _v = VFFSL(SL,"field.name",True) # u'$field.name' on line 26, col 58
+        if _v is not None: write(_filter(_v, rawExpr=u'$field.name')) # from line 26, col 58.
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def copyDeltaAFunctionContents(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def copyDeltaAFunctionContents($function) at line 28, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        loopingField = VFFSL(SL,"primaryCodeBlock.field",True)
+        dimensionsWithIndexOverrides = [dim for dim in loopingField.dimensions if not VFN(VFFSL(SL,"deltaAField",True),"hasDimension",False)(dim)]
+        setOfVectorsToLoopOver = set(VFFSL(SL,"deltaAField.vectors",True))
+        setOfVectorsToLoopOver.update(VFFSL(SL,"vectorsForcingReordering",True))
+        indexOverrides = dict([(dim.name, {loopingField: ''.join([u'_',str(VFN(VFN(VFFSL(SL,"dim",True),"inBasis",False)(VFFSL(SL,"operatorBasis",True)),"name",True)),u'_index'])}) for dim in dimensionsWithIndexOverrides])
+        _v = VFFSL(SL,"loopOverFieldInBasisWithVectorsAndInnerContent",False)(loopingField, VFFSL(SL,"operatorBasis",True), VFFSL(SL,"setOfVectorsToLoopOver",True), VFFSL(SL,"insideCopyDeltaALoops",True), VFFSL(SL,"indexOverrides",True)) # u'${loopOverFieldInBasisWithVectorsAndInnerContent(loopingField, $operatorBasis, $setOfVectorsToLoopOver, $insideCopyDeltaALoops, $indexOverrides)}' on line 34, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverFieldInBasisWithVectorsAndInnerContent(loopingField, $operatorBasis, $setOfVectorsToLoopOver, $insideCopyDeltaALoops, $indexOverrides)}')) # from line 34, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideCopyDeltaALoops(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideCopyDeltaALoops at line 38, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''// This code copies the increments for the components back into the vectors themselves.
+''')
+        for vector in VFFSL(SL,"vectorsForcingReordering",True): # generated from line 41, col 3
+            for componentName in VFFSL(SL,"vector.components",True): # generated from line 42, col 5
+                # 
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 44, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 44, col 1.
+                write(u''' = d''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 44, col 21
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 44, col 21.
+                write(u'''_d''')
+                _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 44, col 39
+                if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 44, col 39.
+                write(u''' * _step;
+''')
+                # 
+                if VFN(VFFSL(SL,"deltaAVectorMap",True)[VFFSL(SL,"vector",True)],"needsInitialisation",True): # generated from line 46, col 7
+                    #  If the delta a vector needs initialisation, then we need to
+                    #  reset it now that we have copied what we need out of it.
+                    # 
+                    write(u'''d''')
+                    _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 50, col 2
+                    if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 50, col 2.
+                    write(u'''_d''')
+                    _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 50, col 20
+                    if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 50, col 20.
+                    write(u''' = 0.0;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideEvaluateOperatorLoops(self, codeString, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideEvaluateOperatorLoops($codeString) at line 57, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"insideEvaluateOperatorLoopsBegin",True) # u'${insideEvaluateOperatorLoopsBegin}' on line 59, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${insideEvaluateOperatorLoopsBegin}')) # from line 59, col 1.
+        # 
+        #  The Operator class will have defined for us all of the dVariableName_dPropagationDimension variables.
+        #  Note that we assume that all of the integration vectors have an operotor component defined for them.
+        write(u'''#define d''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 63, col 10
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 63, col 10.
+        write(u''' _step
+
+// ************* Propagation code ***************
+''')
+        _v = VFFSL(SL,"codeString",True) # u'${codeString}' on line 66, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${codeString}')) # from line 66, col 1.
+        write(u'''// **********************************************
+
+#undef d''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 69, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 69, col 9.
+        write(u'''
+
+
+''')
+        #  Loop over the components of the integration vectors
+        for operatorComponentName in VFN(VFFSL(SL,"operatorComponents",True),"iterkeys",False)(): # generated from line 73, col 3
+            assert len(VFFSL(SL,"operatorComponents",True)[VFFSL(SL,"operatorComponentName",True)]) == 1
+            for integrationVector, integrationVectorComponentList in VFN(VFFSL(SL,"operatorComponents",True)[VFFSL(SL,"operatorComponentName",True)],"iteritems",False)(): # generated from line 75, col 5
+                integrationVectorComponentName = VFFSL(SL,"integrationVectorComponentList",True)[0]
+                assert VFFSL(SL,"integrationVectorComponentName",True) in VFFSL(SL,"integrationVector.components",True)
+                write(u'''_active_''')
+                _v = VFFSL(SL,"integrationVector.id",True) # u'${integrationVector.id}' on line 78, col 9
+                if _v is not None: write(_filter(_v, rawExpr=u'${integrationVector.id}')) # from line 78, col 9.
+                write(u'''[_''')
+                _v = VFFSL(SL,"integrationVector.id",True) # u'${integrationVector.id}' on line 78, col 34
+                if _v is not None: write(_filter(_v, rawExpr=u'${integrationVector.id}')) # from line 78, col 34.
+                write(u'''_index_pointer + ''')
+                _v = VFN(VFFSL(SL,"integrationVector.components",True),"index",False)(VFFSL(SL,"integrationVectorComponentName",True)) # u'${integrationVector.components.index($integrationVectorComponentName)}' on line 78, col 74
+                if _v is not None: write(_filter(_v, rawExpr=u'${integrationVector.components.index($integrationVectorComponentName)}')) # from line 78, col 74.
+                write(u'''] = ''')
+                _v = VFFSL(SL,"operatorComponentName",True) # u'$operatorComponentName' on line 79, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'$operatorComponentName')) # from line 79, col 1.
+                write(u''' * _step;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # DeltaAOperator.tmpl
+        # 
+        # delta-a operator, i.e. dstuff_dt = otherStuff;
+        # 
+        # Created by Graham Dennis on 2007-10-13.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_DeltaAOperator= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(DeltaAOperator, '_initCheetahAttributes'):
+    templateAPIClass = getattr(DeltaAOperator, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(DeltaAOperator)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=DeltaAOperator()).run()
+
+
diff --git a/xpdeint/Operators/DeltaAOperator.tmpl b/xpdeint/Operators/DeltaAOperator.tmpl
new file mode 100644
index 0000000..8057680
--- /dev/null
+++ b/xpdeint/Operators/DeltaAOperator.tmpl
@@ -0,0 +1,84 @@
+@*
+DeltaAOperator.tmpl
+
+delta-a operator, i.e. dstuff_dt = otherStuff;
+
+Created by Graham Dennis on 2007-10-13.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Operators._DeltaAOperator
+
+ at def description: Delta A propagation operator for field $field.name
+
+ at def copyDeltaAFunctionContents($function)
+  @set $loopingField = $primaryCodeBlock.field
+  @set $dimensionsWithIndexOverrides = [dim for dim in loopingField.dimensions if not $deltaAField.hasDimension(dim)]
+  @set $setOfVectorsToLoopOver = set($deltaAField.vectors)
+  @silent setOfVectorsToLoopOver.update($vectorsForcingReordering)
+  @set $indexOverrides = dict([(dim.name, {loopingField: c'_${dim.inBasis($operatorBasis).name}_index'}) for dim in dimensionsWithIndexOverrides])
+${loopOverFieldInBasisWithVectorsAndInnerContent(loopingField, $operatorBasis, $setOfVectorsToLoopOver, $insideCopyDeltaALoops, $indexOverrides)}@slurp
+  @#
+ at end def
+
+ at def insideCopyDeltaALoops
+  @#
+// This code copies the increments for the components back into the vectors themselves.
+  @for $vector in $vectorsForcingReordering
+    @for $componentName in $vector.components
+      @#
+${componentName} = d${componentName}_d${propagationDimension} * _step;
+      @#
+      @if $deltaAVectorMap[$vector].needsInitialisation
+        @# If the delta a vector needs initialisation, then we need to
+        @# reset it now that we have copied what we need out of it.
+        @#
+d${componentName}_d${propagationDimension} = 0.0;
+      @end if
+    @end for
+  @end for
+  @#
+ at end def
+
+ at def insideEvaluateOperatorLoops($codeString)
+  @#
+${insideEvaluateOperatorLoopsBegin}@slurp
+  @#
+  @# The Operator class will have defined for us all of the dVariableName_dPropagationDimension variables.
+  @# Note that we assume that all of the integration vectors have an operotor component defined for them.
+#define d${propagationDimension} _step
+
+// ************* Propagation code ***************
+${codeString}@slurp
+// **********************************************
+
+#undef d${propagationDimension}
+
+
+  @# Loop over the components of the integration vectors
+  @for $operatorComponentName in $operatorComponents.iterkeys()
+    @assert len($operatorComponents[$operatorComponentName]) == 1
+    @for $integrationVector, $integrationVectorComponentList in $operatorComponents[$operatorComponentName].iteritems()
+      @set $integrationVectorComponentName = $integrationVectorComponentList[0]
+      @assert $integrationVectorComponentName in $integrationVector.components
+_active_${integrationVector.id}[_${integrationVector.id}_index_pointer + ${integrationVector.components.index($integrationVectorComponentName)}] = @slurp
+$operatorComponentName * _step;
+    @end for
+  @end for
+  @#
+ at end def
+
diff --git a/xpdeint/Operators/FilterOperator.py b/xpdeint/Operators/FilterOperator.py
new file mode 100644
index 0000000..9ac8446
--- /dev/null
+++ b/xpdeint/Operators/FilterOperator.py
@@ -0,0 +1,258 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Operators._FilterOperator import _FilterOperator
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.045506
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Operators/FilterOperator.tmpl'
+__CHEETAH_srcLastModified__ = 'Mon Jul 23 09:42:26 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class FilterOperator(_FilterOperator):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(FilterOperator, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Filter operator at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Filter operator''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideEvaluateOperatorLoops(self, codeString, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideEvaluateOperatorLoops($codeString) at line 28, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"insideEvaluateOperatorLoopsBegin",True) # u'${insideEvaluateOperatorLoopsBegin}' on line 30, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${insideEvaluateOperatorLoopsBegin}')) # from line 30, col 1.
+        # 
+        write(u'''// ************** Filter code *****************
+''')
+        _v = VFFSL(SL,"codeString",True) # u'${codeString}' on line 33, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${codeString}')) # from line 33, col 1.
+        write(u'''// **********************************************
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def evaluateOperatorFunctionContents(self, function, **KWS):
+
+
+        """
+        This function overrides the Operator implementation of this to ensure that
+          all required computed vectors are evaluated at the start of the filter.
+        """
+
+        ## CHEETAH: generated from @def evaluateOperatorFunctionContents($function) at line 39, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"evaluateComputedVectors",False)(VFFSL(SL,"dependencies",True)) # u'${evaluateComputedVectors($dependencies)}' on line 45, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${evaluateComputedVectors($dependencies)}')) # from line 45, col 1.
+        # 
+        _v = super(FilterOperator, self).evaluateOperatorFunctionContents(function)
+        if _v is not None: write(_filter(_v))
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # FilterOperator.tmpl
+        # 
+        # Filter (moment) operator
+        # 
+        # Created by Graham Dennis on 2007-10-21.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_FilterOperator= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(FilterOperator, '_initCheetahAttributes'):
+    templateAPIClass = getattr(FilterOperator, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(FilterOperator)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=FilterOperator()).run()
+
+
diff --git a/xpdeint/Operators/FilterOperator.tmpl b/xpdeint/Operators/FilterOperator.tmpl
new file mode 100644
index 0000000..e604d77
--- /dev/null
+++ b/xpdeint/Operators/FilterOperator.tmpl
@@ -0,0 +1,49 @@
+@*
+FilterOperator.tmpl
+
+Filter (moment) operator
+
+Created by Graham Dennis on 2007-10-21.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Operators._FilterOperator
+
+ at def description: Filter operator
+
+ at def insideEvaluateOperatorLoops($codeString)
+  @#
+${insideEvaluateOperatorLoopsBegin}@slurp
+  @#
+// ************** Filter code *****************
+${codeString}@slurp
+// **********************************************
+  @#
+ at end def
+
+
+ at def evaluateOperatorFunctionContents($function)
+@*doc:
+  This function overrides the Operator implementation of this to ensure that
+  all required computed vectors are evaluated at the start of the filter.
+*@
+  @#
+${evaluateComputedVectors($dependencies)}@slurp
+  @#
+  @super(function)
+  @#
+ at end def
diff --git a/xpdeint/Operators/FunctionsOperator.py b/xpdeint/Operators/FunctionsOperator.py
new file mode 100644
index 0000000..a6aa868
--- /dev/null
+++ b/xpdeint/Operators/FunctionsOperator.py
@@ -0,0 +1,216 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Operators.Operator import Operator
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.0794
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Operators/FunctionsOperator.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class FunctionsOperator(Operator):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(FunctionsOperator, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Functions operator at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Functions operator''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def evaluateOperatorFunctionContents(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def evaluateOperatorFunctionContents($function) at line 28, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''// ************* Functions code *****************
+''')
+        _v = VFFSL(SL,"primaryCodeBlock.codeString",True) # u'${primaryCodeBlock.codeString}' on line 31, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${primaryCodeBlock.codeString}')) # from line 31, col 1.
+        write(u'''// **********************************************
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # FunctionsOperator.tmpl
+        # 
+        # Functions (raw code) operator
+        # 
+        # Created by Graham Dennis on 2008-03-13.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_FunctionsOperator= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(FunctionsOperator, '_initCheetahAttributes'):
+    templateAPIClass = getattr(FunctionsOperator, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(FunctionsOperator)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=FunctionsOperator()).run()
+
+
diff --git a/xpdeint/Operators/FunctionsOperator.tmpl b/xpdeint/Operators/FunctionsOperator.tmpl
new file mode 100644
index 0000000..750e776
--- /dev/null
+++ b/xpdeint/Operators/FunctionsOperator.tmpl
@@ -0,0 +1,34 @@
+@*
+FunctionsOperator.tmpl
+
+Functions (raw code) operator
+
+Created by Graham Dennis on 2008-03-13.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Operators.Operator
+
+ at def description: Functions operator
+
+ at def evaluateOperatorFunctionContents($function)
+  @#
+// ************* Functions code *****************
+${primaryCodeBlock.codeString}@slurp
+// **********************************************
+  @#
+ at end def
diff --git a/xpdeint/Operators/NonConstantEXOperator.py b/xpdeint/Operators/NonConstantEXOperator.py
new file mode 100644
index 0000000..5502e46
--- /dev/null
+++ b/xpdeint/Operators/NonConstantEXOperator.py
@@ -0,0 +1,289 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Operators._EXOperator import _EXOperator
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.064009
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Operators/NonConstantEXOperator.tmpl'
+__CHEETAH_srcLastModified__ = 'Mon Jul 23 09:43:31 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class NonConstantEXOperator(_EXOperator):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(NonConstantEXOperator, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: EX transverse derivative operator for field $field.name (not constant) at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''EX transverse derivative operator for field ''')
+        _v = VFFSL(SL,"field.name",True) # u'$field.name' on line 26, col 63
+        if _v is not None: write(_filter(_v, rawExpr=u'$field.name')) # from line 26, col 63.
+        write(u''' (not constant)''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideEvaluateOperatorLoops(self, codeString, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideEvaluateOperatorLoops($codeString) at line 29, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"insideEvaluateOperatorLoopsBegin",True) # u'${insideEvaluateOperatorLoopsBegin}' on line 31, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${insideEvaluateOperatorLoopsBegin}')) # from line 31, col 1.
+        # 
+        #  NonConstantOperator will have defined for us all of the operatorName variables.
+        #  Note that we assume that all of the integration vectors have an operotor component defined for them.
+        write(u'''
+// ************** Operator code *****************
+''')
+        _v = VFFSL(SL,"codeString",True) # u'${codeString}' on line 37, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${codeString}')) # from line 37, col 1.
+        write(u'''// **********************************************
+
+''')
+        for operatorComponentNumber, (operatorComponentName, operatorComponentVectors) in enumerate(VFN(VFFSL(SL,"operatorComponents",True),"iteritems",False)()): # generated from line 40, col 3
+            for targetVectorComponents in operatorComponentVectors.itervalues(): # generated from line 41, col 5
+                for targetVectorComponent in targetVectorComponents: # generated from line 42, col 7
+                    write(u'''// ''')
+                    _v = VFFSL(SL,"operatorComponentName",True) # u'${operatorComponentName}' on line 43, col 4
+                    if _v is not None: write(_filter(_v, rawExpr=u'${operatorComponentName}')) # from line 43, col 4.
+                    write(u'''[''')
+                    _v = VFFSL(SL,"targetVectorComponent",True) # u'$targetVectorComponent' on line 43, col 29
+                    if _v is not None: write(_filter(_v, rawExpr=u'$targetVectorComponent')) # from line 43, col 29.
+                    write(u''']
+_''')
+                    _v = VFFSL(SL,"operatorComponentName",True) # u'${operatorComponentName}' on line 44, col 2
+                    if _v is not None: write(_filter(_v, rawExpr=u'${operatorComponentName}')) # from line 44, col 2.
+                    write(u'''_''')
+                    _v = VFFSL(SL,"targetVectorComponent",True) # u'${targetVectorComponent}' on line 44, col 27
+                    if _v is not None: write(_filter(_v, rawExpr=u'${targetVectorComponent}')) # from line 44, col 27.
+                    write(u''' = ''')
+                    _v = VFFSL(SL,"operatorComponentName",True) # u'$operatorComponentName' on line 44, col 54
+                    if _v is not None: write(_filter(_v, rawExpr=u'$operatorComponentName')) # from line 44, col 54.
+                    write(u''' * ''')
+                    _v = VFFSL(SL,"targetVectorComponent",True) # u'$targetVectorComponent' on line 44, col 79
+                    if _v is not None: write(_filter(_v, rawExpr=u'$targetVectorComponent')) # from line 44, col 79.
+                    write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def callEvaluateLoop(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def callEvaluateLoop at line 51, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"optimisedOperatorCopyBegin",True) # u'${optimisedOperatorCopyBegin}' on line 53, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${optimisedOperatorCopyBegin}')) # from line 53, col 1.
+        # 
+        _v = super(NonConstantEXOperator, self).callEvaluateLoop()
+        if _v is not None: write(_filter(_v))
+        # 
+        _v = VFFSL(SL,"optimisedOperatorCopyEnd",True) # u'${optimisedOperatorCopyEnd}' on line 57, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${optimisedOperatorCopyEnd}')) # from line 57, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # NonConstantEXOperator.tmpl
+        # 
+        # Explicit-picture transverse derivative operator
+        # 
+        # Created by Graham Dennis on 2007-10-20.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    operatorKind = _EXOperator.OtherOperatorKind
+
+    _mainCheetahMethod_for_NonConstantEXOperator= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(NonConstantEXOperator, '_initCheetahAttributes'):
+    templateAPIClass = getattr(NonConstantEXOperator, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(NonConstantEXOperator)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=NonConstantEXOperator()).run()
+
+
diff --git a/xpdeint/Operators/NonConstantEXOperator.tmpl b/xpdeint/Operators/NonConstantEXOperator.tmpl
new file mode 100644
index 0000000..6e7f8df
--- /dev/null
+++ b/xpdeint/Operators/NonConstantEXOperator.tmpl
@@ -0,0 +1,59 @@
+@*
+NonConstantEXOperator.tmpl
+
+Explicit-picture transverse derivative operator
+
+Created by Graham Dennis on 2007-10-20.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Operators._EXOperator
+
+ at def description: EX transverse derivative operator for field $field.name (not constant)
+ at attr $operatorKind = _EXOperator.OtherOperatorKind
+
+ at def insideEvaluateOperatorLoops($codeString)
+  @#
+${insideEvaluateOperatorLoopsBegin}@slurp
+  @#
+  @# NonConstantOperator will have defined for us all of the operatorName variables.
+  @# Note that we assume that all of the integration vectors have an operotor component defined for them.
+
+// ************** Operator code *****************
+${codeString}@slurp
+// **********************************************
+
+  @for operatorComponentNumber, (operatorComponentName, operatorComponentVectors) in enumerate($operatorComponents.iteritems())
+    @for targetVectorComponents in operatorComponentVectors.itervalues()
+      @for targetVectorComponent in targetVectorComponents
+// ${operatorComponentName}[$targetVectorComponent]
+_${operatorComponentName}_${targetVectorComponent} = $operatorComponentName * $targetVectorComponent;
+      @end for
+    @end for
+  @end for
+  @#
+ at end def
+
+ at def callEvaluateLoop
+  @#
+${optimisedOperatorCopyBegin}@slurp
+  @#
+  @super
+  @#
+${optimisedOperatorCopyEnd}@slurp
+  @#
+ at end def
\ No newline at end of file
diff --git a/xpdeint/Operators/NonConstantIPOperator.py b/xpdeint/Operators/NonConstantIPOperator.py
new file mode 100644
index 0000000..b9b866d
--- /dev/null
+++ b/xpdeint/Operators/NonConstantIPOperator.py
@@ -0,0 +1,471 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Operators._IPOperator import _IPOperator
+from xpdeint.CallOnceGuards import callOncePerInstanceGuard
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.166526
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Operators/NonConstantIPOperator.tmpl'
+__CHEETAH_srcLastModified__ = 'Mon Jul 23 09:42:26 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class NonConstantIPOperator(_IPOperator):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(NonConstantIPOperator, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def globals at line 30, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(NonConstantIPOperator, self).globals()
+        if _v is not None: write(_filter(_v))
+        # 
+        if len(VFFSL(SL,"integrator.ipPropagationStepFractions",True)) > 1: # generated from line 34, col 3
+            write(u'''int _''')
+            _v = VFFSL(SL,"id",True) # u'${id}' on line 35, col 6
+            if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 35, col 6.
+            write(u'''_exponent_offset_map[''')
+            _v = VFFSL(SL,"len",False)(VFFSL(SL,"integrator.ipPropagationStepFractions",True)) # u'${len($integrator.ipPropagationStepFractions)}' on line 35, col 32
+            if _v is not None: write(_filter(_v, rawExpr=u'${len($integrator.ipPropagationStepFractions)}')) # from line 35, col 32.
+            write(u'''];
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOncePerInstanceGuard
+    def initialise(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def initialise at line 41, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        if len(VFFSL(SL,"integrator.ipPropagationStepFractions",True)) > 1: # generated from line 43, col 3
+            write(u'''memset(_''')
+            _v = VFFSL(SL,"id",True) # u'${id}' on line 44, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 44, col 9.
+            write(u'''_exponent_offset_map, 0, sizeof(_''')
+            _v = VFFSL(SL,"id",True) # u'${id}' on line 44, col 47
+            if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 44, col 47.
+            write(u'''_exponent_offset_map));
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def calculateOperatorFieldFunctionContents(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def calculateOperatorFieldFunctionContents($function) at line 49, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        if len(VFFSL(SL,"integrator.ipPropagationStepFractions",True)) > 1: # generated from line 51, col 3
+            write(u'''static const real _propagationStepFractions[] = {
+''')
+            for propagationStepFraction in VFFSL(SL,"integrator.ipPropagationStepFractions",True): # generated from line 53, col 3
+                write(u'''  ''')
+                _v = VFFSL(SL,"propagationStepFraction",True) # u'$propagationStepFraction' on line 54, col 3
+                if _v is not None: write(_filter(_v, rawExpr=u'$propagationStepFraction')) # from line 54, col 3.
+                write(u''',
+''')
+            write(u'''};
+const real _propagationStepFraction = _propagationStepFractions[abs(_exponent) - 1];
+_''')
+            _v = VFFSL(SL,"id",True) # u'${id}' on line 58, col 2
+            if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 58, col 2.
+            write(u'''_exponent_offset_map[abs(_exponent) - 1] = _arrayIndex;
+''')
+        else: # generated from line 59, col 3
+            write(u'''const real _propagationStepFraction = ''')
+            _v = VFN(VFFSL(SL,"integrator",True),"ipPropagationStepFractions",True)[0] # u'${integrator.ipPropagationStepFractions[0]}' on line 60, col 39
+            if _v is not None: write(_filter(_v, rawExpr=u'${integrator.ipPropagationStepFractions[0]}')) # from line 60, col 39.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = super(NonConstantIPOperator, self).calculateOperatorFieldFunctionContents(function)
+        if _v is not None: write(_filter(_v))
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideCalculateOperatorFieldLoops(self, codeString, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideCalculateOperatorFieldLoops($codeString) at line 67, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"insideCalculateOperatorFieldLoopsBegin",True) # u'${insideCalculateOperatorFieldLoopsBegin}' on line 69, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${insideCalculateOperatorFieldLoopsBegin}')) # from line 69, col 1.
+        # 
+        #  We expect the integrator to have defined '_step'
+        # 
+        write(u'''// ************** Operator code *****************
+''')
+        _v = VFFSL(SL,"codeString",True) # u'${codeString}' on line 74, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${codeString}')) # from line 74, col 1.
+        write(u'''// **********************************************
+
+''')
+        #  Loop over each operator component
+        for operatorComponentNumber, operatorComponent in enumerate(VFN(VFFSL(SL,"operatorComponents",True),"iterkeys",False)()): # generated from line 78, col 3
+            write(u'''_''')
+            _v = VFFSL(SL,"operatorVector.id",True) # u'${operatorVector.id}' on line 79, col 2
+            if _v is not None: write(_filter(_v, rawExpr=u'${operatorVector.id}')) # from line 79, col 2.
+            write(u'''[_''')
+            _v = VFFSL(SL,"operatorVector.id",True) # u'${operatorVector.id}' on line 79, col 24
+            if _v is not None: write(_filter(_v, rawExpr=u'${operatorVector.id}')) # from line 79, col 24.
+            write(u'''_index_pointer + _arrayIndex * ''')
+            _v = VFFSL(SL,"len",False)(VFFSL(SL,"operatorComponents",True)) # u'$len($operatorComponents)' on line 79, col 75
+            if _v is not None: write(_filter(_v, rawExpr=u'$len($operatorComponents)')) # from line 79, col 75.
+            write(u''' + ''')
+            _v = VFFSL(SL,"operatorComponentNumber",True) # u'${operatorComponentNumber}' on line 79, col 103
+            if _v is not None: write(_filter(_v, rawExpr=u'${operatorComponentNumber}')) # from line 79, col 103.
+            write(u''']''')
+            write(u''' = ''')
+            _v = VFFSL(SL,"expFunction",True) # u'${expFunction}' on line 80, col 4
+            if _v is not None: write(_filter(_v, rawExpr=u'${expFunction}')) # from line 80, col 4.
+            write(u'''(''')
+            _v = VFFSL(SL,"operatorComponent",True) # u'${operatorComponent}' on line 80, col 19
+            if _v is not None: write(_filter(_v, rawExpr=u'${operatorComponent}')) # from line 80, col 19.
+            _v = VFFSL(SL,"valueSuffix",True) # u'${valueSuffix}' on line 80, col 39
+            if _v is not None: write(_filter(_v, rawExpr=u'${valueSuffix}')) # from line 80, col 39.
+            write(u''' * _propagationStepFraction * _step);
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def evaluateOperatorLoop(self, setOfVectorsToLoopOver, **KWS):
+
+
+
+        ## CHEETAH: generated from @def evaluateOperatorLoop($setOfVectorsToLoopOver) at line 85, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  We expect the integrator to have defined _exponent
+        # 
+        if len(VFFSL(SL,"integrator.ipPropagationStepFractions",True)) > 1: # generated from line 89, col 3
+            write(u'''unsigned long _exponentIndex = _''')
+            _v = VFFSL(SL,"id",True) # u'${id}' on line 90, col 33
+            if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 90, col 33.
+            write(u'''_exponent_offset_map[abs(_exponent) - 1] * ''')
+            _v = VFFSL(SL,"len",False)(VFFSL(SL,"operatorComponents",True)) # u'$len($operatorComponents)' on line 90, col 81
+            if _v is not None: write(_filter(_v, rawExpr=u'$len($operatorComponents)')) # from line 90, col 81.
+            write(u''';
+
+''')
+        write(u'''if (_exponent > 0) {
+  ''')
+        _v = VFFSL(SL,"loopOverVectorsInBasisWithInnerContent",False)(VFFSL(SL,"setOfVectorsToLoopOver",True), VFFSL(SL,"operatorBasis",True), VFFSL(SL,"insideEvaluateOperatorLoops",False)('*')) # u"${loopOverVectorsInBasisWithInnerContent($setOfVectorsToLoopOver, $operatorBasis, $insideEvaluateOperatorLoops('*')), autoIndent=True}" on line 94, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${loopOverVectorsInBasisWithInnerContent($setOfVectorsToLoopOver, $operatorBasis, $insideEvaluateOperatorLoops('*')), autoIndent=True}")) # from line 94, col 3.
+        write(u'''} else {
+  ''')
+        _v = VFFSL(SL,"loopOverVectorsInBasisWithInnerContent",False)(VFFSL(SL,"setOfVectorsToLoopOver",True), VFFSL(SL,"operatorBasis",True), VFFSL(SL,"insideEvaluateOperatorLoops",False)('/')) # u"${loopOverVectorsInBasisWithInnerContent($setOfVectorsToLoopOver, $operatorBasis, $insideEvaluateOperatorLoops('/')), autoIndent=True}" on line 96, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${loopOverVectorsInBasisWithInnerContent($setOfVectorsToLoopOver, $operatorBasis, $insideEvaluateOperatorLoops('/')), autoIndent=True}")) # from line 96, col 3.
+        write(u'''}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideEvaluateOperatorLoops(self, operationString, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideEvaluateOperatorLoops($operationString) at line 101, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"insideEvaluateOperatorLoopsBegin",True) # u'${insideEvaluateOperatorLoopsBegin}' on line 103, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${insideEvaluateOperatorLoopsBegin}')) # from line 103, col 1.
+        # 
+        for operatorComponentNumber, (operatorComponentName, operatorComponentVectors) in enumerate(VFN(VFFSL(SL,"operatorComponents",True),"iteritems",False)()): # generated from line 105, col 3
+            for targetVectorComponents in operatorComponentVectors.itervalues(): # generated from line 106, col 5
+                for targetVectorComponent in targetVectorComponents: # generated from line 107, col 7
+                    write(u'''// ''')
+                    _v = VFFSL(SL,"operatorComponentName",True) # u'${operatorComponentName}' on line 108, col 4
+                    if _v is not None: write(_filter(_v, rawExpr=u'${operatorComponentName}')) # from line 108, col 4.
+                    write(u'''[''')
+                    _v = VFFSL(SL,"targetVectorComponent",True) # u'$targetVectorComponent' on line 108, col 29
+                    if _v is not None: write(_filter(_v, rawExpr=u'$targetVectorComponent')) # from line 108, col 29.
+                    write(u''']
+''')
+                    _v = VFFSL(SL,"targetVectorComponent",True) # u'$targetVectorComponent' on line 109, col 1
+                    if _v is not None: write(_filter(_v, rawExpr=u'$targetVectorComponent')) # from line 109, col 1.
+                    write(u''' ''')
+                    _v = VFFSL(SL,"operationString",True) # u'${operationString}' on line 109, col 24
+                    if _v is not None: write(_filter(_v, rawExpr=u'${operationString}')) # from line 109, col 24.
+                    write(u'''= _''')
+                    _v = VFFSL(SL,"operatorVector.id",True) # u'${operatorVector.id}' on line 109, col 45
+                    if _v is not None: write(_filter(_v, rawExpr=u'${operatorVector.id}')) # from line 109, col 45.
+                    write(u'''[_''')
+                    _v = VFFSL(SL,"operatorVector.id",True) # u'${operatorVector.id}' on line 109, col 67
+                    if _v is not None: write(_filter(_v, rawExpr=u'${operatorVector.id}')) # from line 109, col 67.
+                    write(u'''_index_pointer + ''')
+                    _v = VFFSL(SL,"operatorComponentNumber",True) # u'$operatorComponentNumber' on line 109, col 104
+                    if _v is not None: write(_filter(_v, rawExpr=u'$operatorComponentNumber')) # from line 109, col 104.
+                    if len(VFFSL(SL,"integrator.ipPropagationStepFractions",True)) > 1: # generated from line 110, col 9
+                        write(u''' + _exponentIndex''')
+                    write(u'''];
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # NonConstantIPOperator.tmpl
+        # 
+        # Interaction-picture transverse derivative operator
+        # 
+        # Created by Graham Dennis on 2007-11-21.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    calculateOperatorFieldFunctionArguments = [('real', '_step'), ('int', '_exponent'), ('int', '_arrayIndex')]
+
+    _mainCheetahMethod_for_NonConstantIPOperator= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(NonConstantIPOperator, '_initCheetahAttributes'):
+    templateAPIClass = getattr(NonConstantIPOperator, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(NonConstantIPOperator)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=NonConstantIPOperator()).run()
+
+
diff --git a/xpdeint/Operators/NonConstantIPOperator.tmpl b/xpdeint/Operators/NonConstantIPOperator.tmpl
new file mode 100644
index 0000000..d74b097
--- /dev/null
+++ b/xpdeint/Operators/NonConstantIPOperator.tmpl
@@ -0,0 +1,118 @@
+@*
+NonConstantIPOperator.tmpl
+
+Interaction-picture transverse derivative operator
+
+Created by Graham Dennis on 2007-11-21.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Operators._IPOperator
+
+ at from xpdeint.CallOnceGuards import callOncePerInstanceGuard
+
+ at attr $calculateOperatorFieldFunctionArguments = [('real', '_step'), ('int', '_exponent'), ('int', '_arrayIndex')]
+
+ at def globals
+  @#
+  @super
+  @#
+  @if len($integrator.ipPropagationStepFractions) > 1
+int _${id}_exponent_offset_map[${len($integrator.ipPropagationStepFractions)}];
+  @end if
+  @#
+ at end def
+
+@@callOncePerInstanceGuard
+ at def initialise
+  @#
+  @if len($integrator.ipPropagationStepFractions) > 1
+memset(_${id}_exponent_offset_map, 0, sizeof(_${id}_exponent_offset_map));
+  @end if
+  @#
+ at end def
+
+ at def calculateOperatorFieldFunctionContents($function)
+  @#
+  @if len($integrator.ipPropagationStepFractions) > 1
+static const real _propagationStepFractions[] = {
+  @for $propagationStepFraction in $integrator.ipPropagationStepFractions
+  $propagationStepFraction,
+  @end for
+};
+const real _propagationStepFraction = _propagationStepFractions[abs(_exponent) - 1];
+_${id}_exponent_offset_map[abs(_exponent) - 1] = _arrayIndex;
+  @else
+const real _propagationStepFraction = ${integrator.ipPropagationStepFractions[0]};
+  @end if
+
+  @super(function)
+  @#
+ at end def
+
+ at def insideCalculateOperatorFieldLoops($codeString)
+  @#
+${insideCalculateOperatorFieldLoopsBegin}@slurp
+  @#
+  @# We expect the integrator to have defined '_step'
+  @#
+// ************** Operator code *****************
+${codeString}@slurp
+// **********************************************
+
+  @# Loop over each operator component
+  @for $operatorComponentNumber, $operatorComponent in enumerate($operatorComponents.iterkeys())
+_${operatorVector.id}[_${operatorVector.id}_index_pointer + _arrayIndex * $len($operatorComponents) + ${operatorComponentNumber}]@slurp
+ = ${expFunction}(${operatorComponent}${valueSuffix} * _propagationStepFraction * _step);
+  @end for
+  @#
+ at end def
+
+ at def evaluateOperatorLoop($setOfVectorsToLoopOver)
+  @#
+  @# We expect the integrator to have defined _exponent
+  @#
+  @if len($integrator.ipPropagationStepFractions) > 1
+unsigned long _exponentIndex = _${id}_exponent_offset_map[abs(_exponent) - 1] * $len($operatorComponents);
+
+  @end if
+if (_exponent > 0) {
+  ${loopOverVectorsInBasisWithInnerContent($setOfVectorsToLoopOver, $operatorBasis, $insideEvaluateOperatorLoops('*')), autoIndent=True}@slurp
+} else {
+  ${loopOverVectorsInBasisWithInnerContent($setOfVectorsToLoopOver, $operatorBasis, $insideEvaluateOperatorLoops('/')), autoIndent=True}@slurp
+}
+  @#
+ at end def
+
+ at def insideEvaluateOperatorLoops($operationString)
+  @#
+${insideEvaluateOperatorLoopsBegin}@slurp
+  @#
+  @for operatorComponentNumber, (operatorComponentName, operatorComponentVectors) in enumerate($operatorComponents.iteritems())
+    @for targetVectorComponents in operatorComponentVectors.itervalues()
+      @for targetVectorComponent in targetVectorComponents
+// ${operatorComponentName}[$targetVectorComponent]
+$targetVectorComponent ${operationString}= _${operatorVector.id}[_${operatorVector.id}_index_pointer + $operatorComponentNumber at slurp
+        @if len($integrator.ipPropagationStepFractions) > 1
+ + _exponentIndex at slurp
+        @end if
+];
+      @end for
+    @end for
+  @end for
+  @#
+ at end def
diff --git a/xpdeint/Operators/Operator.py b/xpdeint/Operators/Operator.py
new file mode 100644
index 0000000..fe93f49
--- /dev/null
+++ b/xpdeint/Operators/Operator.py
@@ -0,0 +1,622 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Operators._Operator import _Operator
+from xpdeint.Vectors.VectorElement import VectorElement
+from xpdeint.CallOnceGuards import callOncePerInstanceGuard
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.183177
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Operators/Operator.tmpl'
+__CHEETAH_srcLastModified__ = 'Tue Nov 20 11:51:47 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class Operator(_Operator):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(Operator, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def insideEvaluateOperatorLoops(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideEvaluateOperatorLoops at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  Content must be provided by a subclass
+        assert 0
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOncePerInstanceGuard
+    def initialise(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def initialise at line 35, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(Operator, self).initialise()
+        if _v is not None: write(_filter(_v))
+        # 
+        if VFFSL(SL,"operatorVector",True): # generated from line 39, col 3
+            write(u'''_''')
+            _v = VFFSL(SL,"parent.id",True) # u'${parent.id}' on line 40, col 2
+            if _v is not None: write(_filter(_v, rawExpr=u'${parent.id}')) # from line 40, col 2.
+            write(u'''_calculate_''')
+            _v = VFFSL(SL,"name",True) # u'${name}' on line 40, col 25
+            if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 40, col 25.
+            write(u'''_field();
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def calculateOperatorFieldFunctionContents(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def calculateOperatorFieldFunctionContents($function) at line 45, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFN(VFFSL(SL,"codeBlocks",True)['operatorDefinition'],"loop",False)(self.insideCalculateOperatorFieldLoops) # u"${codeBlocks['operatorDefinition'].loop(self.insideCalculateOperatorFieldLoops)}" on line 47, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${codeBlocks['operatorDefinition'].loop(self.insideCalculateOperatorFieldLoops)}")) # from line 47, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideCalculateOperatorFieldLoopsBegin(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideCalculateOperatorFieldLoopsBegin at line 51, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        for operatorComponentName in VFN(VFFSL(SL,"operatorComponents",True),"iterkeys",False)(): # generated from line 53, col 3
+            if VFFSL(SL,"operatorVector",True) and operatorComponentName in VFFSL(SL,"operatorVector.components",True): # generated from line 54, col 5
+                continue
+            _v = VFFSL(SL,"operatorVector.type",True) # u'${operatorVector.type}' on line 57, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${operatorVector.type}')) # from line 57, col 1.
+            write(u''' ''')
+            _v = VFFSL(SL,"operatorComponentName",True) # u'$operatorComponentName' on line 57, col 24
+            if _v is not None: write(_filter(_v, rawExpr=u'$operatorComponentName')) # from line 57, col 24.
+            write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def evaluateOperatorFunctionContents(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def evaluateOperatorFunctionContents($function) at line 64, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        if not 'calculateOperatorField' in VFFSL(SL,"functions",True): # generated from line 66, col 3
+            _v = VFFSL(SL,"evaluateOperatorFunctionContentsWithCodeBlock",False)(function) # u'${evaluateOperatorFunctionContentsWithCodeBlock(function)}' on line 67, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${evaluateOperatorFunctionContentsWithCodeBlock(function)}')) # from line 67, col 1.
+        else: # generated from line 68, col 3
+            _v = VFFSL(SL,"evaluateOperatorFunctionContentsWithoutCodeBlock",False)(function) # u'${evaluateOperatorFunctionContentsWithoutCodeBlock(function)}' on line 69, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${evaluateOperatorFunctionContentsWithoutCodeBlock(function)}')) # from line 69, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def evaluateOperatorFunctionContentsWithCodeBlock(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def evaluateOperatorFunctionContentsWithCodeBlock($function) at line 74, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"callEvaluateLoop",True) # u'${callEvaluateLoop}' on line 76, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${callEvaluateLoop}')) # from line 76, col 1.
+        # 
+        if VFFSL(SL,"resultVector",True) and VFFSL(SL,"resultVector.needsTransforms",True): # generated from line 78, col 3
+            write(u'''
+_''')
+            _v = VFFSL(SL,"resultVector.id",True) # u'${resultVector.id}' on line 80, col 2
+            if _v is not None: write(_filter(_v, rawExpr=u'${resultVector.id}')) # from line 80, col 2.
+            write(u'''_basis = ''')
+            _v = VFFSL(SL,"basisIndexForBasis",False)(VFFSL(SL,"operatorBasis",True)) # u'$basisIndexForBasis($operatorBasis)' on line 80, col 29
+            if _v is not None: write(_filter(_v, rawExpr=u'$basisIndexForBasis($operatorBasis)')) # from line 80, col 29.
+            write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def callEvaluateLoop(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def callEvaluateLoop at line 85, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        _v = VFN(VFFSL(SL,"codeBlocks",True)['operatorDefinition'],"loop",False)(self.insideEvaluateOperatorLoops) # u"${codeBlocks['operatorDefinition'].loop(self.insideEvaluateOperatorLoops)}" on line 86, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${codeBlocks['operatorDefinition'].loop(self.insideEvaluateOperatorLoops)}")) # from line 86, col 1.
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideEvaluateOperatorLoopsBegin(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideEvaluateOperatorLoopsBegin at line 89, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        if not VFFSL(SL,"operatorVector",True): # generated from line 91, col 3
+            #  If we don't have an operator vector, then we need to create
+            #  the component variables so that the user can set them inside
+            #  the loop
+            for operatorComponentName, operatorComponentDictionary in VFN(VFFSL(SL,"operatorComponents",True),"iteritems",False)(): # generated from line 95, col 5
+                typeNamesSet = set([vector.type for vector in operatorComponentDictionary.iterkeys()])
+                typeName = 'real'
+                if 'complex' in typeNamesSet: # generated from line 98, col 7
+                    typeName = 'complex'
+                _v = VFFSL(SL,"typeName",True) # u'${typeName}' on line 101, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${typeName}')) # from line 101, col 1.
+                write(u''' ''')
+                _v = VFFSL(SL,"operatorComponentName",True) # u'${operatorComponentName}' on line 101, col 13
+                if _v is not None: write(_filter(_v, rawExpr=u'${operatorComponentName}')) # from line 101, col 13.
+                write(u''';
+''')
+            write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def evaluateOperatorFunctionContentsWithoutCodeBlock(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def evaluateOperatorFunctionContentsWithoutCodeBlock($function) at line 108, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  We need to loop over all of the vectors to which we are applying our operators.
+        # 
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"targetVectors",True), VFFSL(SL,"operatorBasis",True)) # u'${transformVectorsToBasis($targetVectors, $operatorBasis)}' on line 112, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($targetVectors, $operatorBasis)}')) # from line 112, col 1.
+        # 
+        write(u'''
+''')
+        #  We have an operator vector and we will need to loop over it
+        setOfVectorsToLoopOver = VFN(VFFSL(SL,"targetVectors",True),"copy",False)()
+        VFN(VFFSL(SL,"setOfVectorsToLoopOver",True),"add",False)(VFFSL(SL,"operatorVector",True))
+        if VFFSL(SL,"resultVector",True): # generated from line 118, col 3
+            VFN(VFFSL(SL,"setOfVectorsToLoopOver",True),"add",False)(VFFSL(SL,"resultVector",True))
+        # 
+        _v = VFFSL(SL,"evaluateOperatorLoop",False)(setOfVectorsToLoopOver) # u'${evaluateOperatorLoop(setOfVectorsToLoopOver)}' on line 122, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${evaluateOperatorLoop(setOfVectorsToLoopOver)}')) # from line 122, col 1.
+        # 
+        if VFFSL(SL,"resultVector",True) and VFFSL(SL,"resultVector.needsTransforms",True): # generated from line 124, col 3
+            write(u'''
+_''')
+            _v = VFFSL(SL,"resultVector.id",True) # u'${resultVector.id}' on line 126, col 2
+            if _v is not None: write(_filter(_v, rawExpr=u'${resultVector.id}')) # from line 126, col 2.
+            write(u'''_basis = ''')
+            _v = VFFSL(SL,"basisIndexForBasis",False)(VFFSL(SL,"operatorBasis",True)) # u'$basisIndexForBasis($operatorBasis)' on line 126, col 29
+            if _v is not None: write(_filter(_v, rawExpr=u'$basisIndexForBasis($operatorBasis)')) # from line 126, col 29.
+            write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def optimisedOperatorCopyBegin(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def optimisedOperatorCopyBegin at line 131, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        #  This optimisation only works in a restricted set of circumstances.  It's common enough, but not as general
+        #  as it could be.  Basically, you need a single operator name (e.g. L, not Lx and Ly) which is applied to all
+        #  components of a vector.
+        if len(VFFSL(SL,"targetVectors",True)) != 1 or not VFFSL(SL,"resultVector",True) or len(VFFSL(SL,"operatorNames",True)) != 1: # generated from line 135, col 3
+            return
+        targetVector = VFFSL(SL,"anyObject",False)(VFFSL(SL,"targetVectors",True))
+        if VFFSL(SL,"targetVector.nComponents",True) != VFFSL(SL,"resultVector.nComponents",True) or not targetVector.needsTransforms: # generated from line 139, col 3
+            return
+        #  For this operator, we don't modify the target vector, so if we just transform it, we'll have to transform it back again
+        #  Here, we copy the target vector into the result vector because it's the same size. This way we can avoid the second transform
+        write(u'''memcpy(_active_''')
+        _v = VFFSL(SL,"resultVector.id",True) # u'${resultVector.id}' on line 144, col 16
+        if _v is not None: write(_filter(_v, rawExpr=u'${resultVector.id}')) # from line 144, col 16.
+        write(u''', _active_''')
+        _v = VFFSL(SL,"targetVector.id",True) # u'${targetVector.id}' on line 144, col 44
+        if _v is not None: write(_filter(_v, rawExpr=u'${targetVector.id}')) # from line 144, col 44.
+        write(u''', ''')
+        _v = VFFSL(SL,"targetVector.allocSize",True) # u'${targetVector.allocSize}' on line 144, col 64
+        if _v is not None: write(_filter(_v, rawExpr=u'${targetVector.allocSize}')) # from line 144, col 64.
+        write(u''' * sizeof(''')
+        _v = VFFSL(SL,"targetVector.type",True) # u'${targetVector.type}' on line 144, col 99
+        if _v is not None: write(_filter(_v, rawExpr=u'${targetVector.type}')) # from line 144, col 99.
+        write(u'''));
+''')
+        _v = VFFSL(SL,"targetVector.type",True) # u'${targetVector.type}' on line 145, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${targetVector.type}')) # from line 145, col 1.
+        write(u''' *__backup_ptr = _active_''')
+        _v = VFFSL(SL,"targetVector.id",True) # u'${targetVector.id}' on line 145, col 46
+        if _v is not None: write(_filter(_v, rawExpr=u'${targetVector.id}')) # from line 145, col 46.
+        write(u''';
+ptrdiff_t __backup_basis = _''')
+        _v = VFFSL(SL,"targetVector.id",True) # u'${targetVector.id}' on line 146, col 29
+        if _v is not None: write(_filter(_v, rawExpr=u'${targetVector.id}')) # from line 146, col 29.
+        write(u'''_basis;
+_active_''')
+        _v = VFFSL(SL,"targetVector.id",True) # u'${targetVector.id}' on line 147, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${targetVector.id}')) # from line 147, col 9.
+        write(u''' = _active_''')
+        _v = VFFSL(SL,"resultVector.id",True) # u'${resultVector.id}' on line 147, col 38
+        if _v is not None: write(_filter(_v, rawExpr=u'${resultVector.id}')) # from line 147, col 38.
+        write(u''';
+
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def optimisedOperatorCopyEnd(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def optimisedOperatorCopyEnd at line 152, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        if len(VFFSL(SL,"targetVectors",True)) != 1 or not VFFSL(SL,"resultVector",True) or len(VFFSL(SL,"operatorNames",True)) != 1: # generated from line 153, col 3
+            return
+        targetVector = VFFSL(SL,"anyObject",False)(VFFSL(SL,"targetVectors",True))
+        if VFFSL(SL,"targetVector.nComponents",True) != VFFSL(SL,"resultVector.nComponents",True) or not targetVector.needsTransforms: # generated from line 157, col 3
+            return
+        write(u'''_active_''')
+        _v = VFFSL(SL,"targetVector.id",True) # u'${targetVector.id}' on line 160, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${targetVector.id}')) # from line 160, col 9.
+        write(u''' = __backup_ptr;
+_''')
+        _v = VFFSL(SL,"targetVector.id",True) # u'${targetVector.id}' on line 161, col 2
+        if _v is not None: write(_filter(_v, rawExpr=u'${targetVector.id}')) # from line 161, col 2.
+        write(u'''_basis = __backup_basis;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # Operator.tmpl
+        # 
+        # Created by Graham Dennis on 2007-10-13.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    evaluateOperatorFunctionArgument = 'real _step'
+
+    _mainCheetahMethod_for_Operator= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(Operator, '_initCheetahAttributes'):
+    templateAPIClass = getattr(Operator, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(Operator)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=Operator()).run()
+
+
diff --git a/xpdeint/Operators/Operator.tmpl b/xpdeint/Operators/Operator.tmpl
new file mode 100644
index 0000000..5cff0e2
--- /dev/null
+++ b/xpdeint/Operators/Operator.tmpl
@@ -0,0 +1,164 @@
+@*
+Operator.tmpl
+
+Created by Graham Dennis on 2007-10-13.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Operators._Operator
+
+ at from xpdeint.Vectors.VectorElement import VectorElement
+ at from xpdeint.CallOnceGuards import callOncePerInstanceGuard
+
+ at def insideEvaluateOperatorLoops
+  @#
+  @# Content must be provided by a subclass
+  @assert 0
+  @#
+ at end def
+
+@@callOncePerInstanceGuard
+ at def initialise
+  @#
+  @super
+  @#
+  @if $operatorVector
+_${parent.id}_calculate_${name}_field();
+  @end if
+  @#
+ at end def
+
+ at def calculateOperatorFieldFunctionContents($function)
+  @#
+${codeBlocks['operatorDefinition'].loop(self.insideCalculateOperatorFieldLoops)}@slurp
+  @#
+ at end def
+
+ at def insideCalculateOperatorFieldLoopsBegin
+  @#
+  @for $operatorComponentName in $operatorComponents.iterkeys()
+    @if $operatorVector and operatorComponentName in $operatorVector.components
+      @continue
+    @end if
+${operatorVector.type} $operatorComponentName;
+  @end for
+  @#
+ at end def
+
+ at attr $evaluateOperatorFunctionArgument = 'real _step'
+
+ at def evaluateOperatorFunctionContents($function)
+  @#
+  @if not 'calculateOperatorField' in $functions
+${evaluateOperatorFunctionContentsWithCodeBlock(function)}@slurp
+  @else
+${evaluateOperatorFunctionContentsWithoutCodeBlock(function)}@slurp
+  @end if
+  @#
+ at end def
+
+ at def evaluateOperatorFunctionContentsWithCodeBlock($function)
+  @#
+${callEvaluateLoop}@slurp
+  @#
+  @if $resultVector and $resultVector.needsTransforms
+
+_${resultVector.id}_basis = $basisIndexForBasis($operatorBasis);
+  @end if
+  @#
+ at end def
+
+ at def callEvaluateLoop
+${codeBlocks['operatorDefinition'].loop(self.insideEvaluateOperatorLoops)}@slurp
+ at end def
+
+ at def insideEvaluateOperatorLoopsBegin
+  @#
+  @if not $operatorVector
+    @# If we don't have an operator vector, then we need to create
+    @# the component variables so that the user can set them inside
+    @# the loop
+    @for $operatorComponentName, $operatorComponentDictionary in $operatorComponents.iteritems()
+      @set $typeNamesSet = set([vector.type for vector in operatorComponentDictionary.iterkeys()])
+      @set $typeName = 'real'
+      @if 'complex' in typeNamesSet
+        @set $typeName = 'complex'
+      @end if
+${typeName} ${operatorComponentName};
+    @end for
+
+  @end if
+  @#
+ at end def
+
+ at def evaluateOperatorFunctionContentsWithoutCodeBlock($function)
+  @#
+  @# We need to loop over all of the vectors to which we are applying our operators.
+  @#
+${transformVectorsToBasis($targetVectors, $operatorBasis)}@slurp
+  @#
+
+  @# We have an operator vector and we will need to loop over it
+  @set $setOfVectorsToLoopOver = $targetVectors.copy()
+  @silent $setOfVectorsToLoopOver.add($operatorVector)
+  @if $resultVector
+    @silent $setOfVectorsToLoopOver.add($resultVector)
+  @end if
+  @#
+${evaluateOperatorLoop(setOfVectorsToLoopOver)}@slurp
+  @#
+  @if $resultVector and $resultVector.needsTransforms
+
+_${resultVector.id}_basis = $basisIndexForBasis($operatorBasis);
+  @end if
+  @#
+ at end def
+
+ at def optimisedOperatorCopyBegin
+  @# This optimisation only works in a restricted set of circumstances.  It's common enough, but not as general
+  @# as it could be.  Basically, you need a single operator name (e.g. L, not Lx and Ly) which is applied to all
+  @# components of a vector.
+  @if len($targetVectors) != 1 or not $resultVector or len($operatorNames) != 1
+    @return
+  @end if
+  @set targetVector = $anyObject($targetVectors)
+  @if $targetVector.nComponents != $resultVector.nComponents or not targetVector.needsTransforms
+    @return
+  @end if
+  @# For this operator, we don't modify the target vector, so if we just transform it, we'll have to transform it back again
+  @# Here, we copy the target vector into the result vector because it's the same size. This way we can avoid the second transform
+memcpy(_active_${resultVector.id}, _active_${targetVector.id}, ${targetVector.allocSize} * sizeof(${targetVector.type}));
+${targetVector.type} *__backup_ptr = _active_${targetVector.id};
+ptrdiff_t __backup_basis = _${targetVector.id}_basis;
+_active_${targetVector.id} = _active_${resultVector.id};
+
+  @#
+ at end def
+
+ at def optimisedOperatorCopyEnd
+  @if len($targetVectors) != 1 or not $resultVector or len($operatorNames) != 1
+    @return
+  @end if
+  @set targetVector = $anyObject($targetVectors)
+  @if $targetVector.nComponents != $resultVector.nComponents or not targetVector.needsTransforms
+    @return
+  @end if
+_active_${targetVector.id} = __backup_ptr;
+_${targetVector.id}_basis = __backup_basis;
+  @#
+ at end def
+
diff --git a/xpdeint/Operators/OperatorContainer.py b/xpdeint/Operators/OperatorContainer.py
new file mode 100644
index 0000000..293bb27
--- /dev/null
+++ b/xpdeint/Operators/OperatorContainer.py
@@ -0,0 +1,182 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+OperatorContainer.py
+
+Created by Graham Dennis on 2008-03-09.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.ScriptElement import ScriptElement
+
+from xpdeint.Operators._Operator import _Operator
+from xpdeint.ParserException import ParserException
+
+from xpdeint.Utilities import lazy_property, valueForKeyPath
+
+class OperatorContainer(ScriptElement):
+  """
+  The `OperatorContainer` is, as the name suggests, a container for operators.
+  The idea is that there are many places where you want to be able to have a set
+  of operators and you want to be execute all of them without worrying too much
+  about what operators they are. 
+  
+  Similarly, some operators depend on a common (or 'shared') code block to determine
+  their behaviour (e.g. IP and EX). The `OperatorContainer` abstracts exactly where
+  this shared code block is and what its dependencies are so the operators don't need
+  to know whether they are being used in an integrator or in moment group sampling,
+  all they care about is that the `OperatorContainer` has been configured correctly.
+  
+  Configuring an OperatorContainer amounts to setting the `sharedCodeEntityKeyPath`, 
+  `dependenciesKeyPath` and `sharedCodeSpaceKeyPath` variables in the initialiser
+  for `OperatorContainer`. `sharedCodeEntityKeyPath` is a string that is a dotted-name
+  lookup specifier for the string that is the 'shared' code block for this operator
+  container. For example, in the case of an integrator, the 'shared' code block is the
+  integration code ``'dphi_dt = L[phi] + V*phi; // etc.'`` In an integrator, this
+  shared code belongs to the delta-a operator of the operator container. The 
+  `sharedCodeSpaceKeyPath` is simply the space in which the 'shared' code block is
+  evaluated, and `dependenciesKeyPath` is the key path to the dependencies that will
+  be available when the shared code is evaluated. These three variables configure
+  the three proxy variables on the `OperatorContainer`, `sharedCode`,
+  `dependencies` and `sharedCodeSpace`. Proxies are used to refer to the actual variables
+  instead of accessing them directly to enable write access to, for example, the shared code
+  object (as is needed by the IP operator).
+  
+  When executing operators in an `OperatorContainer` it is important to first to ensure
+  that all necessary computed vectors have been evaluated (and in the correct order).
+  To help with this, OperatorContainer returns a set of all of the computed vectors
+  on which operators in this `OperatorContainer` depend through the 
+  `dynamicVectorsNeedingPrecalculation` method.
+  
+  Do write the code that will actually evaluate the operators, just call one of the ``evaluate*``
+  functions. If you need to call another function on the operators other than ``evaluate``,
+  (currently the only other function is ``calculateOperatorField``) then you would use the
+  ``callOperatorFunctionWithArguments`` method.
+  """
+  def __init__(self, *args, **KWs):
+    localKWs = self.extractLocalKWs(['field', 'name', 'sharedCodeBlockKeyPath'], KWs)
+    
+    ScriptElement.__init__(self, *args, **KWs)
+    
+    # Set default state
+    self.ipOperators = []
+    self.preDeltaAOperators = []
+    self.deltaAOperator = None
+    self.postDeltaAOperators = []
+    self.field = localKWs.get('field', None)
+    self._name = localKWs.get('name', None)
+    
+    # These key paths are the 'paths' to the actual attributes for our
+    # 'sharedCodeBlock' proxy property
+    self.sharedCodeBlockKeyPath = localKWs.get('sharedCodeBlockKeyPath', 'deltaAOperator.primaryCodeBlock')
+  
+  def _getSharedCode(self):
+    return valueForKeyPath(self, self.sharedCodeEntityKeyPath).value
+  
+  def _setSharedCode(self, value):
+    valueForKeyPath(self, self.sharedCodeEntityKeyPath).value = value
+  
+  sharedCode = property(_getSharedCode, _setSharedCode)
+  del _getSharedCode, _setSharedCode
+  
+  @lazy_property
+  def sharedCodeBlock(self):
+    return valueForKeyPath(self, self.sharedCodeBlockKeyPath)
+  
+  @property
+  def name(self):
+    if self._name:
+      return self._name
+    if not self.field:
+      # We are deliberately not setting self._name here
+      return ''
+    self._name = 'container' + str(self.parent.operatorContainers.index(self))
+    return self._name
+  
+  @property
+  def operators(self):
+    result = self.ipOperators[:]
+    result.extend(self.preDeltaAOperators)
+    if self.deltaAOperator:
+      result.append(self.deltaAOperator)
+    result.extend(self.postDeltaAOperators)
+    return result
+  
+  @property
+  def children(self):
+    children = super(OperatorContainer, self).children
+    children.extend(self.operators)
+    return children
+  
+  @property
+  def dynamicVectorsNeedingPrecalculation(self):
+    result = set()
+    for operator in self.operators:
+      result.update(operator.dynamicVectorsNeedingPrecalculation)
+    return result
+  
+  def addOperator(self, op):
+    if op.operatorKind == _Operator.IPOperatorKind:
+      self.ipOperators.append(op)
+    elif op.operatorKind == _Operator.DeltaAOperatorKind:
+      if self.deltaAOperator:
+        raise ParserException(op.xmlElement, "For some reason we are trying to add two delta a operators to this operator container.")
+      self.deltaAOperator = op
+    elif not self.deltaAOperator:
+      self.preDeltaAOperators.append(op)
+    else:
+      self.postDeltaAOperators.append(op)
+    
+    op.operatorNumber = len(self.operators) - 1
+  
+  def evaluateIPOperators(self, arguments = None, parentFunction = None, **KWs):
+    arguments = arguments or {}
+    return self.callOperatorFunctionWithArguments('evaluate', self.ipOperators, arguments, parentFunction, **KWs)
+  
+  def evaluatePreDeltaAOperators(self, arguments = None, parentFunction = None, **KWs):
+    arguments = arguments or {}
+    return self.callOperatorFunctionWithArguments('evaluate', self.preDeltaAOperators, arguments, parentFunction, **KWs)
+  
+  def evaluatePostDeltaAOperators(self, arguments = None, parentFunction = None, **KWs):
+    arguments = arguments or {}
+    return self.callOperatorFunctionWithArguments('evaluate', self.postDeltaAOperators, arguments, parentFunction, **KWs)
+  
+  def evaluateDeltaAOperator(self, arguments = None, parentFunction = None, **KWs):
+    arguments = arguments or {}
+    if self.deltaAOperator:
+      return self.callOperatorFunctionWithArguments('evaluate', [self.deltaAOperator], arguments, parentFunction, **KWs)
+    else:
+      return ''
+  
+  def evaluateOperators(self, arguments = None, parentFunction = None, **KWs):
+    arguments = arguments or {}
+    assert not self.postDeltaAOperators and not self.deltaAOperator and not self.ipOperators
+    return self.callOperatorFunctionWithArguments('evaluate', self.preDeltaAOperators, arguments, parentFunction, **KWs)
+  
+  @staticmethod
+  def callOperatorFunctionWithArguments(functionName, operators, arguments = None, parentFunction = None, **KWs):
+    arguments = arguments or {}
+    return '\n'.join(['// ' + op.description() + '\n' + op.functions[functionName].call(arguments, parentFunction = parentFunction, **KWs) + '\n' for op in operators])
+  
+  def preflight(self):
+    super(OperatorContainer, self).preflight()
+    
+    if self.field and self.deltaAOperator:
+      assert self.field == self.deltaAOperator.field
+    
+
diff --git a/xpdeint/Operators/SICDeltaAOperator.py b/xpdeint/Operators/SICDeltaAOperator.py
new file mode 100644
index 0000000..a1381ea
--- /dev/null
+++ b/xpdeint/Operators/SICDeltaAOperator.py
@@ -0,0 +1,533 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Operators._SICDeltaAOperator import _SICDeltaAOperator
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.223261
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Operators/SICDeltaAOperator.tmpl'
+__CHEETAH_srcLastModified__ = 'Mon Jul 23 09:42:26 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class SICDeltaAOperator(_SICDeltaAOperator):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(SICDeltaAOperator, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Left/Right Delta A propagation operator for field $field.name at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Left/Right Delta A propagation operator for field ''')
+        _v = VFFSL(SL,"field.name",True) # u'$field.name' on line 26, col 69
+        if _v is not None: write(_filter(_v, rawExpr=u'$field.name')) # from line 26, col 69.
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def callEvaluateLoop(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def callEvaluateLoop at line 28, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        for crossIntegrationVector in VFFSL(SL,"crossIntegrationVectors",True): # generated from line 30, col 3
+            for componentName in crossIntegrationVector.components: # generated from line 31, col 5
+                _v = VFFSL(SL,"crossIntegrationVector.type",True) # u'${crossIntegrationVector.type}' on line 32, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${crossIntegrationVector.type}')) # from line 32, col 1.
+                write(u''' _old_d''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 32, col 38
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 32, col 38.
+                write(u'''_d''')
+                _v = VFFSL(SL,"crossPropagationDimension",True) # u'${crossPropagationDimension}' on line 32, col 56
+                if _v is not None: write(_filter(_v, rawExpr=u'${crossPropagationDimension}')) # from line 32, col 56.
+                write(u''';
+''')
+        # 
+        loopingOrder = {                        '+': SICDeltaAOperator.LoopingOrder.StrictlyAscendingOrder,                        '-': SICDeltaAOperator.LoopingOrder.StrictlyDescendingOrder                       }[self.crossPropagationDirection]
+        _v = VFN(VFFSL(SL,"codeBlocks",True)['operatorDefinition'],"loop",False)(self.insideEvaluateOperatorLoops, loopingOrder = loopingOrder) # u"${codeBlocks['operatorDefinition'].loop(self.insideEvaluateOperatorLoops, loopingOrder = loopingOrder)}" on line 40, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${codeBlocks['operatorDefinition'].loop(self.insideEvaluateOperatorLoops, loopingOrder = loopingOrder)}")) # from line 40, col 1.
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideEvaluateOperatorLoops(self, codeString, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideEvaluateOperatorLoops($codeString) at line 43, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"insideEvaluateOperatorLoopsBegin",True) # u'${insideEvaluateOperatorLoopsBegin}' on line 45, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${insideEvaluateOperatorLoopsBegin}')) # from line 45, col 1.
+        # 
+        #  The Operator class will have defined for us all of the dVariableName_dPropagationDimension variables.
+        #  Note that we assume that all of the integration vectors have an operotor component defined for them.
+        write(u'''  
+// UNVECTORISABLE
+''')
+        for crossIntegrationVector in VFFSL(SL,"crossIntegrationVectors",True): # generated from line 51, col 3
+            for componentName in crossIntegrationVector.components: # generated from line 52, col 5
+                write(u'''d''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 53, col 2
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 53, col 2.
+                write(u'''_d''')
+                _v = VFFSL(SL,"crossPropagationDimension",True) # u'${crossPropagationDimension}' on line 53, col 20
+                if _v is not None: write(_filter(_v, rawExpr=u'${crossPropagationDimension}')) # from line 53, col 20.
+                write(u''' = _old_d''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 53, col 57
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 53, col 57.
+                write(u'''_d''')
+                _v = VFFSL(SL,"crossPropagationDimension",True) # u'${crossPropagationDimension}' on line 53, col 75
+                if _v is not None: write(_filter(_v, rawExpr=u'${crossPropagationDimension}')) # from line 53, col 75.
+                write(u''';
+''')
+        write(u'''
+''')
+        crossDimRep = VFN(VFN(VFFSL(SL,"loopingField",True),"dimensionWithName",False)(VFFSL(SL,"crossPropagationDimension",True)),"inBasis",False)(VFFSL(SL,"operatorBasis",True))
+        if VFFSL(SL,"crossPropagationDirection",True) == '+': # generated from line 58, col 3
+            write(u'''if (''')
+            _v = VFFSL(SL,"crossDimRep.loopIndex",True) # u'${crossDimRep.loopIndex}' on line 59, col 5
+            if _v is not None: write(_filter(_v, rawExpr=u'${crossDimRep.loopIndex}')) # from line 59, col 5.
+            write(u''' == 0) {
+''')
+        else: # generated from line 60, col 3
+            write(u'''if (''')
+            _v = VFFSL(SL,"crossDimRep.loopIndex",True) # u'${crossDimRep.loopIndex}' on line 61, col 5
+            if _v is not None: write(_filter(_v, rawExpr=u'${crossDimRep.loopIndex}')) # from line 61, col 5.
+            write(u''' == ''')
+            _v = VFFSL(SL,"crossDimRep.globalLattice",True) # u'${crossDimRep.globalLattice}' on line 61, col 33
+            if _v is not None: write(_filter(_v, rawExpr=u'${crossDimRep.globalLattice}')) # from line 61, col 33.
+            write(u''' - 1) {
+''')
+        write(u'''  // ********** Boundary condition code ***********
+  ''')
+        _v = VFN(VFFSL(SL,"codeBlocks",True)['boundaryCondition'],"loopCodeString",True) # u"${codeBlocks['boundaryCondition'].loopCodeString, autoIndent=True}" on line 64, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${codeBlocks['boundaryCondition'].loopCodeString, autoIndent=True}")) # from line 64, col 3.
+        write(u'''  // **********************************************
+  
+''')
+        for crossIntegrationVector in VFFSL(SL,"crossIntegrationVectors",True): # generated from line 67, col 3
+            write(u'''  for (long _cmp = 0; _cmp < _''')
+            _v = VFFSL(SL,"crossIntegrationVector.id",True) # u'${crossIntegrationVector.id}' on line 68, col 31
+            if _v is not None: write(_filter(_v, rawExpr=u'${crossIntegrationVector.id}')) # from line 68, col 31.
+            write(u'''_ncomponents; _cmp++)
+    _old_''')
+            _v = VFFSL(SL,"crossIntegrationVector.id",True) # u'${crossIntegrationVector.id}' on line 69, col 10
+            if _v is not None: write(_filter(_v, rawExpr=u'${crossIntegrationVector.id}')) # from line 69, col 10.
+            write(u'''[_cmp] = _active_''')
+            _v = VFFSL(SL,"crossIntegrationVector.id",True) # u'${crossIntegrationVector.id}' on line 69, col 55
+            if _v is not None: write(_filter(_v, rawExpr=u'${crossIntegrationVector.id}')) # from line 69, col 55.
+            write(u'''[_''')
+            _v = VFFSL(SL,"crossIntegrationVector.id",True) # u'${crossIntegrationVector.id}' on line 69, col 85
+            if _v is not None: write(_filter(_v, rawExpr=u'${crossIntegrationVector.id}')) # from line 69, col 85.
+            write(u'''_index_pointer + _cmp];
+''')
+        write(u'''  
+''')
+        #  This is where one (half-step) cross-IP step would go
+        write(u'''} else {
+  // Update the next guess for iteration.
+''')
+        for crossIntegrationVector in VFFSL(SL,"crossIntegrationVectors",True): # generated from line 75, col 3
+            for componentNumber, componentName, in enumerate(crossIntegrationVector.components): # generated from line 76, col 5
+                write(u'''  ''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 77, col 3
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 77, col 3.
+                write(u''' = _old_''')
+                _v = VFFSL(SL,"crossIntegrationVector.id",True) # u'${crossIntegrationVector.id}' on line 77, col 27
+                if _v is not None: write(_filter(_v, rawExpr=u'${crossIntegrationVector.id}')) # from line 77, col 27.
+                write(u'''[''')
+                _v = VFFSL(SL,"componentNumber",True) # u'${componentNumber}' on line 77, col 56
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentNumber}')) # from line 77, col 56.
+                write(u'''] + d''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 77, col 79
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 77, col 79.
+                write(u'''_d''')
+                _v = VFFSL(SL,"crossPropagationDimension",True) # u'${crossPropagationDimension}' on line 77, col 97
+                if _v is not None: write(_filter(_v, rawExpr=u'${crossPropagationDimension}')) # from line 77, col 97.
+                write(u''' * (''')
+                _v = VFFSL(SL,"crossPropagationDirection",True) # u'${crossPropagationDirection}' on line 77, col 129
+                if _v is not None: write(_filter(_v, rawExpr=u'${crossPropagationDirection}')) # from line 77, col 129.
+                write(u'''0.5*d''')
+                _v = VFFSL(SL,"crossPropagationDimension",True) # u'${crossPropagationDimension}' on line 77, col 162
+                if _v is not None: write(_filter(_v, rawExpr=u'${crossPropagationDimension}')) # from line 77, col 162.
+                write(u''');
+''')
+        write(u'''}
+
+for (long _iter = 0; _iter < ''')
+        _v = VFFSL(SL,"iterations",True) # u'${iterations}' on line 82, col 30
+        if _v is not None: write(_filter(_v, rawExpr=u'${iterations}')) # from line 82, col 30.
+        write(u'''; _iter++) {
+  
+  #define d''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 84, col 12
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 84, col 12.
+        write(u''' _step
+  {
+    // ************* Propagation code ***************
+    ''')
+        _v = VFFSL(SL,"codeString",True) # u'${codeString, autoIndent=True}' on line 87, col 5
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${codeString, autoIndent=True}')) # from line 87, col 5.
+        write(u'''    // **********************************************
+  }
+  #undef d''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 90, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 90, col 11.
+        write(u'''
+  
+  {
+    // *********** Cross-propagation code ***********
+    ''')
+        _v = VFN(VFFSL(SL,"codeBlocks",True)['crossPropagation'],"loopCodeString",True) # u"${codeBlocks['crossPropagation'].loopCodeString, autoIndent=True}" on line 94, col 5
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${codeBlocks['crossPropagation'].loopCodeString, autoIndent=True}")) # from line 94, col 5.
+        write(u'''    // **********************************************
+  }
+  
+  // Update propagation vectors (note that _step is actually half a step)
+''')
+        for integrationVector in VFFSL(SL,"integrationVectors",True): # generated from line 99, col 3
+            for componentNumber, componentName in enumerate(integrationVector.components): # generated from line 100, col 5
+                write(u'''  ''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 101, col 3
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 101, col 3.
+                write(u''' = _''')
+                _v = VFFSL(SL,"integrator.name",True) # u'${integrator.name}' on line 101, col 23
+                if _v is not None: write(_filter(_v, rawExpr=u'${integrator.name}')) # from line 101, col 23.
+                write(u'''_oldcopy_''')
+                _v = VFFSL(SL,"integrationVector.id",True) # u'${integrationVector.id}' on line 101, col 50
+                if _v is not None: write(_filter(_v, rawExpr=u'${integrationVector.id}')) # from line 101, col 50.
+                write(u'''[_''')
+                _v = VFFSL(SL,"integrationVector.id",True) # u'${integrationVector.id}' on line 101, col 75
+                if _v is not None: write(_filter(_v, rawExpr=u'${integrationVector.id}')) # from line 101, col 75.
+                write(u'''_index_pointer + ''')
+                _v = VFFSL(SL,"componentNumber",True) # u'${componentNumber}' on line 101, col 115
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentNumber}')) # from line 101, col 115.
+                write(u'''] + d''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 101, col 138
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 101, col 138.
+                write(u'''_d''')
+                _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 101, col 156
+                if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 101, col 156.
+                write(u''' * _step;
+''')
+        write(u'''  
+  // Update cross-propagation vectors
+''')
+        for crossIntegrationVector in VFFSL(SL,"crossIntegrationVectors",True): # generated from line 106, col 3
+            for componentNumber, componentName in enumerate(VFFSL(SL,"crossIntegrationVector.components",True)): # generated from line 107, col 5
+                write(u'''  ''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 108, col 3
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 108, col 3.
+                write(u''' = _old_''')
+                _v = VFFSL(SL,"crossIntegrationVector.id",True) # u'${crossIntegrationVector.id}' on line 108, col 27
+                if _v is not None: write(_filter(_v, rawExpr=u'${crossIntegrationVector.id}')) # from line 108, col 27.
+                write(u'''[''')
+                _v = VFFSL(SL,"componentNumber",True) # u'${componentNumber}' on line 108, col 56
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentNumber}')) # from line 108, col 56.
+                write(u'''] + d''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 108, col 79
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 108, col 79.
+                write(u'''_d''')
+                _v = VFFSL(SL,"crossPropagationDimension",True) # u'${crossPropagationDimension}' on line 108, col 97
+                if _v is not None: write(_filter(_v, rawExpr=u'${crossPropagationDimension}')) # from line 108, col 97.
+                write(u''' * (''')
+                _v = VFFSL(SL,"crossPropagationDirection",True) # u'${crossPropagationDirection}' on line 108, col 129
+                if _v is not None: write(_filter(_v, rawExpr=u'${crossPropagationDirection}')) # from line 108, col 129.
+                write(u'''0.5*d''')
+                _v = VFFSL(SL,"crossPropagationDimension",True) # u'${crossPropagationDimension}' on line 108, col 162
+                if _v is not None: write(_filter(_v, rawExpr=u'${crossPropagationDimension}')) # from line 108, col 162.
+                write(u''');
+''')
+        write(u"""}
+
+// Update the 'old' copy for the next half-step
+""")
+        for crossIntegrationVector in VFFSL(SL,"crossIntegrationVectors",True): # generated from line 114, col 1
+            for componentNumber, componentName in enumerate(crossIntegrationVector.components): # generated from line 115, col 3
+                write(u'''_old_''')
+                _v = VFFSL(SL,"crossIntegrationVector.id",True) # u'${crossIntegrationVector.id}' on line 116, col 6
+                if _v is not None: write(_filter(_v, rawExpr=u'${crossIntegrationVector.id}')) # from line 116, col 6.
+                write(u'''[''')
+                _v = VFFSL(SL,"componentNumber",True) # u'${componentNumber}' on line 116, col 35
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentNumber}')) # from line 116, col 35.
+                write(u'''] += d''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 116, col 59
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 116, col 59.
+                write(u'''_d''')
+                _v = VFFSL(SL,"crossPropagationDimension",True) # u'${crossPropagationDimension}' on line 116, col 77
+                if _v is not None: write(_filter(_v, rawExpr=u'${crossPropagationDimension}')) # from line 116, col 77.
+                write(u''' * (''')
+                _v = VFFSL(SL,"crossPropagationDirection",True) # u'${crossPropagationDirection}' on line 116, col 109
+                if _v is not None: write(_filter(_v, rawExpr=u'${crossPropagationDirection}')) # from line 116, col 109.
+                write(u'''d''')
+                _v = VFFSL(SL,"crossPropagationDimension",True) # u'${crossPropagationDimension}' on line 116, col 138
+                if _v is not None: write(_filter(_v, rawExpr=u'${crossPropagationDimension}')) # from line 116, col 138.
+                write(u''');
+''')
+        write(u'''
+''')
+        #  This is where one (full step) cross-IP step would go
+        write(u'''
+''')
+        for crossIntegrationVector in VFFSL(SL,"crossIntegrationVectors",True): # generated from line 122, col 3
+            for componentName in crossIntegrationVector.components: # generated from line 123, col 5
+                write(u'''_old_d''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 124, col 7
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 124, col 7.
+                write(u'''_d''')
+                _v = VFFSL(SL,"crossPropagationDimension",True) # u'${crossPropagationDimension}' on line 124, col 25
+                if _v is not None: write(_filter(_v, rawExpr=u'${crossPropagationDimension}')) # from line 124, col 25.
+                write(u''' = d''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 124, col 57
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 124, col 57.
+                write(u'''_d''')
+                _v = VFFSL(SL,"crossPropagationDimension",True) # u'${crossPropagationDimension}' on line 124, col 75
+                if _v is not None: write(_filter(_v, rawExpr=u'${crossPropagationDimension}')) # from line 124, col 75.
+                write(u''';
+''')
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def evaluateOperatorFunctionContentsWithCodeBlock(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def evaluateOperatorFunctionContentsWithCodeBlock($function) at line 131, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  We shouldn't have a deltaAField. It doesn't work with cross-propagation.
+        assert not VFFSL(SL,"deltaAField",True)
+        # 
+        for crossIntegrationVector in VFFSL(SL,"crossIntegrationVectors",True): # generated from line 136, col 3
+            _v = VFFSL(SL,"crossIntegrationVector.type",True) # u'${crossIntegrationVector.type}' on line 137, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${crossIntegrationVector.type}')) # from line 137, col 1.
+            write(u''' _old_''')
+            _v = VFFSL(SL,"crossIntegrationVector.id",True) # u'${crossIntegrationVector.id}' on line 137, col 37
+            if _v is not None: write(_filter(_v, rawExpr=u'${crossIntegrationVector.id}')) # from line 137, col 37.
+            write(u'''[_''')
+            _v = VFFSL(SL,"crossIntegrationVector.id",True) # u'${crossIntegrationVector.id}' on line 137, col 67
+            if _v is not None: write(_filter(_v, rawExpr=u'${crossIntegrationVector.id}')) # from line 137, col 67.
+            write(u'''_ncomponents];
+''')
+        # 
+        _v = super(SICDeltaAOperator, self).evaluateOperatorFunctionContentsWithCodeBlock(function)
+        if _v is not None: write(_filter(_v))
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # SICDeltaAOperator.tmpl
+        # 
+        # delta-a operator for the left/right propagation in the SIC integrator.
+        # 
+        # Created by Graham Dennis on 2008-08-07.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_SICDeltaAOperator= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(SICDeltaAOperator, '_initCheetahAttributes'):
+    templateAPIClass = getattr(SICDeltaAOperator, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(SICDeltaAOperator)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=SICDeltaAOperator()).run()
+
+
diff --git a/xpdeint/Operators/SICDeltaAOperator.tmpl b/xpdeint/Operators/SICDeltaAOperator.tmpl
new file mode 100644
index 0000000..44ab456
--- /dev/null
+++ b/xpdeint/Operators/SICDeltaAOperator.tmpl
@@ -0,0 +1,142 @@
+@*
+SICDeltaAOperator.tmpl
+
+delta-a operator for the left/right propagation in the SIC integrator.
+
+Created by Graham Dennis on 2008-08-07.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Operators._SICDeltaAOperator
+
+ at def description: Left/Right Delta A propagation operator for field $field.name
+
+ at def callEvaluateLoop
+  @#
+  @for crossIntegrationVector in $crossIntegrationVectors
+    @for componentName in crossIntegrationVector.components
+${crossIntegrationVector.type} _old_d${componentName}_d${crossPropagationDimension};
+    @end for
+  @end for
+  @#
+  @set $loopingOrder = {
+                        '+': SICDeltaAOperator.LoopingOrder.StrictlyAscendingOrder,
+                        '-': SICDeltaAOperator.LoopingOrder.StrictlyDescendingOrder
+                       }[self.crossPropagationDirection]
+${codeBlocks['operatorDefinition'].loop(self.insideEvaluateOperatorLoops, loopingOrder = loopingOrder)}@slurp
+ at end def
+
+ at def insideEvaluateOperatorLoops($codeString)
+  @#
+${insideEvaluateOperatorLoopsBegin}@slurp
+  @#
+  @# The Operator class will have defined for us all of the dVariableName_dPropagationDimension variables.
+  @# Note that we assume that all of the integration vectors have an operotor component defined for them.
+  
+// UNVECTORISABLE
+  @for crossIntegrationVector in $crossIntegrationVectors
+    @for componentName in crossIntegrationVector.components
+d${componentName}_d${crossPropagationDimension} = _old_d${componentName}_d${crossPropagationDimension};
+    @end for
+  @end for
+
+  @set $crossDimRep = $loopingField.dimensionWithName($crossPropagationDimension).inBasis($operatorBasis)
+  @if $crossPropagationDirection == '+'
+if (${crossDimRep.loopIndex} == 0) {
+  @else
+if (${crossDimRep.loopIndex} == ${crossDimRep.globalLattice} - 1) {
+  @end if
+  // ********** Boundary condition code ***********
+  ${codeBlocks['boundaryCondition'].loopCodeString, autoIndent=True}@slurp
+  // **********************************************
+  
+  @for crossIntegrationVector in $crossIntegrationVectors
+  for (long _cmp = 0; _cmp < _${crossIntegrationVector.id}_ncomponents; _cmp++)
+    _old_${crossIntegrationVector.id}[_cmp] = _active_${crossIntegrationVector.id}[_${crossIntegrationVector.id}_index_pointer + _cmp];
+  @end for
+  
+  @# This is where one (half-step) cross-IP step would go
+} else {
+  // Update the next guess for iteration.
+  @for crossIntegrationVector in $crossIntegrationVectors
+    @for componentNumber, componentName, in enumerate(crossIntegrationVector.components)
+  ${componentName} = _old_${crossIntegrationVector.id}[${componentNumber}] + d${componentName}_d${crossPropagationDimension} * (${crossPropagationDirection}0.5*d${crossPropagationDimension});
+    @end for
+  @end for
+}
+
+for (long _iter = 0; _iter < ${iterations}; _iter++) {
+  
+  #define d${propagationDimension} _step
+  {
+    // ************* Propagation code ***************
+    ${codeString, autoIndent=True}@slurp
+    // **********************************************
+  }
+  #undef d${propagationDimension}
+  
+  {
+    // *********** Cross-propagation code ***********
+    ${codeBlocks['crossPropagation'].loopCodeString, autoIndent=True}@slurp
+    // **********************************************
+  }
+  
+  // Update propagation vectors (note that _step is actually half a step)
+  @for integrationVector in $integrationVectors
+    @for componentNumber, componentName in enumerate(integrationVector.components)
+  ${componentName} = _${integrator.name}_oldcopy_${integrationVector.id}[_${integrationVector.id}_index_pointer + ${componentNumber}] + d${componentName}_d${propagationDimension} * _step;
+    @end for
+  @end for
+  
+  // Update cross-propagation vectors
+  @for crossIntegrationVector in $crossIntegrationVectors
+    @for componentNumber, componentName in enumerate($crossIntegrationVector.components)
+  ${componentName} = _old_${crossIntegrationVector.id}[${componentNumber}] + d${componentName}_d${crossPropagationDimension} * (${crossPropagationDirection}0.5*d${crossPropagationDimension});
+    @end for
+  @end for
+}
+
+// Update the 'old' copy for the next half-step
+ at for crossIntegrationVector in $crossIntegrationVectors
+  @for componentNumber, componentName in enumerate(crossIntegrationVector.components)
+_old_${crossIntegrationVector.id}[${componentNumber}] += d${componentName}_d${crossPropagationDimension} * (${crossPropagationDirection}d${crossPropagationDimension});
+  @end for
+ at end for
+
+@# This is where one (full step) cross-IP step would go
+
+  @for crossIntegrationVector in $crossIntegrationVectors
+    @for componentName in crossIntegrationVector.components
+_old_d${componentName}_d${crossPropagationDimension} = d${componentName}_d${crossPropagationDimension};
+    @end for
+  @end for
+
+  @#
+ at end def
+
+ at def evaluateOperatorFunctionContentsWithCodeBlock($function)
+  @#
+  @# We shouldn't have a deltaAField. It doesn't work with cross-propagation.
+  @assert not $deltaAField
+  @#
+  @for $crossIntegrationVector in $crossIntegrationVectors
+${crossIntegrationVector.type} _old_${crossIntegrationVector.id}[_${crossIntegrationVector.id}_ncomponents];
+  @end for
+  @#
+  @super(function)
+  @#
+ at end def
diff --git a/xpdeint/Operators/_CrossPropagationOperator.py b/xpdeint/Operators/_CrossPropagationOperator.py
new file mode 100644
index 0000000..3ca5937
--- /dev/null
+++ b/xpdeint/Operators/_CrossPropagationOperator.py
@@ -0,0 +1,232 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_CrossPropagationOperator.py
+
+Created by Graham Dennis on 2008-03-01.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Operators.Operator import Operator
+
+from xpdeint.Geometry.FieldElement import FieldElement
+from xpdeint.Vectors.VectorElement import VectorElement
+
+from xpdeint.ParserException import ParserException
+from xpdeint.Utilities import lazy_property
+
+class _CrossPropagationOperator (Operator):
+  operatorKind = Operator.OtherOperatorKind
+  evaluateOperatorFunctionArguments = []
+  
+  # This is a class attribute and not an instance attribute to prevent two
+  # cross-propagation operators trying to create the same reduced field
+  # and then creating the same reduced vectors, but in these different
+  # fields (but with the same names)
+  # By having a sharedFieldMap, two cross-propagators with the same cross-propagation
+  # dimension can share the same fieldMap variable.
+  # sharedFieldMap is a map from propagation dimension name to a dictionary that can
+  # be used as the fieldMap variable for an instance
+  sharedFieldMap = {}
+  
+  def __init__(self, *args, **KWs):
+    Operator.__init__(self, *args, **KWs)
+    
+    # Set default variables
+    self.propagationDirection = None # '+' or '-'
+    self.propagationDimension = None # Name of the propagation dimension
+    
+    self._crossPropagationIntegrator = None
+    self.crossPropagationIntegratorDeltaAOperator = None
+    self.integrationVectorsEntity = None
+    self.integrationVectors = set()
+    self.reducedVectorMap = {}
+    self.fullVectorMap = {}
+    self.integrationVectorMap = {}
+    self.reducedField = None
+  
+  
+  @lazy_property
+  def fieldMap(self):
+    """
+    Return the field map for this cross-propagator.
+    
+    The fieldMap is a map from full fields to reduced cross-propagation fields that do not have the
+    cross-propagation dimension. The fieldMap instances are shared between cross-propagators that have
+    the same cross-propagation dimension.
+    """
+    if not self.propagationDimension in self.sharedFieldMap:
+      self.sharedFieldMap[self.propagationDimension] = {}
+    return self.sharedFieldMap[self.propagationDimension]
+    
+  
+  def _getCrossPropagationIntegrator(self):
+    return self._crossPropagationIntegrator
+  
+  def _setCrossPropagationIntegrator(self, value):
+    self._crossPropagationIntegrator = value
+    if value not in self._children:
+      self._children.append(value)
+  
+  crossPropagationIntegrator = property(_getCrossPropagationIntegrator, _setCrossPropagationIntegrator)
+  del _getCrossPropagationIntegrator, _setCrossPropagationIntegrator
+  
+  def reducedDimensionFieldForField(self, fullField):
+    if fullField in self.fieldMap:
+      return self.fieldMap[fullField]
+    
+    fieldsWithSameDimensions = filter(lambda x: fullField.dimensions == x.dimensions, self.fieldMap.values())
+    if fieldsWithSameDimensions:
+      result = fieldsWithSameDimensions[0]
+      self.fieldMap[fullField] = result
+      return result
+    
+    reducedField = FieldElement(name = 'cross_%s_%s' % (self.propagationDimension, fullField.name),
+                                **self.argumentsToTemplateConstructors)
+    reducedField.dimensions = filter(lambda x: x.name != self.propagationDimension, fullField.dimensions)
+    
+    self.fieldMap[fullField] = reducedField
+    
+    return reducedField
+  
+  def reducedDimensionVectorForVector(self, fullVector):
+    if fullVector in self.reducedVectorMap:
+      return self.reducedVectorMap[fullVector]
+    # If the vector belongs to a field that lacks the cross-propagation field
+    # then we can just use the original field and we don't need a reduced dimension
+    # version of this vector.
+    if not fullVector.field.hasDimensionName(self.propagationDimension):
+      return fullVector
+    
+    # We have to create the vector element
+    reducedField = self.reducedDimensionFieldForField(fullVector.field)
+    
+    vectorsWithSameName = filter(lambda v: v.name == fullVector.name, reducedField.vectors)
+    if vectorsWithSameName:
+      reducedVector = vectorsWithSameName[0]
+    else:
+      reducedVector = VectorElement(
+        name = fullVector.name, field = reducedField,
+        type = fullVector.type,
+        **self.argumentsToTemplateConstructors
+      )
+      
+      reducedVector.type = fullVector.type
+      reducedVector.components = fullVector.components
+      reducedVector.needsInitialisation = False
+      reducedField.managedVectors.add(reducedVector)
+    
+    self.reducedVectorMap[fullVector] = reducedVector
+    self.fullVectorMap[reducedVector] = fullVector
+    
+    return reducedVector
+  
+  def vectorForVectorName(self, vectorName, vectorDictionary):
+    """
+    This method allows us to override the mapping of vector names to vectors for our children.
+    This way we can replace the full vectors specified by the user with their reduced equivalents.
+    """
+    # Don't try and remap vector names if we don't have a reduced vector map yet.
+    # i.e. if we are parsing our own code blocks
+    if not vectorName in vectorDictionary or not self.reducedVectorMap:
+      return self.parent.vectorForVectorName(vectorName, vectorDictionary)
+    return self.reducedDimensionVectorForVector(vectorDictionary[vectorName])
+  
+  def bindNamedVectors(self):
+    super(_CrossPropagationOperator, self).bindNamedVectors()
+    
+    reducedDependencies = set()
+    # Our named dependencies will already have been taken care of thanks to _Operator.bindNamedVectors()
+    for vector in self.dependencies:
+      reducedVector = self.reducedDimensionVectorForVector(vector)
+      # If the reducedVector is the same as the vector, then it doesn't belong in the dependency map
+      if not reducedVector == vector:
+        reducedDependencies.add(reducedVector)
+    
+    # Add the reduced dependencies to the various parts of the cross-propagation integrator
+    self.crossPropagationIntegratorDeltaAOperator.dependencies.update(reducedDependencies)
+    
+    if self.integrationVectorsEntity:
+      self.integrationVectors = self.vectorsFromEntity(self.integrationVectorsEntity)
+      
+      for integrationVector in self.integrationVectors:
+        if not integrationVector.field == self.field:
+          raise ParserException(self.integrationVectorsEntity.xmlElement, 
+                                "Cannot integrate vector '%s' in this cross-propagation element as it "
+                                "does not belong to the '%s' field." % (integrationVector.name, self.field.name))
+        
+        if integrationVector in self.parent.deltaAOperator.integrationVectors:
+          raise ParserException(self.integrationVectorsEntity.xmlElement,
+                                "Cannot integrate vector '%s' in this cross-propagation element as it "
+                                "is being integrated by the ancestor integrator." % integrationVector.name)
+        
+        reducedVector = self.reducedDimensionVectorForVector(integrationVector)
+        self.integrationVectorMap[integrationVector] = reducedVector
+      
+      # Add the reduced integration vectors to the various parts of the cross-propagation integrator
+      reducedIntegrationVectors = set(self.integrationVectorMap.values())
+      self.crossPropagationIntegrator.integrationVectors.update(reducedIntegrationVectors)
+      self.crossPropagationIntegratorDeltaAOperator.integrationVectors.update(reducedIntegrationVectors)
+      self.crossPropagationIntegratorDeltaAOperator.dependencies.update(reducedIntegrationVectors)
+      
+      self.parent.sharedCodeBlock.dependencies.update(self.integrationVectors)
+    
+    
+    boundaryConditionDependencies = self.codeBlocks['boundaryCondition'].dependencies
+    boundaryConditionDependencies.update(self.integrationVectors)
+    for vector in boundaryConditionDependencies:
+      if not vector.field.isSubsetOfField(self.field):
+        raise ParserException(self.codeBlocks['boundaryCondition'].xmlElement,
+                              "Cannot depend on vector '%s' because it is in the field '%s' "
+                              "which contains dimensions that are not in the field for this operator ('%s')."
+                              % (vector.name, vector.field.name, self.field))
+    
+    if self.propagationDirection == '+':
+      indexOverrideValue = '0'
+    else:
+      propDimRep = self.field.dimensionWithName(self.propagationDimension).inBasis(self.operatorBasis)
+      indexOverrideValue = '(%s - 1)' % propDimRep.globalLattice
+    indexOverrides = {self.propagationDimension: dict([(v.field, indexOverrideValue) for v in boundaryConditionDependencies])}
+    self.codeBlocks['boundaryCondition'].loopArguments['indexOverrides'] = indexOverrides
+  
+  def preflight(self):
+    super(_CrossPropagationOperator, self).preflight()
+    
+    # Check that we aren't distributed with MPI along our intended integration dimension
+    driver = self.getVar('features')['Driver']
+    if self.propagationDimension in driver.distributedDimensionNames:
+      raise ParserException(self.xmlElement, "Cannot cross-propagate along a dimension distributed with MPI.")
+    
+    # Create the dependency map and integration vector map for the cross propagation integrator
+    # Note that they are reversed as they are reducedVector --> fullVector maps, not
+    # fullVector --> reducedVector maps as we constructed above.
+    
+    self.crossPropagationIntegrator.dependencyMap = \
+      dict([(reducedVector, fullVector) for (fullVector, reducedVector) in self.reducedVectorMap.iteritems() if fullVector in self.dependencies])
+    self.crossPropagationIntegrator.integrationVectorMap = \
+      dict([(reducedVector, fullVector) for (fullVector, reducedVector) in self.integrationVectorMap.iteritems()])
+    
+    # Copy the evolution code to the delta a operator
+    # self.crossPropagationIntegratorDeltaAOperator.codeBlocks['operatorDefinition'] = self.primaryCodeBlock
+    
+    # Allow the cross propagation dimension variable to exist in the delta a operator.
+    self.crossPropagationIntegrator.functions['deltaA'].args.append(('real', self.propagationDimension)) # Add it to the calculate_delta_a function
+    self.crossPropagationIntegratorDeltaAOperator.functions['evaluate'].args.append(('real', self.propagationDimension)) # Add it to the delta a operator
+  
+  
+
diff --git a/xpdeint/Operators/_DeltaAOperator.py b/xpdeint/Operators/_DeltaAOperator.py
new file mode 100644
index 0000000..bdcd26a
--- /dev/null
+++ b/xpdeint/Operators/_DeltaAOperator.py
@@ -0,0 +1,293 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_DeltaAOperator.py
+
+Created by Graham Dennis on 2008-01-01.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Operators.Operator import Operator
+from xpdeint.Geometry.FieldElement import FieldElement
+from xpdeint.Vectors.VectorElement import VectorElement
+from xpdeint.Vectors.VectorInitialisation import VectorInitialisation
+from xpdeint.Function import Function
+from xpdeint.Utilities import lazy_property
+
+from xpdeint.ParserException import ParserException
+
+from xpdeint import CodeParser
+
+class _DeltaAOperator (Operator):
+  evaluateOperatorFunctionArguments = [('real', '_step')]
+  operatorKind = Operator.DeltaAOperatorKind
+  
+  def __init__(self, *args, **KWs):
+    Operator.__init__(self, *args, **KWs)
+    
+    # Set default variables
+    self.integrationVectorsEntity = None
+    self.integrationVectors = set()
+    self.deltaAField = None
+    self.deltaAVectorMap = {}
+  
+  @lazy_property
+  def integrator(self):
+    # Our parent is an OperatorContainer, and its parent is the Integrator
+    return self.parent.parent
+  
+  def bindNamedVectors(self):
+    super(_DeltaAOperator, self).bindNamedVectors()
+    
+    if self.integrationVectorsEntity:
+      self.integrationVectors.update(self.vectorsFromEntity(self.integrationVectorsEntity))
+      
+      for integrationVector in self.integrationVectors:
+        if not integrationVector.field == self.field:
+          raise ParserException(self.integrationVectorsEntity.xmlElement, 
+                                "Cannot integrate vector '%s' in this operators element as it "
+                                "belongs to a different field" % integrationVector.name)
+        
+      self.dependencies.update(self.integrationVectors)
+  
+  
+  def preflight(self):
+    super(_DeltaAOperator, self).preflight()
+    
+    # Construct the operator components dictionary
+    for integrationVector in self.integrationVectors:
+      for componentName in integrationVector.components:
+        derivativeString = "d%s_d%s" % (componentName, self.propagationDimension)
+        
+        # Map of operator names to vector -> component list dictionary
+        self.operatorComponents[derivativeString] = {integrationVector: [componentName]}
+        
+        # Check that the user code block contains derivatives for every vector.
+        # If not, throw an exception.
+        
+        if not derivativeString in self.primaryCodeBlock.codeString:
+          raise ParserException(
+            self.primaryCodeBlock.xmlElement,
+            "Missing derivative for integration variable '%s' in vector '%s'." % (componentName, integrationVector.name)
+          )
+    
+    
+    
+    # Our job here is to consider the case where the user's integration code
+    # depends on a component of an integration vector which might get overwritten
+    # in the process of looping over the integration code. For example, if the
+    # user has code like:
+    # dx_dt[j] = x[j-1]
+    # then on the previous loop, x[j-1] will have been overwritten with
+    # dx_dt[j-1]*_step (due to the way the delta a operator works). Consequently,
+    # x[j-1] won't mean what the user think it means. This would be OK if the code
+    # was
+    # dx_dt[j] = x[j + 1]
+    # however we cannot safely know in all cases if j + 1 is greater than j or not.
+    #
+    # The solution will be to create an array to save all of the results for dx_dt
+    # and then copy the results back in to the x array.
+    #
+    # As an optimisation, we don't want to do this if all of the accesses for an
+    # integer valued dimension is with just the value of the dimension index.
+    # 
+    # Additionally, if we have an integer-valued dimension at the start that we
+    # need to fix this problem for, the array would need to be large enough to
+    # hold all of the dimensions after that dimension as well. To reduce the
+    # memory requirement for this, we will re-order the looping of the dimensions
+    # to put any integer-valued dimensions that need this special treatment as the
+    # innermost loops.
+    
+    dimRepNamesNeedingReordering = set()
+    
+    # Not all integration vectors may be forcing this reordering. For any that aren't,
+    # we can just do the normal behaviour. This saves memory.
+    self.vectorsForcingReordering = set()
+    
+    components = set()
+    derivativeMap = {}
+    propagationDimension = self.propagationDimension
+    basis = self.primaryCodeBlock.basis
+    dimRepNameMap = dict([(dimRep.name, dimRep) for dimRep in self.field.inBasis(basis)])
+    
+    for vector in self.integrationVectors:
+      components.update(vector.components)
+      for componentName in vector.components:
+        derivativeString = ''.join(['d', componentName, '_d', propagationDimension])
+        components.add(derivativeString)
+        derivativeMap[derivativeString] = vector
+    
+    indexAccessedVariables = CodeParser.nonlocalDimensionAccessForComponents(components, self.primaryCodeBlock)
+    
+    simulationDriver = self.getVar('features')['Driver']
+    
+    for componentName, resultDict, codeSlice in indexAccessedVariables:
+      
+      vectors = [v for v in self.integrationVectors if componentName in v.components]
+      
+      if len(vectors) == 1:
+        # Either our component belongs to one of the integration vectors
+        vector = vectors[0]
+      else:
+        # Or it is a derivative, and so the vector we should use is the one for the original component
+        vector = derivativeMap[componentName]
+      
+      # Add the dimension names that aren't being accessed with the dimension variable
+      # to the set of dimensions needing reordering.
+      dimRepNamesForThisVectorNeedingReordering = [dimRepName for dimRepName, (indexString, accessLoc) in resultDict.iteritems() if indexString != dimRepName]
+      
+      if vector.field.isDistributed:
+        distributedDimRepsNeedingReordering = set(
+          [dimRep.name for dimRep in self.field.inBasis(basis)
+                  if dimRep.hasLocalOffset]
+        ).intersection(dimRepNamesForThisVectorNeedingReordering)
+        if distributedDimRepsNeedingReordering:
+          # This vector is being accessed nonlocally on a dimension that is distributed. This isn't legal.
+          dimRepName = list(distributedDimRepsNeedingReordering)[0]
+          raise ParserException(self.xmlElement, 
+                                  "The dimension '%(dimRepName)s' cannot be accessed nonlocally because it is being distributed with MPI. "
+                                  "Try turning off MPI or re-ordering the dimensions in the <geometry> element." % locals())
+      
+      if dimRepNamesForThisVectorNeedingReordering:
+        # If we have any dimensions that need reordering for this vector, add them to the complete set
+        dimRepNamesNeedingReordering.update(dimRepNamesForThisVectorNeedingReordering)
+        # ... and add the vector itself to the set of vectors forcing this reordering.
+        self.vectorsForcingReordering.add(vector)
+        
+    
+    
+    # We now have all of the dimension names that need re-ordering to the end of the array.
+    # We only need to do our magic if this set is non-empty
+    if dimRepNamesNeedingReordering:
+      
+      # Now we need to construct a new field which has the same dimensions as self.field,
+      # but has the dimensions that need reordering at the end.
+      newFieldDimensions = self.field.dimensions[:]
+      
+      dimensionsNeedingReordering = []
+      
+      # Remove the dimensions needing reordering and replace them at the end
+      for dim in newFieldDimensions[:]:
+        if dim.inBasis(basis).name in dimRepNamesNeedingReordering:
+          newFieldDimensions.remove(dim)
+          newFieldDimensions.append(dim)
+          dimensionsNeedingReordering.append(dim)
+      
+      loopingFieldName = ''.join([self.integrator.name, '_', self.name, '_looping_field'])
+      
+      loopingField = FieldElement(name = loopingFieldName,
+                                  **self.argumentsToTemplateConstructors)
+      
+      loopingField.dimensions = [dim.copy(parent=loopingField) for dim in newFieldDimensions]
+      self.primaryCodeBlock.field = loopingField
+      
+      # Now construct a second field for the vector which will hold our delta a operators
+      deltaAFieldName = ''.join([self.integrator.name, '_', self.name, '_delta_a_field'])
+      
+      self.deltaAField = FieldElement(name = deltaAFieldName,
+                                      **self.argumentsToTemplateConstructors)
+      
+      self.deltaAField.dimensions = [dim.copy(parent = self.deltaAField) for dim in dimensionsNeedingReordering]
+      
+      propagationDimension = self.propagationDimension
+      
+      # For each integration vector forcing the reordering, we need to construct
+      # a corresponding vector in the new field.
+      for integrationVector in self.vectorsForcingReordering:
+        deltaAVector = VectorElement(
+          name = integrationVector.name, field = self.deltaAField,
+          parent = self, initialBasis = self.operatorBasis,
+          type = integrationVector.type,
+          **self.argumentsToTemplateConstructors
+        )
+        
+        # The vector will only need initialisation if the derivatives are accessed out
+        # of order, i.e. dphi_dt[j+1] for example. We can detect this later and change this
+        # if that is the case.
+        deltaAVector.needsInitialisation = False
+        # Construct dx_dt variables for the delta a vector.
+        deltaAVector.components = [''.join(['d', componentName, '_d', propagationDimension]) for componentName in integrationVector.components]
+        
+        # Make sure the vector gets allocated etc.
+        self._children.append(deltaAVector)
+        
+        # Make the vector available when looping
+        self.primaryCodeBlock.dependencies.add(deltaAVector)
+        
+        # Remove the components of the vector from our operatorComponents so that we won't get doubly-defined variables
+        for componentName in deltaAVector.components:
+          del self.operatorComponents[componentName]
+        
+        # Add the new delta a vector to the integration vector --> delta a vector map
+        self.deltaAVectorMap[integrationVector] = deltaAVector
+      
+    
+    # We need to rewrite all the derivatives to only use dimensions in the delta a field (if we have one)
+    # This needs to be done even if we don't have a delta-a field as otherwise writing dx_dt(j: j) wouldn't
+    # get transformed as dx_dt won't be vector.
+    indexAccessedDerivatives = CodeParser.nonlocalDimensionAccessForComponents(derivativeMap.keys(), self.primaryCodeBlock)
+    
+    for componentName, resultDict, codeSlice in reversed(indexAccessedDerivatives):
+      componentAccessString = componentName
+      componentAccesses = []
+      for dimRepName, (accessString, accessCodeLoc) in resultDict.iteritems():
+        if not dimRepName in dimRepNamesNeedingReordering:
+          continue
+        componentAccesses.append('%(dimRepName)s => %(accessString)s' % locals())
+      if componentAccesses:
+        componentAccessString += '(' + ','.join(componentAccesses) + ')'
+      
+      # If we have at least one dimension that is not being accessed with the correct index,
+      # we must initialise the delta a vector just in case. (See gravity.xmds for an example)
+      if any([resultDict[dimRepName][0] != dimRepName for dimRepName in resultDict if dimRepName in dimRepNamesNeedingReordering]):
+        # The integrationVector must be in the deltaAVectorMap because we would have had to allocate
+        # a delta-a vector for this integration vector.
+        deltaAVector = self.deltaAVectorMap[integrationVector]
+        if not deltaAVector.needsInitialisation:
+          deltaAVector.needsInitialisation = True
+          deltaAVector.initialiser = VectorInitialisation(parent = deltaAVector, **self.argumentsToTemplateConstructors)
+          deltaAVector.initialiser.vector = deltaAVector
+      
+      self.primaryCodeBlock.codeString = self.primaryCodeBlock.codeString[:codeSlice.start] + componentAccessString \
+                                        + self.primaryCodeBlock.codeString[codeSlice.stop:]
+      
+    if self.deltaAField:
+      copyDeltaAFunctionName = ''.join(['_', self.id, '_copy_delta_a'])
+      loopingField = self.primaryCodeBlock.field
+      arguments = [('real', '_step')]
+      deltaAFieldReps = self.deltaAField.inBasis(self.operatorBasis)
+      arguments.extend([('long', '_' + dimRep.name + '_index') \
+                            for dimRep in loopingField.inBasis(self.operatorBasis) if not dimRep in deltaAFieldReps])
+      copyDeltaAFunction = Function(name = copyDeltaAFunctionName,
+                                    args = arguments,
+                                    implementation = self.copyDeltaAFunctionContents,
+                                    returnType = 'inline void')
+      self.functions['copyDeltaA'] = copyDeltaAFunction
+      
+      # Create arguments dictionary for a call to the copyDeltaA function
+      arguments = dict([('_' + dimRep.name + '_index', dimRep.loopIndex) \
+                          for dimRep in loopingField.inBasis(self.operatorBasis) if not dimRep in deltaAFieldReps])
+      functionCall = self.functions['copyDeltaA'].call(parentFunction = self.functions['evaluate'], arguments = arguments) + '\n'
+      self.primaryCodeBlock.loopArguments['postDimensionLoopClosingCode'] = {
+        self.deltaAField.dimensions[0].inBasis(self.operatorBasis).name: functionCall
+      }
+      
+    
+  
+  
+
diff --git a/xpdeint/Operators/_EXOperator.py b/xpdeint/Operators/_EXOperator.py
new file mode 100644
index 0000000..eef00b7
--- /dev/null
+++ b/xpdeint/Operators/_EXOperator.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_EXOperator.py
+
+Created by Graham Dennis on 2008-02-21.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Operators.Operator import Operator
+from xpdeint.ParserException import parserWarning
+
+from xpdeint import CodeParser
+
+class _EXOperator(Operator):
+  evaluateOperatorFunctionArguments = []
+  
+  operatorKind = Operator.OtherOperatorKind
+  
+  def preflight(self):
+    super(_EXOperator, self).preflight()
+    
+    for operatorName in self.operatorNames:
+      self.operatorComponents[operatorName] = {}
+    
+    operatorNamesUsed = set()
+    operatorNames = set(self.operatorNames)
+    sharedCodeBlock = self.parent.sharedCodeBlock
+    
+    operatorTargetPairs = CodeParser.targetComponentsForOperatorsInString(self.operatorNames, sharedCodeBlock)
+    
+    targetComponents = set()
+    for vector in sharedCodeBlock.dependencies:
+      targetComponents.update(vector.components)
+    
+    indexAccessedVariables = None
+    
+    # We loop over this in reverse order as we will be modifying the code string. So in order to not have to
+    # re-run targetComponentsForOperatorsInString after each modification, we loop over the operatorTargetPairs in
+    # reverse order so that slices (character index ranges) for earlier operator-target pairs don't change
+    for operatorName, target, codeSlice in reversed(operatorTargetPairs):
+      operatorNamesUsed.add(operatorName)
+      
+      # Target is what is inside the square brackets in the integration code block
+      
+      # As this is the EX operator, we have fewer constraints.
+      # If the target matches something of the form 'phi' or 'phi[j+3, k*k][m % 3, n]'
+      # Then we don't need to use our result vector to make 'phi' available to the operator
+      # If it doesn't match, then we have to assume that the expression is well formed, and
+      # copy it into the result vector then fourier transform it into the space of the operator
+      targetVector = None
+      replacementStringSuffix = ''
+      
+      if target in targetComponents:
+        targetComponentName = target
+        # We have direct access to the component, so just work out which vector it belongs to
+        # Now we need to get the vector corresponding to componentName
+        tempVectorList = [v for v in sharedCodeBlock.dependencies if targetComponentName in v.components]
+        assert len(tempVectorList) == 1
+        targetVector = tempVectorList[0]
+      else:
+        # The target of our EX operator isn't a simple component.
+        # In principle, this could be OK. We just need to construct the variable using the result vector.
+        # If the user has made a mistake with their code, the compiler will barf, not xpdeint. This isn't ideal
+        # but we can't understand an arbitrary string; that's what the compiler is for.
+        
+        targetComponentName = sharedCodeBlock.addCodeStringToSpecialTargetsVector(target, codeSlice)
+        targetVector = sharedCodeBlock.specialTargetsVector
+      
+      # We have our match, now we need to create the operatorComponents dictionary
+      if not operatorName in self.operatorComponents:
+        self.operatorComponents[operatorName] = {}
+      
+      if not targetVector in self.operatorComponents[operatorName]:
+        self.operatorComponents[operatorName][targetVector] = [targetComponentName]
+      elif not targetComponentName in self.operatorComponents[operatorName][targetVector]:
+        self.operatorComponents[operatorName][targetVector].append(targetComponentName)
+      
+      if targetVector.type == 'complex':
+        for v in [self.operatorVector, self.resultVector]:
+          if v: v.type = 'complex'
+      
+      # Set the replacement string for the L[x] operator
+      replacementString = "_%(operatorName)s_%(targetComponentName)s" % locals()
+        
+      
+      sharedCodeBlock.codeString = sharedCodeBlock.codeString[:codeSlice.start] + replacementString + sharedCodeBlock.codeString[codeSlice.stop:]
+    
+    # If any operator names weren't used in the code, issue a warning
+    unusedOperatorNames = operatorNames.difference(operatorNamesUsed)
+    if unusedOperatorNames:
+      unusedOperatorNamesString = ', '.join(unusedOperatorNames)
+      parserWarning(self.xmlElement,
+                    "The following EX operator names were declared but not used: %(unusedOperatorNamesString)s" % locals())
+    
+    # Iterate over the operator components adding the appropriate bits to the resultVector, but do it in
+    # the order of the components in the targetVectors to make it easier to optimise out an FFT.
+    for operatorName, operatorDict in self.operatorComponents.iteritems():
+      for targetVector, targetVectorUsedComponents in operatorDict.iteritems():
+        for targetComponent in targetVector.components:
+          if targetComponent in targetVectorUsedComponents:
+            self.resultVector.components.append("_%(operatorName)s_%(targetComponent)s" % locals())
+    
+    if self.resultVector.nComponents == 0:
+      self.resultVector.remove()
+      self.resultVector = None
+    
+    # Add the result vector to the shared dependencies for the operator container
+    # These dependencies are just the delta a dependencies, so this is just adding
+    # our result vector to the dependencies for the delta a operator
+    if self.resultVector:
+      sharedCodeBlock.dependencies.add(self.resultVector)
+    
+    # If we are nonconstant then we need to add the target vectors to the dependencies of our primary code block
+    if not 'calculateOperatorField' in self.functions:
+      self.primaryCodeBlock.dependencies.update(self.targetVectors)
+    
+    vectors = set(self.targetVectors)
+    vectors.add(self.resultVector)
+    self.registerVectorsRequiredInBasis(vectors, self.operatorBasis)
+    
diff --git a/xpdeint/Operators/_FilterOperator.py b/xpdeint/Operators/_FilterOperator.py
new file mode 100644
index 0000000..90d38c3
--- /dev/null
+++ b/xpdeint/Operators/_FilterOperator.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_FilterOperator.py
+
+Created by Graham Dennis on 2008-01-01.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Operators.Operator import Operator
+from xpdeint.Geometry.FieldElement import FieldElement
+
+from xpdeint.Utilities import lazy_property
+
+class _FilterOperator (Operator):
+  # Filter operators must cause their computed vectors to be re-evaluated
+  # as one filter operator could easily change the value of a computed vector
+  # (think renormalisation)
+  dynamicVectorsNeedingPrecalculation = []
+  
+  evaluateOperatorFunctionArguments = []
+  operatorKind = Operator.OtherOperatorKind
+  vectorsMustBeInSubsetsOfIntegrationField = False
+  
+  @lazy_property
+  def field(self):
+    return self.primaryCodeBlock.field
+  
+  def bindNamedVectors(self):
+    super(_FilterOperator, self).bindNamedVectors()
+    
+    dimensionNames = set()
+    for dependency in self.dependencies:
+      dimensionNames.update([dim.name for dim in dependency.field.dimensions])
+    
+    codeBlock = self.primaryCodeBlock
+    codeBlock.field = FieldElement.sortedFieldWithDimensionNames(dimensionNames)
+    
+    if codeBlock.dependenciesEntity and codeBlock.dependenciesEntity.xmlElement.hasAttribute('basis'):
+      codeBlock.basis = \
+        codeBlock.field.basisFromString(
+          codeBlock.dependenciesEntity.xmlElement.getAttribute('basis'),
+          xmlElement = codeBlock.dependenciesEntity.xmlElement
+        )
+    if not codeBlock.basis:
+      codeBlock.basis = codeBlock.field.defaultCoordinateBasis
+  
+
+
diff --git a/xpdeint/Operators/_IPOperator.py b/xpdeint/Operators/_IPOperator.py
new file mode 100644
index 0000000..f78db74
--- /dev/null
+++ b/xpdeint/Operators/_IPOperator.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_IPOperator.py
+
+Created by Graham Dennis on 2008-02-20.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Operators.Operator import Operator
+from xpdeint.ParserException import ParserException, parserWarning
+
+from xpdeint import CodeParser
+from xpdeint.Utilities import lazy_property
+
+class _IPOperator(Operator):
+  evaluateOperatorFunctionArguments = [('int', '_exponent')]
+  operatorKind = Operator.IPOperatorKind
+  expFunction = 'exp'
+  valueSuffix = ''
+  
+  @lazy_property
+  def integrator(self):
+    # Our parent is an OperatorContainer, and its parent is the Integrator
+    return self.parent.parent
+  
+  def preflight(self):
+    super(_IPOperator, self).preflight()
+    
+    for operatorName in self.operatorNames:
+      self.operatorComponents[operatorName] = {}
+    
+    sharedCodeBlock = self.parent.sharedCodeBlock
+    operatorTargetPairs = CodeParser.targetComponentsForOperatorsInString(self.operatorNames, sharedCodeBlock)
+    
+    operatorNamesUsed = set()
+    operatorNames = set(self.operatorNames)
+    
+    integrationVectors = self.parent.deltaAOperator.integrationVectors
+    field = self.field
+    
+    legalTargetComponentNames = set()
+    for v in integrationVectors:
+      legalTargetComponentNames.update(v.components)
+    
+    targetComponentNamesUsed = set()
+    
+    indexAccessedVariables = None
+    
+    # We loop over this in reverse order as we will be modifying the code string. So in order to not have to
+    # re-run targetComponentsForOperatorsInString after each modification, we loop over the operatorTargetPairs in
+    # reverse order so that slices (character index ranges) for earlier operator-target pairs don't change
+    for operatorName, target, codeSlice in reversed(operatorTargetPairs):
+      operatorNamesUsed.add(operatorName)
+      
+      # Target is what is inside the square brackets in the integration code block
+      
+      # As this is the IP operator, we have a few additional constraints
+      # Firstly, the targets must be of the form 'phi' or 'phi[j,k][m,n]'
+      # where j, k, m, n are the names of the integer dimension
+      
+      if target in legalTargetComponentNames:
+        # Everything is OK
+        componentName = target
+      else:
+        if indexAccessedVariables == None:
+          indexAccessedVariables = CodeParser.nonlocalDimensionAccessForVectors(integrationVectors, sharedCodeBlock)
+        
+        try:
+          # This will extract the componentName corresponding to the indexed variable in the target
+          # or it will fail because it isn't of that form.
+          componentName, resultDict = [(l[0], l[2]) for l in indexAccessedVariables if sharedCodeBlock.codeString[l[3]] == target][0]
+        except IndexError:
+          # Target didn't match something of the form 'phi[j, k][m+3,n-9]'
+          raise ParserException(self.xmlElement,
+                                "IP operators can only act on components of integration vectors. "
+                                "The '%(operatorName)s' operator acting on '%(target)s' doesn't seem to be of the right form "
+                                "or '%(target)s' isn't in one of the integration vectors."
+                                % locals())
+        
+        # Check that nonlocally-accessed dimensions are being accessed with the dimension names
+        # i.e. of the form 'phi(j: j, k:k, m:m, n:n)' not 'phi(j: j-7, k: k*2, m: 3, n: n+1)'
+        for dimName, (indexString, codeSlice) in resultDict.iteritems():
+          if not dimName == indexString:
+            raise ParserException(self.xmlElement,
+                                  "IP operators can only act on every value of a dimension. "
+                                  "The problem was caused by the '%(operatorName)s' operator acting on '%(target)s'. "
+                                  "EX operators do not have this restriction."
+                                  % locals())
+      
+      if componentName in targetComponentNamesUsed:
+        raise ParserException(self.xmlElement,
+                              "Check the documentation, only one IP operator can act on a given component, "
+                              "and this operator can only appear once. "
+                              "The problem was with the '%(componentName)s' term appearing more than once in an IP operator. "
+                              "You may be able to accomplish what you are trying with an EX operator."
+                              % locals())
+      
+      targetComponentNamesUsed.add(componentName)
+      
+      # Now we need to get the vector corresponding to componentName
+      tempVectorList = [v for v in integrationVectors if componentName in v.components]
+      assert len(tempVectorList) == 1
+      targetVector = tempVectorList[0]
+      
+      # We have our match, now we need to create the operatorComponents dictionary
+      if not targetVector in self.operatorComponents[operatorName]:
+        self.operatorComponents[operatorName][targetVector] = [componentName]
+      else:
+        self.operatorComponents[operatorName][targetVector].append(componentName)
+      
+      if targetVector.type == 'real':
+        self.operatorVector.type = 'real'
+      
+      
+      # Check the sanity of the integration code.
+      # i.e. check that we don't have something of the form:
+      # dy_dt = L[x].
+      # Obviously the user could hide this from us, but if we can check the most
+      # common case that frequently goes wrong, then we should.
+      
+      CodeParser.performIPOperatorSanityCheck(componentName, self.propagationDimension, codeSlice, sharedCodeBlock)
+      
+      # Replace the L[x] string with 0.0
+      sharedCodeBlock.codeString = sharedCodeBlock.codeString[:codeSlice.start] + '0.0' + sharedCodeBlock.codeString[codeSlice.stop:]
+    
+    
+    # If any operator names weren't used in the code, issue a warning
+    unusedOperatorNames = operatorNames.difference(operatorNamesUsed)
+    if unusedOperatorNames:
+      unusedOperatorNamesString = ', '.join(unusedOperatorNames)
+      parserWarning(self.xmlElement,
+                    "The following operator names weren't used: %(unusedOperatorNamesString)s" % locals())
+    
+    vectors = set(self.targetVectors)
+    self.registerVectorsRequiredInBasis(vectors, self.operatorBasis)
+    
+  
+
+
diff --git a/xpdeint/Operators/_Operator.py b/xpdeint/Operators/_Operator.py
new file mode 100644
index 0000000..aec088f
--- /dev/null
+++ b/xpdeint/Operators/_Operator.py
@@ -0,0 +1,165 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_Operator.py
+
+This contains all the pure-python code for Operator.tmpl
+
+Created by Graham Dennis on 2007-10-18.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.ScriptElement import ScriptElement
+from xpdeint.ParserException import ParserException
+
+from xpdeint.Function import Function
+from xpdeint.Utilities import lazy_property
+from xpdeint.CallOnceGuards import callOncePerInstanceGuard
+
+class _Operator (ScriptElement):
+  # This is an ordered list of (type, argName) pairs
+  evaluateOperatorFunctionArguments = []
+  
+  # Operator kinds
+  IPOperatorKind     = 1
+  OtherOperatorKind  = 2
+  DeltaAOperatorKind = 3
+  
+  operatorKind = OtherOperatorKind
+  
+  vectorsMustBeInSubsetsOfIntegrationField = True
+  
+  def __init__(self, *args, **KWs):
+    localKWs = self.extractLocalKWs(['name'], KWs)
+    ScriptElement.__init__(self, *args, **KWs)
+    
+    # Set default variables
+    self.dependenciesEntity = None
+    self.operatorComponents = {}
+    self.operatorVector = None
+    self.resultVector = None
+    self.operatorNumber = -1
+    
+    # the name is only used for filter operators, which default to a normal segment object if not named in the XML
+    self._name = None
+    if localKWs:
+        self._name = localKWs['name']
+    
+    parent = self.parent
+    parent.addOperator(self)
+    if self._name:
+        evaluateOperatorFunctionName = self._name
+    else:
+        evaluateOperatorFunctionName = ''.join(['_', parent.id, '_evaluate_', self.name])
+    evaluateOperatorFunction = Function(name = evaluateOperatorFunctionName,
+                                        args = self.evaluateOperatorFunctionArguments,
+                                        implementation = self.evaluateOperatorFunctionContents,
+                                        description = self.description())
+    self.functions['evaluate'] = evaluateOperatorFunction
+    if hasattr(self, 'calculateOperatorFieldFunctionArguments'):
+      calculateOperatorFieldFunctionName = ''.join(['_', parent.id, '_calculate_', self.name, '_field'])
+      calculateOperatorFieldFunction = Function(name = calculateOperatorFieldFunctionName, 
+                                                args = self.calculateOperatorFieldFunctionArguments,
+                                                implementation = self.calculateOperatorFieldFunctionContents,
+                                                description = self.description())
+      self.functions['calculateOperatorField'] = calculateOperatorFieldFunction
+    
+  
+  # The children
+  @property
+  def children(self):
+    # Return either or both of operatorVector and resultVector
+    # depending on whether or not they are 'None'
+    children = super(_Operator, self).children
+    children.extend(filter(lambda x: x, [self.operatorVector, self.resultVector]))
+    return children
+  
+  @lazy_property
+  def name(self):
+    return 'operator' + str(self.operatorNumber)
+  
+  @property
+  def targetVectors(self):
+    targetVectors = set()
+    
+    # Loop over the vectors that the operators are going to operate on
+    for targetVectorDict in self.operatorComponents.itervalues():
+      targetVectors.update(set(targetVectorDict.keys()))
+    
+    return targetVectors
+  
+  @lazy_property
+  def calculateOperatorFieldFunctionArgumentString(self):
+    return ', '.join([pair[0] + ' ' + pair[1] for pair in self.calculateOperatorFieldFunctionArguments])
+  
+  @lazy_property
+  def evaluateOperatorFunctionArgumentString(self):
+    return ', '.join([pair[0] + ' ' + pair[1] for pair in self.evaluateOperatorFunctionArguments])
+  
+  @lazy_property
+  def dynamicVectorsNeedingPrecalculation(self):
+    vectorSet = self.dependencies.copy()
+    vectorSet.update(self.targetVectors)
+    return filter(lambda x: x.isComputed or x.isNoise, vectorSet)
+  
+  @lazy_property
+  def primaryCodeBlock(self):
+    return self.codeBlocks['operatorDefinition']
+  
+  @property
+  def dependencies(self):
+    return self.primaryCodeBlock.dependencies
+  
+  @property
+  def operatorBasis(self):
+    return self.primaryCodeBlock.basis
+  
+  @lazy_property
+  def field(self):
+    return self.parent.field
+  
+  def preflight(self):
+    super(_Operator, self).preflight()
+    
+    if self.primaryCodeBlock.dependenciesEntity:
+      # If this operator has dependencies, then the integrator cannot be initialised early.
+      # This only affects the multi-path drivers, which try to initialise integrators once
+      # per node, rather than once per path.  The following code disables this optimisation
+      # in this situation
+      if self.operatorVector:
+        self.parent.parent.canBeInitialisedEarly = False
+      for dependency in self.primaryCodeBlock.dependencies:
+        if self.vectorsMustBeInSubsetsOfIntegrationField and not dependency.field.isSubsetOfField(self.field):
+          raise ParserException(self.primaryCodeBlock.dependenciesEntity.xmlElement,
+                  "Can't depend on a vector that is in a field that has dimensions that "
+                  "aren't in this field (%s).\n"
+                  "The vector causing this problem is '%s'." 
+                  % (self.field.name, dependency.name))
+    
+  
+  @callOncePerInstanceGuard
+  def allocate(self):   return super(_Operator, self).allocate()
+  @callOncePerInstanceGuard
+  def free(self):       return super(_Operator, self).free()
+  
+  @callOncePerInstanceGuard
+  def initialise(self): return super(_Operator, self).initialise()
+  @callOncePerInstanceGuard
+  def finalise(self):   return super(_Operator, self).finalise()
+  
+  
diff --git a/xpdeint/Operators/_SICDeltaAOperator.py b/xpdeint/Operators/_SICDeltaAOperator.py
new file mode 100644
index 0000000..8ead795
--- /dev/null
+++ b/xpdeint/Operators/_SICDeltaAOperator.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_SICDeltaAOperator.py
+
+Created by Graham Dennis on 2008-08-07.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Operators.DeltaAOperator import DeltaAOperator
+
+from xpdeint.ParserException import ParserException
+
+class _SICDeltaAOperator (DeltaAOperator):
+  def __init__(self, *args, **KWs):
+    DeltaAOperator.__init__(self, *args, **KWs)
+    
+    # Set default variables
+    self.crossPropagationDimension           = None
+    self.crossPropagationDirection           = None
+    self.crossIntegrationVectors             = set()
+    self.crossIntegrationVectorsEntity       = None
+    
+  
+  @property
+  def integrator(self):
+    # Our parent is the operator container, and its parent is the integrator
+    return self.parent.parent
+  
+  def bindNamedVectors(self):
+    super(_SICDeltaAOperator, self).bindNamedVectors()
+    
+    self.primaryCodeBlock.dependencies.update(self.codeBlocks['boundaryCondition'].dependencies)
+    self.primaryCodeBlock.dependencies.update(self.codeBlocks['crossPropagation'].dependencies)
+    
+    if self.crossIntegrationVectorsEntity:
+      self.crossIntegrationVectors.update(self.vectorsFromEntity(self.crossIntegrationVectorsEntity))
+      if self.integrationVectors.intersection(self.crossIntegrationVectors):
+        badVectors = self.integrationVectors.intersection(self.crossIntegrationVectors)
+        raise ParserException(self.crossIntegrationVectorsEntity.xmlElement,
+                              "Can't have a vector being integrated by both a cross-propagator and an integration block.\n"
+                              "The vectors causing the problems are: %s" % ', '.join([v.name for v in badVectors]))
+      self.dependencies.update(self.crossIntegrationVectors)
+      
+  
+  
+  def preflight(self):
+    super(_SICDeltaAOperator, self).preflight()
+    # Construct the operator components dictionary for the cross-propagation vectors
+    for crossIntegrationVector in self.crossIntegrationVectors:
+      for componentName in crossIntegrationVector.components:
+        derivativeString = "d%s_d%s" % (componentName, self.crossPropagationDimension)
+        
+        # Map of operator names to vector -> component list dictionary
+        self.operatorComponents[derivativeString] = {crossIntegrationVector: [componentName]}
+    
+    crossDimRep = self.loopingField.dimensionWithName(self.crossPropagationDimension).inBasis(self.operatorBasis)
+    crossPropDimOverrides = [(v.field, crossDimRep.loopIndex) for v in self.codeBlocks['crossPropagation'].dependencies 
+                                if v.field.hasDimensionName(self.crossPropagationDimension)]
+    
+    self.codeBlocks['crossPropagation'].loopArguments['indexOverrides'] = \
+      {self.crossPropagationDimension: crossPropDimOverrides}
+    
+    
diff --git a/xpdeint/Operators/__init__.py b/xpdeint/Operators/__init__.py
new file mode 100644
index 0000000..792d600
--- /dev/null
+++ b/xpdeint/Operators/__init__.py
@@ -0,0 +1 @@
+#
diff --git a/xpdeint/ParsedEntity.py b/xpdeint/ParsedEntity.py
new file mode 100644
index 0000000..80e484b
--- /dev/null
+++ b/xpdeint/ParsedEntity.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+ParsedEntity.py
+
+Created by Graham Dennis on 2008-01-01.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Utilities import lazy_property
+
+class ParsedEntity(object):
+  def __init__(self, xmlElement, value):
+    self.xmlElement = xmlElement
+    self.value = value
+  
+  @lazy_property
+  def scriptLineNumber(self):
+    return self.xmlElement.lineNumberForCDATASection()
+  
+
diff --git a/xpdeint/ParserException.py b/xpdeint/ParserException.py
new file mode 100644
index 0000000..a19c6b6
--- /dev/null
+++ b/xpdeint/ParserException.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+ParserException.py
+
+Created by Graham Dennis on 2007-10-14.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+import sys
+import textwrap
+
+def indentMessageWithPrefix(prefix, msg):
+    textWrapper = textwrap.TextWrapper(subsequent_indent=' '*len(prefix))
+    msgLines = msg.split('\n\n')
+    result = [textWrapper.fill(prefix + msgLines[0])]
+    textWrapper.initial_indent = ' '*len(prefix)
+    result.extend([textWrapper.fill(line) for line in msgLines[1:]])
+    return '\n'.join(result)
+
+
+class ParserException(Exception):
+    def __init__(self, element, msg):
+        
+        self.msg = indentMessageWithPrefix('ERROR: ', msg)
+        self.element = element
+        
+        self.lineNumber = self.columnNumber = None
+        
+        if self.element:
+            self.lineNumber = self.element.getUserData('lineNumber')
+            self.columnNumber = self.element.getUserData('columnNumber')
+
+warningsGiven = set()
+
+def parserWarning(element, msg):
+    try:
+        lineNumber, columnNumber = element
+    except (TypeError, ValueError), err:
+        lineNumber = element.getUserData('lineNumber')
+        columnNumber = element.getUserData('columnNumber')
+    if (lineNumber, columnNumber, msg) in warningsGiven: return
+    warningsGiven.add((lineNumber, columnNumber, msg))
+    print >> sys.stderr, indentMessageWithPrefix('WARNING: ', msg)
+    print >> sys.stderr, "    At line %(lineNumber)i, column %(columnNumber)i" % locals()
+    # print >> sys.stderr, "    In element: " + element.userUnderstandableXPath()
+
diff --git a/xpdeint/Preferences.py b/xpdeint/Preferences.py
new file mode 100755
index 0000000..1529ca5
--- /dev/null
+++ b/xpdeint/Preferences.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+# encoding: utf-8
+import os
+
+versionString = '2.1.4 "Well if this isn\'t nice, I don\'t know what is"'
+
+if 'XMDS_USER_DATA' in os.environ:
+    xpdeintUserDataPath = os.environ['XMDS_USER_DATA']
+else:
+    xpdeintUserDataPath = os.path.join(os.path.expanduser('~'), '.xmds')
diff --git a/xpdeint/PrintfSafeFilter.py b/xpdeint/PrintfSafeFilter.py
new file mode 100644
index 0000000..4a1ad8e
--- /dev/null
+++ b/xpdeint/PrintfSafeFilter.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+PrintfSafeFilter.py
+
+Created by Graham Dennis on 2007-09-23.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from Cheetah.Filters import Filter
+
+class PrintfSafeFilter(Filter):
+  """Escape C string and format string entities in $placeholders
+  """
+  def filter(self, val, **kw):
+    s = super(PrintfSafeFilter, self).filter(val, **kw)
+    s = s.replace("\\", "\\\\")   # Escape single backslashes
+    s = s.replace("%", "%%")      # Escape format-string specifiers
+    s = s.replace("\"", "\\\"")   # Escape double-quotes
+    # We're done
+    return s
diff --git a/xpdeint/Python24Support.py b/xpdeint/Python24Support.py
new file mode 100644
index 0000000..42526c7
--- /dev/null
+++ b/xpdeint/Python24Support.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+Python24Support.py
+
+Created by Graham Dennis on 2008-07-16.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+This module adds missing features from python 2.4 that are
+available in later versions which xpdeint depends on.
+"""
+
+import sys
+module = type(sys)
+
+try:
+  import functools
+except ImportError, err:
+  functools = module('functools')
+  sys.modules['functools'] = functools
+  # Functools function decorator
+  def wraps(f):
+    def decorator(fn):
+      return fn
+    return decorator
+  
+  functools.wraps = wraps
+  
+
+try:
+  all = sys.modules['__builtin__'].all
+except AttributeError, err:
+  def all(iter):
+    for element in iter:
+      if not element:
+        return False
+    return True
+  sys.modules['__builtin__'].all = all
+
+try:
+  any = sys.modules['__builtin__'].any
+except AttributeError, err:
+  def any(iter):
+    for element in iter:
+      if element:
+        return True
+    return False
+  sys.modules['__builtin__'].any = any
+  
+
+try:
+  import hashlib
+except ImportError, err:
+  hashlib = module('hashlib')
+  sys.modules['hashlib'] = hashlib
+  from sha import new as sha1
+  hashlib.sha1 = sha1
+
diff --git a/xpdeint/RegularExpressionStrings.py b/xpdeint/RegularExpressionStrings.py
new file mode 100644
index 0000000..4afd75a
--- /dev/null
+++ b/xpdeint/RegularExpressionStrings.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+RegularExpressionStrings.py
+
+Created by Graham Dennis on 2008-02-20.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+import re
+
+# integer regular expression string
+integer = r'[-+]?[0-9]+'
+
+# domain pair ( something, somethingElse) regular expression string
+domainPair = r'\(\s*(\S+),\s*(\S+)\s*\)'
+
+def integersInString(string):
+  """
+  Return a list of the integers in `string`.
+  """
+  integerRegex = re.compile(r'\b' + integer + r'\b')
+  results = integerRegex.findall(string)
+  # Convert captured strings into integers
+  return [int(result) for result in results]
+
+def integerInString(string):
+  """
+  Return the single integer in `string`.
+  
+  If there is more than one integer in this string (as determined by `integersInString`),
+  this method will raise a `ValueError` exception.
+  """
+  results = integersInString(string)
+  if len(results) > 1:
+    raise ValueError('Too many integers')
+  elif len(results) == 0:
+    raise ValueError('No integers found')
+  return results[0]
+  
diff --git a/xpdeint/ScriptElement.py b/xpdeint/ScriptElement.py
new file mode 100644
index 0000000..d526958
--- /dev/null
+++ b/xpdeint/ScriptElement.py
@@ -0,0 +1,1127 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint._ScriptElement import _ScriptElement
+from xpdeint.CallOnceGuards import callOnceGuard
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.610259
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/ScriptElement.tmpl'
+__CHEETAH_srcLastModified__ = 'Mon Jul 23 09:42:26 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class ScriptElement(_ScriptElement):
+    """
+    This class provides all of the various loop constructs that are needed in the generated code.
+      Currently, this class provides three different types of loop with differing levels of complexity:
+      
+      1.  `loopOverVectorsWithInnerContentTemplate`: This is the most basic form of a loop.
+          This loop construct is for the occasions where you want to do the same operation to
+          every component of a bunch of vectors. The perfect example of this case is in the 
+          integrators where a derivative for each vector component has been calculated, and that
+          needs to be added to the original vector in some way. Note that the operation performed
+          by this loop must perform the same operation to the real and imaginary parts of a complex
+          vector.
+          
+          This function generates one loop per vector, and the form of the loop generated for each vector is::
+          
+            for (long _i0 = 0; _i0 < _size_of_vector; _i0++) {
+              // contents of loop
+            }
+          
+          As the exact contents of the loops will be different for each vector as each vector has a
+          different array name, and a different size, instead of providing the exact contents of the loop,
+          you provide a Cheetah template string for the loop contents describing the loop contents.
+          
+          Due to the very simple nature of this loop, it can be threaded quite easily using the OpenMP
+          feature (if it is turned on), or the code modified to make most compilers' auto-vectorisation
+          features vectorise the code (if the auto-vectorisation feature is turned on).
+          
+      2.  `loopOverVectorsInSpaceWithInnerContent`: This one is slightly more complex than the previous type,
+          and so has slightly different restrictions. This loop construct is for the occasions where you want
+          to do the same operation at each point, but possibly different operations to different components.
+          An additional restriction for this loop construct is that all of the vectors must be in the same
+          field. This is because unlike the previous loop construct, only one loop is created, and all of
+          the vectors are made available in that loop. This loop construct also creates ``#define``s for
+          components of vectors, but only the ``phi`` form, not the integer-valued ``phi[i, j]`` form as
+          well.
+          
+          The form of the loop generated by this function is::
+          
+            // #define's and creation of index pointers for each vector
+            for (long _i0 = 0; _i0 < _size_of_field_all_vectors_are_in; _i0++) {
+              // contents of loop
+              
+              // increment each vector's index pointer by the number of components in the vector.
+            }
+          
+          For this loop construct, the contents of the loop are simply transplanted inside the loop, i.e.
+          it isn't interpreted as a Cheetah template string.
+          
+          As this loop can contain arbitrary operations on complex vectors, this loop cannot be auto-vectorised.
+          However, it can still be threaded with the OpenMP feature.
+         
+      3. `loopOverFieldInBasisWithVectorsAndInnerContent`: By far the most powerful loop construct available.
+         This is the loop construct you want with user-provided code. It allows you to loop over all of the 
+         dimensions of a given field in a given space (arbitrary combination of fourier and non-fourier space),
+         making various vectors available which may or may not come from the same field as the looping field.
+         This loop construct can be used for integrating over dimensions for moments, sub-sampling, etc.
+         
+         This function supports a number of optional arguments to enable customisation of the generated loops.
+         As this loop could contain arbitrary code, it can neither be vectorised nor threaded using OpenMP.
+         
+         See the documentation of the function for more details.
+         
+      
+      
+      Although this class might look a bit like black magic, I promise that it is not self-aware, and
+      probably won't take over the universe. However, should it attempt to do so, I'll provide a copy of the 3
+      laws for its own reference:
+      
+      1.  xpdeint may not injure a user or, through inaction, allow a user to come to harm.
+      
+      2.  xpdeint must obey orders given to it by the user, except where such orders would conflict with the First Law.
+      
+      3.  xpdeint must protect its own existence as long as such protection does not conflict with the First or Second Law.
+    """
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(ScriptElement, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def loopOverVectorsWithInnerContentTemplate(self, vectors, templateString, basis=None, **KWS):
+
+
+        """
+        Insert code to loop over a vector.
+        
+        The contents of the loop are specified by a Cheetah template string,
+        which has the following variables available:
+        
+          - ``$vector``:   The current vector
+          - ``$index``:   The index variable name
+        
+        A simple example for the contents of this loop would be (passed as a `templateString`)::
+        
+          _active_${vector.id}[${index}] $operation;
+        
+        Where ``$operation`` is some operation. If the `templateString` does not end with a new line,
+        then one is added automatically.
+        
+        The intention is that this function is to be used when you have a very simple operation
+        to be performed in the same way on a range of vectors in possibly different fields.
+        """
+
+        ## CHEETAH: generated from @def loopOverVectorsWithInnerContentTemplate($vectors, $templateString, $basis = None) at line 101, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        assert len(VFFSL(SL,"templateString",True)) > 0
+        # 
+        templateFeatureOrdering = ['AutoVectorise']
+        dict = {'templateString': VFFSL(SL,"templateString",True),                'originalTemplateString': VFFSL(SL,"templateString",True),                'loopCountPrefixFunction': None,                'templateFunctions': []}
+        VFFSL(SL,"insertCodeForFeatures",False)('loopOverVectorsWithInnerContentTemplateModifyTemplate',
+                                 VFFSL(SL,"templateFeatureOrdering",True),
+                                 VFFSL(SL,"dict",True))
+        templateString = dict['templateString']
+        #  If the loopCountPrefixFunction is None, then provide an empty default
+        loopCountPrefixFunction = dict['loopCountPrefixFunction'] or (lambda v: '')
+        # 
+        #  The template string should end with a new line, if it doesn't we'll add it
+        if VFFSL(SL,"templateString",True)[-1] != '\n': # generated from line 136, col 3
+            templateString = VFFSL(SL,"templateString",True) + '\n'
+        # 
+        templateString += '\n'.join(dict['templateFunctions'])
+        # 
+        templateVariables = {'index': '_i0'}
+        innerLoopTemplate = VFFSL(SL,"templateObjectFromStringWithTemplateVariables",False)(VFFSL(SL,"templateString",True), VFFSL(SL,"templateVariables",True))
+        # 
+        loopFeatureOrdering = ['AutoVectorise', 'OpenMP']
+        VFFSL(SL,"dict",True)['extraIndent'] = 0
+        VFFSL(SL,"dict",True)['template'] = VFFSL(SL,"innerLoopTemplate",True)
+        for vector in VFFSL(SL,"vectors",True): # generated from line 148, col 3
+            # 
+            #  Get the loopCountPrefix from the loopCountPrefixFunction
+            loopCountPrefix = VFFSL(SL,"loopCountPrefixFunction",False)(VFFSL(SL,"vector",True))
+            # 
+            #  Set the template's current vector
+            VFFSL(SL,"templateVariables",True)['vector'] = VFFSL(SL,"vector",True)
+            _v = VFFSL(SL,"insertCodeForFeatures",False)('loopOverVectorsWithInnerContentTemplateBegin', VFFSL(SL,"loopFeatureOrdering",True), VFFSL(SL,"dict",True)) # u"${insertCodeForFeatures('loopOverVectorsWithInnerContentTemplateBegin', $loopFeatureOrdering, $dict)}" on line 155, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('loopOverVectorsWithInnerContentTemplateBegin', $loopFeatureOrdering, $dict)}")) # from line 155, col 1.
+            ## START CAPTURE REGION: _73591120 loopString at line 156, col 5 in the source.
+            _orig_trans_73591120 = trans
+            _wasBuffering_73591120 = self._CHEETAH__isBuffering
+            self._CHEETAH__isBuffering = True
+            trans = _captureCollector_73591120 = DummyTransaction()
+            write = _captureCollector_73591120.response().write
+            if basis is None: # generated from line 157, col 7
+                vectorSize = vector.allocSize
+            else: # generated from line 159, col 7
+                vectorSize = vector.sizeInBasis(basis)
+            write(u'''for (long _i0 = 0; _i0 < ''')
+            _v = VFFSL(SL,"loopCountPrefix",True) # u'${loopCountPrefix}' on line 162, col 26
+            if _v is not None: write(_filter(_v, rawExpr=u'${loopCountPrefix}')) # from line 162, col 26.
+            _v = VFFSL(SL,"vectorSize",True) # u'${vectorSize}' on line 162, col 44
+            if _v is not None: write(_filter(_v, rawExpr=u'${vectorSize}')) # from line 162, col 44.
+            write(u'''; _i0++) {
+  ''')
+            _v = VFFSL(SL,"innerLoopTemplate",True) # u'${innerLoopTemplate, autoIndent=True}' on line 163, col 3
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${innerLoopTemplate, autoIndent=True}')) # from line 163, col 3.
+            write(u'''}
+''')
+            trans = _orig_trans_73591120
+            write = trans.response().write
+            self._CHEETAH__isBuffering = _wasBuffering_73591120 
+            loopString = _captureCollector_73591120.response().getvalue()
+            del _orig_trans_73591120
+            del _captureCollector_73591120
+            del _wasBuffering_73591120
+            _v = VFFSL(SL,"loopString",True) # u"${loopString, extraIndent=dict['extraIndent']}" on line 166, col 1
+            if _v is not None: write(_filter(_v, extraIndent=dict['extraIndent'], rawExpr=u"${loopString, extraIndent=dict['extraIndent']}")) # from line 166, col 1.
+            write(u'''
+''')
+            _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('loopOverVectorsWithInnerContentTemplateEnd', VFFSL(SL,"loopFeatureOrdering",True), VFFSL(SL,"dict",True)) # u"${insertCodeForFeaturesInReverseOrder('loopOverVectorsWithInnerContentTemplateEnd', $loopFeatureOrdering, $dict)}" on line 167, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeaturesInReverseOrder('loopOverVectorsWithInnerContentTemplateEnd', $loopFeatureOrdering, $dict)}")) # from line 167, col 1.
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def loopOverVectorsInBasisWithInnerContent(self, vectors, basis, innerContent, **KWS):
+
+
+        """
+        Insert code to loop over vectors in a single field.
+        Unlike the previous function, this function loops over a single field
+        and only provides access to vectors in that field.
+        
+        The intention is that this function is used where a specific operation
+        needs to be performed that does not require loops over individual dimensions,
+        and so the resulting code can be simplified, and possibly made easier to
+        optimise in the future with vectorisation and OpenMP.
+        """
+
+        ## CHEETAH: generated from @def loopOverVectorsInBasisWithInnerContent($vectors, $basis, $innerContent) at line 171, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        #  All of the vectors must be in the same field
+        fields = set([v.field for v in VFFSL(SL,"vectors",True)])
+        # 
+        assert len(VFFSL(SL,"fields",True)) == 1
+        field = VFFSL(SL,"anyObject",False)(VFFSL(SL,"fields",True))
+        # 
+        featureOrdering = ['OpenMP']
+        # 
+        blankLineSeparator = ''
+        # 
+        #  Initialise index pointers
+        for vector in VFFSL(SL,"vectors",True): # generated from line 193, col 3
+            #  Don't output a blank line for the first vector
+            _v = VFFSL(SL,"blankLineSeparator",True) # u'${blankLineSeparator}' on line 195, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${blankLineSeparator}')) # from line 195, col 1.
+            blankLineSeparator = '\n'
+            # 
+            write(u'''long _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 198, col 7
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 198, col 7.
+            write(u'''_index_pointer = 0;
+''')
+            # 
+            for componentNumber, componentName in enumerate(VFFSL(SL,"vector.components",True)): # generated from line 200, col 5
+                write(u'''#define ''')
+                _v = VFFSL(SL,"componentName",True) # u'$componentName' on line 201, col 9
+                if _v is not None: write(_filter(_v, rawExpr=u'$componentName')) # from line 201, col 9.
+                write(u''' _active_''')
+                _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 201, col 32
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 201, col 32.
+                write(u'''[_''')
+                _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 201, col 46
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 201, col 46.
+                write(u'''_index_pointer + ''')
+                _v = VFFSL(SL,"componentNumber",True) # u'$componentNumber' on line 201, col 75
+                if _v is not None: write(_filter(_v, rawExpr=u'$componentNumber')) # from line 201, col 75.
+                write(u''']
+''')
+        dict = {'vectors': VFFSL(SL,"vectors",True), 'loopCode': innerContent}
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('loopOverVectorsWithInnerContentBegin', VFFSL(SL,"featureOrdering",True), VFFSL(SL,"dict",True)) # u"${insertCodeForFeatures('loopOverVectorsWithInnerContentBegin', $featureOrdering, $dict)}" on line 205, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('loopOverVectorsWithInnerContentBegin', $featureOrdering, $dict)}")) # from line 205, col 1.
+        write(u'''for (long _i0 = 0; _i0 < ''')
+        _v = VFN(VFFSL(SL,"field",True),"sizeInBasis",False)(basis) # u'${field.sizeInBasis(basis)}' on line 206, col 26
+        if _v is not None: write(_filter(_v, rawExpr=u'${field.sizeInBasis(basis)}')) # from line 206, col 26.
+        write(u'''; _i0++) {
+  ''')
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('loopOverVectorsWithInnerContentEnd', VFFSL(SL,"featureOrdering",True), VFFSL(SL,"dict",True)) # u"${insertCodeForFeaturesInReverseOrder('loopOverVectorsWithInnerContentEnd', $featureOrdering, $dict), autoIndent=True}" on line 207, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeaturesInReverseOrder('loopOverVectorsWithInnerContentEnd', $featureOrdering, $dict), autoIndent=True}")) # from line 207, col 3.
+        # 
+        write(u'''  ''')
+        _v = VFFSL(SL,"innerContent",True) # u'${innerContent, autoIndent=True}' on line 209, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${innerContent, autoIndent=True}')) # from line 209, col 3.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"vectors",True): # generated from line 211, col 3
+            write(u'''  _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 212, col 4
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 212, col 4.
+            write(u'''_index_pointer += _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 212, col 35
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 212, col 35.
+            write(u'''_ncomponents;
+''')
+        write(u'''}
+''')
+        for vector in VFFSL(SL,"vectors",True): # generated from line 215, col 3
+            for componentName in VFFSL(SL,"vector.components",True): # generated from line 216, col 5
+                write(u'''#undef ''')
+                _v = VFFSL(SL,"componentName",True) # u'$componentName' on line 217, col 8
+                if _v is not None: write(_filter(_v, rawExpr=u'$componentName')) # from line 217, col 8.
+                write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def loopOverFieldInBasisWithVectorsAndInnerContent(self, field, basis, vectors, innerLoopCode, indexOverrides=None, vectorOverrides=None, loopingOrder=_ScriptElement.LoopingOrder.MemoryOrder, preDimensionLoopOpeningCode=None, postDimensionLoopClosingCode=None, vectorsNotNeedingDefines=None, **KWS):
+
+
+        """
+        Insert code to loop over a fields points making available the given vectors
+        Note that this code asserts that the field that will be iterated over is at
+        most as fine as the fields underlying the vectors in each dimension that has
+        more than one point.
+        
+        Note that the vectors CAN be from fields other than ``$field``, this makes it easy
+        to use this code for moment groups. The only restriction is that the fields
+        for the vectors cannot be coarser than ``$field`` (in dimensions that have more
+        than one point). Though this could be changed if a use-case for this can be
+        found such that the meaning of this would be well-defined.
+        
+        Optional arguments:
+        
+          - `indexOverrides`: instead of looping over a dimension, use a specific value for its index.
+            This should be a dictionary mapping dimension names to a dictionary of field -> override
+            string pairs.
+            
+            For example, if you want to override the propagation dimension (``t``)::
+            
+              { 't': {some_field: 'some_t_index_for_field', some_other_field: 'etc'}}
+            
+          - `vectorOverrides`: instead of causing the component names to be directly mapped to the arrays
+            create variables for each component.
+          
+          - `loopingOrder`: One of the values of the `LoopingOrder` class. i.e. MemoryOrder, StrictlyAscendingOrder
+            or StrictlyDescendingOrder. For example, StrictlyAscendingOrder causes the loops over kspace dimensions
+            to be performed in strictly ascending order instead of starting at 0, working up to the maximum value,
+            and then doing the negative values in increasing order.
+          
+          - `preDimensionLoopOpeningCode`: a dictionary containing code to be put in the loop structure before
+            the loop for a given dimension has been opened. For example, if you want to insert code before the
+            ``x`` dimension, you would pass the following for `postDimensionLoopOpeningCode`::
+            
+              { 'x': lotsAndLotsOfPreLoopCode }
+            
+            Note that ``x`` must be the name of the dimension representation, not the dimension itself. i.e. ``kx`` instead
+            of ``x`` if the dimension is in Fourier space. This note applies to `postDimensionLoopClosingCode` as well.
+          
+          - `postDimensionLoopClosingCode`: a dictionary containing code to be put in the loop structure after
+            the loop for a given dimension has been closed. For example, if you want to insert code after the
+            ``x`` dimension, you would pass the following for `postDimensionLoopClosingCode`::
+            
+              { 'x': lotsAndLotsOfPostLoopCode }
+            
+          - `vectorsNotNeedingDefines`: a set of vectors for which C ``#define`` statements for vector components are
+            not wanted.
+        """
+
+        ## CHEETAH: generated from @def loopOverFieldInBasisWithVectorsAndInnerContent($field, $basis, $vectors, $innerLoopCode, $indexOverrides = None, $vectorOverrides = None, $loopingOrder = _ScriptElement.LoopingOrder.MemoryOrder, $preDimensionLoopOpeningCode = None, $postDimensionLoopClosingCode = None, vectorsNotNeedingDefines = None) at line 223, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  Defaults
+        # 
+        indexOverrides = indexOverrides or {}
+        vectorOverrides = vectorOverrides or []
+        preDimensionLoopOpeningCode = preDimensionLoopOpeningCode or {}
+        postDimensionLoopClosingCode = postDimensionLoopClosingCode or {}
+        vectorsNotNeedingDefines = vectorsNotNeedingDefines or set()
+        # 
+        featureOrdering = ['Driver']
+        featuresDict = { 'field': field,                         'basis': basis,                         'vectors': vectors,                         'indexOverrides': indexOverrides,                         'vectorOverrides': vectorOverrides,                         'preDimensionLoopOpeningCode': preDimensionLoopOpeningCode,                         'postDimensionLoopClosingCode': postDimensionLoopClosingCode,                       }
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('loopOverFieldInBasisWithVectorsAndInnerContentBegin', featureOrdering, featuresDict) # u"${insertCodeForFeatures('loopOverFieldInBasisWithVectorsAndInnerContentBegin', featureOrdering, featuresDict)}" on line 291, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('loopOverFieldInBasisWithVectorsAndInnerContentBegin', featureOrdering, featuresDict)}")) # from line 291, col 1.
+        # 
+        #  Some vectors will need to have their index pointers set explicitly.
+        #  These will be those which belong to fields with different dimensions.
+        vectorsRequiringExplictIndexPointers = set([v for v in vectors if v.field.dimensions != field.dimensions])
+        #  
+        #  If we have a loopingOrder other than MemoryOrder, then the vectors in
+        #  field $field will also need their index pointers set explicitly
+        if VFFSL(SL,"loopingOrder",True) != VFFSL(SL,"LoopingOrder.MemoryOrder",True): # generated from line 299, col 3
+            vectorsRequiringExplictIndexPointers.update(VFFSL(SL,"vectors",True))
+        # 
+        #  Now determine the vectors not requiring explicit index pointers
+        vectorsNotRequiringExplicitIndexPointers = set(vectors).difference(vectorsRequiringExplictIndexPointers)
+        # 
+        indentLevel = 0
+        # 
+        #  Initialise index pointers
+        for vector in VFFSL(SL,"vectors",True): # generated from line 309, col 3
+            # 
+            write(u'''long _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 311, col 7
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 311, col 7.
+            write(u'''_index_pointer = 0;
+''')
+            if vector in vectorsNotNeedingDefines: # generated from line 312, col 5
+                pass
+            elif vector in vectorOverrides: # generated from line 314, col 5
+                #  This vector is in vectorOverrides, so instead of #defining, we want to create variables
+                for componentName in vector.components: # generated from line 316, col 7
+                    _v = VFFSL(SL,"vector.type",True) # u'$vector.type' on line 317, col 1
+                    if _v is not None: write(_filter(_v, rawExpr=u'$vector.type')) # from line 317, col 1.
+                    write(u''' ''')
+                    _v = VFFSL(SL,"componentName",True) # u'$componentName' on line 317, col 14
+                    if _v is not None: write(_filter(_v, rawExpr=u'$componentName')) # from line 317, col 14.
+                    write(u''';
+''')
+            else: # generated from line 319, col 5
+                #  If vector isn't in vectorOverrides or vectorsNotNeedingDefines, then we want to #define the vector's components
+                for componentNumber, componentName in enumerate(VFFSL(SL,"vector.components",True)): # generated from line 321, col 7
+                    write(u'''#define ''')
+                    _v = VFFSL(SL,"componentName",True) # u'$componentName' on line 322, col 9
+                    if _v is not None: write(_filter(_v, rawExpr=u'$componentName')) # from line 322, col 9.
+                    write(u''' _active_''')
+                    _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 322, col 32
+                    if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 322, col 32.
+                    write(u'''[_''')
+                    _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 322, col 46
+                    if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 322, col 46.
+                    write(u'''_index_pointer + ''')
+                    _v = VFFSL(SL,"componentNumber",True) # u'$componentNumber' on line 322, col 75
+                    if _v is not None: write(_filter(_v, rawExpr=u'$componentNumber')) # from line 322, col 75.
+                    write(u''']
+''')
+        #  loop over geometry dimensions creating dimension variable names for those that
+        #  aren't in this field, but are in any of the $vectors fields, unless we have an index override for it.
+        for dimension in VFFSL(SL,"geometry.dimensions",True): # generated from line 328, col 3
+            if VFN(VFFSL(SL,"field",True),"hasDimension",False)(VFFSL(SL,"dimension",True)): # generated from line 329, col 5
+                continue
+            # 
+            if len([v for v in vectors if v.field.hasDimension(dimension)]) == 0: # generated from line 333, col 5
+                continue
+            # 
+            dimRep = dimension.inBasis(basis)
+            if indexOverrides.has_key(dimRep.name): # generated from line 338, col 5
+                continue
+            write(u'''
+''')
+            _v = VFFSL(SL,"dimRep.createCoordinateVariableForSinglePointSample",True) # u'${dimRep.createCoordinateVariableForSinglePointSample}' on line 342, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.createCoordinateVariableForSinglePointSample}')) # from line 342, col 1.
+            write(u'''
+''')
+        # 
+        #  loop over the dimensions opening the loops
+        lastLoopDimRep = None
+        for dimRep in field.inBasis(basis): # generated from line 348, col 3
+            # 
+            if dimRep.name in preDimensionLoopOpeningCode: # generated from line 350, col 5
+                _v = VFFSL(SL,"preDimensionLoopOpeningCode",True)[VFFSL(SL,"dimRep.name",True)] # u'${preDimensionLoopOpeningCode[$dimRep.name], extraIndent=$indentLevel}' on line 351, col 1
+                if _v is not None: write(_filter(_v, extraIndent=VFFSL(SL,"indentLevel",True), rawExpr=u'${preDimensionLoopOpeningCode[$dimRep.name], extraIndent=$indentLevel}')) # from line 351, col 1.
+            if not indexOverrides.has_key(dimRep.name): # generated from line 353, col 5
+                #  If there isn't an indexOverride for this dimension, then open a loop
+                lastLoopDimRep = dimRep
+                # 
+                loopOpeningFeatureOrdering = ['OpenMP']
+                featuresDict.update({        'vectorsNotRequiringExplicitIndexPointers': vectorsNotRequiringExplicitIndexPointers,        'dimRep': dimRep,        'loopCode': innerLoopCode      })
+                _v = VFFSL(SL,"insertCodeForFeatures",False)('loopOverFieldInBasisWithVectorsAndInnerContentLoopOpenBegin', loopOpeningFeatureOrdering, featuresDict) # u"${insertCodeForFeatures('loopOverFieldInBasisWithVectorsAndInnerContentLoopOpenBegin', loopOpeningFeatureOrdering, featuresDict), extraIndent=indentLevel}" on line 363, col 1
+                if _v is not None: write(_filter(_v, extraIndent=indentLevel, rawExpr=u"${insertCodeForFeatures('loopOverFieldInBasisWithVectorsAndInnerContentLoopOpenBegin', loopOpeningFeatureOrdering, featuresDict), extraIndent=indentLevel}")) # from line 363, col 1.
+                # 
+                _v = VFN(VFFSL(SL,"dimRep",True),"openLoop",False)(loopingOrder=loopingOrder) # u'${dimRep.openLoop(loopingOrder=loopingOrder), extraIndent=indentLevel}' on line 365, col 1
+                if _v is not None: write(_filter(_v, extraIndent=indentLevel, rawExpr=u'${dimRep.openLoop(loopingOrder=loopingOrder), extraIndent=indentLevel}')) # from line 365, col 1.
+                indentLevel = VFFSL(SL,"indentLevel",True) + 2
+                _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('loopOverFieldInBasisWithVectorsAndInnerContentLoopOpenEnd', loopOpeningFeatureOrdering, featuresDict) # u"${insertCodeForFeaturesInReverseOrder('loopOverFieldInBasisWithVectorsAndInnerContentLoopOpenEnd', loopOpeningFeatureOrdering, featuresDict), extraIndent=indentLevel}" on line 367, col 1
+                if _v is not None: write(_filter(_v, extraIndent=indentLevel, rawExpr=u"${insertCodeForFeaturesInReverseOrder('loopOverFieldInBasisWithVectorsAndInnerContentLoopOpenEnd', loopOpeningFeatureOrdering, featuresDict), extraIndent=indentLevel}")) # from line 367, col 1.
+            else: # generated from line 368, col 5
+                #  We have an indexOverride for this dimension. 
+                _v = VFFSL(SL,"prologueForOverriddenDimRepInFieldInBasisWithVectors",False)(VFFSL(SL,"dimRep",True), VFFSL(SL,"field",True), VFFSL(SL,"basis",True), VFFSL(SL,"vectors",True), VFFSL(SL,"indexOverrides",True)) # u'${prologueForOverriddenDimRepInFieldInBasisWithVectors($dimRep, $field, $basis, $vectors, $indexOverrides), extraIndent=$indentLevel}' on line 370, col 1
+                if _v is not None: write(_filter(_v, extraIndent=VFFSL(SL,"indentLevel",True), rawExpr=u'${prologueForOverriddenDimRepInFieldInBasisWithVectors($dimRep, $field, $basis, $vectors, $indexOverrides), extraIndent=$indentLevel}')) # from line 370, col 1.
+            # 
+        # 
+        result = VFFSL(SL,"setExplicitIndexPointersForVectorsWithFieldAndBasis",False)(vectorsRequiringExplictIndexPointers, field, basis, indexOverrides)
+        if result: # generated from line 376, col 3
+            _v = VFFSL(SL,"result",True) # u'${result, extraIndent=indentLevel}' on line 377, col 1
+            if _v is not None: write(_filter(_v, extraIndent=indentLevel, rawExpr=u'${result, extraIndent=indentLevel}')) # from line 377, col 1.
+        # 
+        _v = VFFSL(SL,"innerLoopCode",True) # u'${innerLoopCode, extraIndent=$indentLevel}' on line 380, col 1
+        if _v is not None: write(_filter(_v, extraIndent=VFFSL(SL,"indentLevel",True), rawExpr=u'${innerLoopCode, extraIndent=$indentLevel}')) # from line 380, col 1.
+        _v = VFFSL(SL,"epilogueToIntegrateOverriddenVectorsForSamplingFieldInBasis",False)(vectorOverrides, field, basis) # u'${epilogueToIntegrateOverriddenVectorsForSamplingFieldInBasis(vectorOverrides, field, basis), extraIndent=indentLevel}' on line 381, col 1
+        if _v is not None: write(_filter(_v, extraIndent=indentLevel, rawExpr=u'${epilogueToIntegrateOverriddenVectorsForSamplingFieldInBasis(vectorOverrides, field, basis), extraIndent=indentLevel}')) # from line 381, col 1.
+        # 
+        if lastLoopDimRep: # generated from line 383, col 3
+            #  Increment the index pointers. This needs to be in a function in order to be able
+            #  to use the variable indentation required
+            _v = VFFSL(SL,"incrementIndexPointersForVectorsWithFieldBasisAndLastLoopDimRep",False)(vectorsNotRequiringExplicitIndexPointers, field, basis, lastLoopDimRep) # u'${incrementIndexPointersForVectorsWithFieldBasisAndLastLoopDimRep(vectorsNotRequiringExplicitIndexPointers, field, basis, lastLoopDimRep), extraIndent=indentLevel}' on line 386, col 1
+            if _v is not None: write(_filter(_v, extraIndent=indentLevel, rawExpr=u'${incrementIndexPointersForVectorsWithFieldBasisAndLastLoopDimRep(vectorsNotRequiringExplicitIndexPointers, field, basis, lastLoopDimRep), extraIndent=indentLevel}')) # from line 386, col 1.
+        # 
+        #  loop over the dimensions (in reverse order) closing the loops
+        # 
+        for dimRep in reversed(field.inBasis(basis)): # generated from line 391, col 3
+            # 
+            #  If there isn't an indexOverride for this dimension, then reduce the indent and close the loop
+            if not indexOverrides.has_key(dimRep.name): # generated from line 394, col 5
+                indentLevel = indentLevel - 2
+                _v = VFN(VFFSL(SL,"dimRep",True),"closeLoop",False)(loopingOrder=loopingOrder) # u'${dimRep.closeLoop(loopingOrder=loopingOrder), extraIndent=indentLevel}' on line 396, col 1
+                if _v is not None: write(_filter(_v, extraIndent=indentLevel, rawExpr=u'${dimRep.closeLoop(loopingOrder=loopingOrder), extraIndent=indentLevel}')) # from line 396, col 1.
+            # 
+            if VFFSL(SL,"dimRep.name",True) in postDimensionLoopClosingCode: # generated from line 399, col 5
+                _v = VFFSL(SL,"postDimensionLoopClosingCode",True)[dimRep.name] # u'${postDimensionLoopClosingCode[dimRep.name], extraIndent=indentLevel}' on line 400, col 1
+                if _v is not None: write(_filter(_v, extraIndent=indentLevel, rawExpr=u'${postDimensionLoopClosingCode[dimRep.name], extraIndent=indentLevel}')) # from line 400, col 1.
+            # 
+        # 
+        #  Undefine vector components that weren't in vectorOverrides
+        for vector in vectors: # generated from line 406, col 3
+            if vector in vectorOverrides or vector in vectorsNotNeedingDefines: # generated from line 407, col 5
+                continue
+            for componentName in vector.components: # generated from line 410, col 5
+                write(u'''#undef ''')
+                _v = VFFSL(SL,"componentName",True) # u'$componentName' on line 411, col 8
+                if _v is not None: write(_filter(_v, rawExpr=u'$componentName')) # from line 411, col 8.
+                write(u'''
+''')
+        #  loop over geometry dimensions undefining dimension step variable names for those that
+        #  aren't in this field, but are in any of the $vectors fields, unless we have an index override for it.
+        for dimension in VFFSL(SL,"geometry.dimensions",True): # generated from line 416, col 3
+            if VFN(VFFSL(SL,"field",True),"hasDimension",False)(VFFSL(SL,"dimension",True)): # generated from line 417, col 5
+                continue
+            # 
+            if len([v for v in vectors if v.field.hasDimension(dimension)]) == 0: # generated from line 421, col 5
+                continue
+            # 
+            dimRep = dimension.inBasis(basis)
+            if indexOverrides.has_key(dimRep.name): # generated from line 426, col 5
+                continue
+            write(u'''#undef d''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 429, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 429, col 9.
+            write(u'''
+''')
+        # 
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('loopOverFieldInBasisWithVectorsAndInnerContentEnd', featureOrdering, featuresDict) # u"${insertCodeForFeaturesInReverseOrder('loopOverFieldInBasisWithVectorsAndInnerContentEnd', featureOrdering, featuresDict)}" on line 432, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeaturesInReverseOrder('loopOverFieldInBasisWithVectorsAndInnerContentEnd', featureOrdering, featuresDict)}")) # from line 432, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def prologueForOverriddenDimRepInFieldInBasisWithVectors(self, dimRep, field, basis, vectors, indexOverrides, **KWS):
+
+
+        """
+        Insert prologue for dimension $dimension when its index variable has been overridden
+        """
+
+        ## CHEETAH: generated from @def prologueForOverriddenDimRepInFieldInBasisWithVectors($dimRep, $field, $basis, $vectors, $indexOverrides) at line 437, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  As this field contains this dimension, we must make sure that the indexOverride dictionary contains
+        #  a value for this field
+        assert VFN(VFFSL(SL,"indexOverrides",True)[VFFSL(SL,"dimRep.name",True)],"has_key",False)(field)
+        # 
+        write(u'''unsigned long ''')
+        _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 444, col 15
+        if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 444, col 15.
+        write(u''' = ''')
+        _v = VFFSL(SL,"indexOverrides",True)[dimRep.name][field] # u'${indexOverrides[dimRep.name][field]}' on line 444, col 37
+        if _v is not None: write(_filter(_v, rawExpr=u'${indexOverrides[dimRep.name][field]}')) # from line 444, col 37.
+        write(u''';
+''')
+        #  loop over the vectors in field $field, because we need to fix up their index pointers
+        #  and those vectors with the same dimensions
+        for vector in [v for v in vectors if v.field.dimensions == field.dimensions]: # generated from line 447, col 3
+            write(u'''_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 448, col 2
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 448, col 2.
+            write(u'''_index_pointer += ''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 448, col 32
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 448, col 32.
+            write(u''' * ''')
+            _v = VFN(VFFSL(SL,"field",True),"localPointsInDimensionsAfterDimRepInBasis",False)(dimRep, basis) # u'${field.localPointsInDimensionsAfterDimRepInBasis(dimRep, basis)}' on line 449, col 4
+            if _v is not None: write(_filter(_v, rawExpr=u'${field.localPointsInDimensionsAfterDimRepInBasis(dimRep, basis)}')) # from line 449, col 4.
+            write(u''';
+''')
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def setExplicitIndexPointersForVectorsWithFieldAndBasis(self, vectors, field, basis, indexOverrides, **KWS):
+
+
+        """
+        Set index pointers for those vectors requiring it to be set explicitly
+        """
+
+        ## CHEETAH: generated from @def setExplicitIndexPointersForVectorsWithFieldAndBasis($vectors, $field, $basis, $indexOverrides) at line 456, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  There's no need to (re-)set the index pointer for fields that have no dimensions
+        vectorsNeedingExplicitIndexPointers = [vector for vector in vectors if vector.field.dimensions]
+        if len(vectorsNeedingExplicitIndexPointers) == 0: # generated from line 461, col 3
+            return
+        # 
+        #  For the vectors that are not in the field $field, set their index pointers
+        write(u'''// Set index pointers explicitly for (some) vectors
+''')
+        for vector in vectorsNeedingExplicitIndexPointers: # generated from line 467, col 3
+            # 
+            write(u'''_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 469, col 2
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 469, col 2.
+            write(u'''_index_pointer = ( 0''')
+            for dimRep in vector.field.inBasis(basis): # generated from line 470, col 5
+                _v = VFFSL(SL,"explicitIndexPointerTermForVectorAndDimRepWithFieldAndBasis",False)(vector, dimRep, field, basis, indexOverrides) # u'${explicitIndexPointerTermForVectorAndDimRepWithFieldAndBasis(vector, dimRep, field, basis, indexOverrides)}' on line 471, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${explicitIndexPointerTermForVectorAndDimRepWithFieldAndBasis(vector, dimRep, field, basis, indexOverrides)}')) # from line 471, col 1.
+            write(u''' ) * _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 473, col 7
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 473, col 7.
+            write(u'''_ncomponents;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def explicitIndexPointerTermForVectorAndDimRepWithFieldAndBasis(self, vector, dimRep, field, basis, indexOverrides, **KWS):
+
+
+
+        ## CHEETAH: generated from @def explicitIndexPointerTermForVectorAndDimRepWithFieldAndBasis($vector, $dimRep, $field, $basis, $indexOverrides) at line 478, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  Blank line for output formatting
+        write(u'''
+''')
+        #  Not all of the dimensions in the vector's field's dimensions will necessarily
+        #  be in $field's dimensions, and we need to do slightly different things when they
+        #  aren't in $field's dimensions.
+        # 
+        #  First, check the case that they both have this dimension
+        fieldDimRepList = [dr for dr in field.inBasis(basis) if dr.name == dimRep.name]
+        # 
+        if fieldDimRepList: # generated from line 489, col 3
+            #  First, consider when they both contain this dimension
+            # 
+            assert len(fieldDimRepList) == 1
+            fieldDimRep = fieldDimRepList[0]
+            # 
+            #  If the lattices are the same, then there is nothing special to be done for this dimension
+            #  We also require that there are neither dimension could have a local offset
+            hasLocalOffset = dimRep.hasLocalOffset or fieldDimRep.hasLocalOffset
+            if dimRep.runtimeLattice == fieldDimRep.runtimeLattice and not hasLocalOffset: # generated from line 498, col 5
+                write(u'''   + ''')
+                _v = VFFSL(SL,"fieldDimRep.loopIndex",True) # u'${fieldDimRep.loopIndex}' on line 499, col 6
+                if _v is not None: write(_filter(_v, rawExpr=u'${fieldDimRep.loopIndex}')) # from line 499, col 6.
+                write(u''' * ''')
+                _v = VFN(VFFSL(SL,"vector.field",True),"localPointsInDimensionsAfterDimRepInBasis",False)(dimRep, basis) # u'$vector.field.localPointsInDimensionsAfterDimRepInBasis(dimRep, basis)' on line 500, col 4
+                if _v is not None: write(_filter(_v, rawExpr=u'$vector.field.localPointsInDimensionsAfterDimRepInBasis(dimRep, basis)')) # from line 500, col 4.
+            else: # generated from line 501, col 5
+                write(u'''   + ( ''')
+                _v = VFN(VFFSL(SL,"dimRep",True),"localIndexFromIndexForDimensionRep",False)(fieldDimRep) # u'${dimRep.localIndexFromIndexForDimensionRep(fieldDimRep)}' on line 502, col 8
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.localIndexFromIndexForDimensionRep(fieldDimRep)}')) # from line 502, col 8.
+                write(u''' )''')
+                write(u''' * ''')
+                _v = VFN(VFFSL(SL,"vector.field",True),"localPointsInDimensionsAfterDimRepInBasis",False)(dimRep, basis) # u'$vector.field.localPointsInDimensionsAfterDimRepInBasis(dimRep, basis)' on line 503, col 4
+                if _v is not None: write(_filter(_v, rawExpr=u'$vector.field.localPointsInDimensionsAfterDimRepInBasis(dimRep, basis)')) # from line 503, col 4.
+        else: # generated from line 505, col 3
+            #  Now, consider when $field doesn't contain this dimension. If this dimension has an index override, then
+            #  use the index pointers from that.
+            if indexOverrides.has_key(dimRep.name): # generated from line 508, col 5
+                #  We do have an index override for this dimension
+                # 
+                #  Check that we actually have an entry for this vector's field
+                assert indexOverrides[dimRep.name].has_key(vector.field)
+                write(u'''   + ''')
+                _v = VFFSL(SL,"indexOverrides",True)[dimRep.name][vector.field] # u'${indexOverrides[dimRep.name][vector.field]}' on line 513, col 6
+                if _v is not None: write(_filter(_v, rawExpr=u'${indexOverrides[dimRep.name][vector.field]}')) # from line 513, col 6.
+                write(u'''  * ''')
+                _v = VFN(VFFSL(SL,"vector.field",True),"localPointsInDimensionsAfterDimRepInBasis",False)(dimRep, basis) # u'$vector.field.localPointsInDimensionsAfterDimRepInBasis(dimRep, basis)' on line 514, col 5
+                if _v is not None: write(_filter(_v, rawExpr=u'$vector.field.localPointsInDimensionsAfterDimRepInBasis(dimRep, basis)')) # from line 514, col 5.
+            else: # generated from line 515, col 5
+                #  We don't have an index override for this dimension.
+                #  What happens in this case depends on whether or not the vector
+                #  is in fourier space in this dimension. If it is, then we want to take its
+                #  value at k=0 (the first element in this dimension). If it isn't in fourier
+                #  space, then we want to take its element in the middle.
+                # 
+                #  Either way, this is handled by the dimension. But we can't have this dimension distributed.
+                assert not dimRep.hasLocalOffset, "Can't do single point samples with the distributed-mpi driver."
+                write(u'''   + ( ''')
+                _v = VFFSL(SL,"dimRep.indexForSinglePointSample",True) # u'${dimRep.indexForSinglePointSample}' on line 524, col 8
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.indexForSinglePointSample}')) # from line 524, col 8.
+                write(u''' )''')
+                write(u'''  * ''')
+                _v = VFN(VFFSL(SL,"vector.field",True),"localPointsInDimensionsAfterDimRepInBasis",False)(dimRep, basis) # u'$vector.field.localPointsInDimensionsAfterDimRepInBasis(dimRep, basis)' on line 525, col 5
+                if _v is not None: write(_filter(_v, rawExpr=u'$vector.field.localPointsInDimensionsAfterDimRepInBasis(dimRep, basis)')) # from line 525, col 5.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def epilogueToIntegrateOverriddenVectorsForSamplingFieldInBasis(self, vectorOverrides, field, basis, **KWS):
+
+
+        """
+        Integrate the overridden vectors
+        """
+
+        ## CHEETAH: generated from @def epilogueToIntegrateOverriddenVectorsForSamplingFieldInBasis($vectorOverrides, $field, $basis) at line 532, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  Loop over the overridden vectors
+        for vector in VFFSL(SL,"vectorOverrides",True): # generated from line 536, col 3
+            write(u'''
+''')
+            #  Determine which dimensions are being integrated over (if any)
+            #  These are the ones that are in $field, but not in the vector's field
+            dimensionsIntegratedOver = [dim for dim in field.dimensions if not vector.field.hasDimension(dim)]
+            # 
+            #  Loop over the components in each vector
+            for componentNumber, componentName in enumerate(VFFSL(SL,"vector.components",True)): # generated from line 543, col 5
+                write(u'''_active_''')
+                _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 544, col 9
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 544, col 9.
+                write(u'''[_''')
+                _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 544, col 23
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 544, col 23.
+                write(u'''_index_pointer + ''')
+                _v = VFFSL(SL,"componentNumber",True) # u'${componentNumber}' on line 544, col 52
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentNumber}')) # from line 544, col 52.
+                write(u'''] += ''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 544, col 75
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 544, col 75.
+                #  Loop over the dimensions
+                for dimension in VFFSL(SL,"dimensionsIntegratedOver",True): # generated from line 546, col 7
+                    write(u''' * d''')
+                    _v = VFN(VFN(VFFSL(SL,"dimension",True),"inBasis",False)(basis),"name",True) # u'${dimension.inBasis(basis).name}' on line 547, col 5
+                    if _v is not None: write(_filter(_v, rawExpr=u'${dimension.inBasis(basis).name}')) # from line 547, col 5.
+                write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def incrementIndexPointersForVectorsWithFieldBasisAndLastLoopDimRep(self, vectors, field, basis, lastLoopDimRep, **KWS):
+
+
+        """
+        Increment index pointers but only for those in field `field` or in a field with the same dimensions.
+        """
+
+        ## CHEETAH: generated from @def incrementIndexPointersForVectorsWithFieldBasisAndLastLoopDimRep($vectors, $field, $basis, $lastLoopDimRep) at line 556, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  For the vectors that are in the field $field, increment their index pointers.
+        # 
+        #  If none of $vectors have field $field, then there's nothing to do
+        if len(vectors) == 0: # generated from line 562, col 3
+            return
+        write(u'''// Increment index pointers for vectors in field ''')
+        _v = VFFSL(SL,"field.name",True) # u'$field.name' on line 565, col 50
+        if _v is not None: write(_filter(_v, rawExpr=u'$field.name')) # from line 565, col 50.
+        write(u''' (or having the same dimensions)
+''')
+        for vector in vectors: # generated from line 566, col 3
+            #  We can only do this for vectors in $field
+            #  or that have the same dimensions
+            assert vector.field.dimensions == field.dimensions
+            # 
+            #  Now we need to increment the vector
+            #  We need to know the last loop dimension because we could be looping over the second last dimension and not the last
+            #  because the last was overridden by an indexOverride. Hence the step may not be _stuff_ncomponents,
+            #  but _stuff_latticeN * _stuff_ncomponents (etc.)
+            #  This is needed for cross-propagation when cross-propagating along the last dimension.
+            write(u'''_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 576, col 2
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 576, col 2.
+            write(u'''_index_pointer += ''')
+            _v = VFN(VFFSL(SL,"field",True),"localPointsInDimensionsAfterDimRepInBasis",False)(lastLoopDimRep, basis) # u'$field.localPointsInDimensionsAfterDimRepInBasis(lastLoopDimRep, basis)' on line 576, col 32
+            if _v is not None: write(_filter(_v, rawExpr=u'$field.localPointsInDimensionsAfterDimRepInBasis(lastLoopDimRep, basis)')) # from line 576, col 32.
+            write(u''' * _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 576, col 107
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 576, col 107.
+            write(u'''_ncomponents;
+''')
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def evaluateComputedVectors(self, vectors, static=True, **KWS):
+
+
+        """
+        Evaluate the computed vectors in an appropriate order taking into account dependencies.  
+        All noises vectors must have the same static/dynamic type as that passed in.
+        """
+
+        ## CHEETAH: generated from @def evaluateComputedVectors($vectors, $static = True) at line 582, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        for vector in self.evaluationOrderForVectors(vectors, static, predicate = lambda x: x.isComputed): # generated from line 588, col 3
+            _v = VFN(VFN(VFFSL(SL,"vector",True),"functions",True)['evaluate'],"call",False)() # u"${vector.functions['evaluate'].call()}" on line 589, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u"${vector.functions['evaluate'].call()}")) # from line 589, col 1.
+            write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def copyVectors(self, vectors, destPrefix, srcPrefix=None, **KWS):
+
+
+        """
+        Copy the contents of `vecSrc` into `vecDest`
+        """
+
+        ## CHEETAH: generated from @def copyVectors($vectors, $destPrefix, $srcPrefix = None) at line 594, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        for vector in VFFSL(SL,"vectors",True): # generated from line 597, col 3
+            write(u'''memcpy(''')
+            _v = VFFSL(SL,"destPrefix",True) # u'${destPrefix}' on line 598, col 8
+            if _v is not None: write(_filter(_v, rawExpr=u'${destPrefix}')) # from line 598, col 8.
+            write(u'''_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 598, col 22
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 598, col 22.
+            write(u''', ''')
+            _v = VFFSL(SL,"srcPrefix",True) # u'${srcPrefix}' on line 598, col 36
+            if _v is not None: write(_filter(_v, rawExpr=u'${srcPrefix}')) # from line 598, col 36.
+            write(u'''_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 598, col 49
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 598, col 49.
+            write(u''', sizeof(''')
+            _v = VFFSL(SL,"vector.type",True) # u'${vector.type}' on line 598, col 70
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.type}')) # from line 598, col 70.
+            write(u''') * ''')
+            _v = VFFSL(SL,"vector.allocSize",True) # u'${vector.allocSize}' on line 598, col 88
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.allocSize}')) # from line 598, col 88.
+            write(u''');
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # ScriptElement.tmpl
+        # 
+        # Created by Graham Dennis on 2007-08-23.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_ScriptElement= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(ScriptElement, '_initCheetahAttributes'):
+    templateAPIClass = getattr(ScriptElement, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(ScriptElement)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=ScriptElement()).run()
+
+
diff --git a/xpdeint/ScriptElement.tmpl b/xpdeint/ScriptElement.tmpl
new file mode 100644
index 0000000..46763d1
--- /dev/null
+++ b/xpdeint/ScriptElement.tmpl
@@ -0,0 +1,602 @@
+@*
+ScriptElement.tmpl
+
+Created by Graham Dennis on 2007-08-23.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint._ScriptElement
+
+ at from xpdeint.CallOnceGuards import callOnceGuard
+
+@*doc-class:
+  This class provides all of the various loop constructs that are needed in the generated code.
+  Currently, this class provides three different types of loop with differing levels of complexity:
+  
+  1.  `loopOverVectorsWithInnerContentTemplate`: This is the most basic form of a loop.
+      This loop construct is for the occasions where you want to do the same operation to
+      every component of a bunch of vectors. The perfect example of this case is in the 
+      integrators where a derivative for each vector component has been calculated, and that
+      needs to be added to the original vector in some way. Note that the operation performed
+      by this loop must perform the same operation to the real and imaginary parts of a complex
+      vector.
+      
+      This function generates one loop per vector, and the form of the loop generated for each vector is::
+      
+        for (long _i0 = 0; _i0 < _size_of_vector; _i0++) {
+          // contents of loop
+        }
+      
+      As the exact contents of the loops will be different for each vector as each vector has a
+      different array name, and a different size, instead of providing the exact contents of the loop,
+      you provide a Cheetah template string for the loop contents describing the loop contents.
+      
+      Due to the very simple nature of this loop, it can be threaded quite easily using the OpenMP
+      feature (if it is turned on), or the code modified to make most compilers' auto-vectorisation
+      features vectorise the code (if the auto-vectorisation feature is turned on).
+      
+  2.  `loopOverVectorsInSpaceWithInnerContent`: This one is slightly more complex than the previous type,
+      and so has slightly different restrictions. This loop construct is for the occasions where you want
+      to do the same operation at each point, but possibly different operations to different components.
+      An additional restriction for this loop construct is that all of the vectors must be in the same
+      field. This is because unlike the previous loop construct, only one loop is created, and all of
+      the vectors are made available in that loop. This loop construct also creates ``#define``s for
+      components of vectors, but only the ``phi`` form, not the integer-valued ``phi[i, j]`` form as
+      well.
+      
+      The form of the loop generated by this function is::
+      
+        // #define's and creation of index pointers for each vector
+        for (long _i0 = 0; _i0 < _size_of_field_all_vectors_are_in; _i0++) {
+          // contents of loop
+          
+          // increment each vector's index pointer by the number of components in the vector.
+        }
+      
+      For this loop construct, the contents of the loop are simply transplanted inside the loop, i.e.
+      it isn't interpreted as a Cheetah template string.
+      
+      As this loop can contain arbitrary operations on complex vectors, this loop cannot be auto-vectorised.
+      However, it can still be threaded with the OpenMP feature.
+     
+  3. `loopOverFieldInBasisWithVectorsAndInnerContent`: By far the most powerful loop construct available.
+     This is the loop construct you want with user-provided code. It allows you to loop over all of the 
+     dimensions of a given field in a given space (arbitrary combination of fourier and non-fourier space),
+     making various vectors available which may or may not come from the same field as the looping field.
+     This loop construct can be used for integrating over dimensions for moments, sub-sampling, etc.
+     
+     This function supports a number of optional arguments to enable customisation of the generated loops.
+     As this loop could contain arbitrary code, it can neither be vectorised nor threaded using OpenMP.
+     
+     See the documentation of the function for more details.
+     
+  
+  
+  Although this class might look a bit like black magic, I promise that it is not self-aware, and
+  probably won't take over the universe. However, should it attempt to do so, I'll provide a copy of the 3
+  laws for its own reference:
+  
+  1.  xpdeint may not injure a user or, through inaction, allow a user to come to harm.
+  
+  2.  xpdeint must obey orders given to it by the user, except where such orders would conflict with the First Law.
+  
+  3.  xpdeint must protect its own existence as long as such protection does not conflict with the First or Second Law.
+*@
+
+
+ at def loopOverVectorsWithInnerContentTemplate($vectors, $templateString, $basis = None)
+@*doc:
+Insert code to loop over a vector.
+
+The contents of the loop are specified by a Cheetah template string,
+which has the following variables available:
+
+  - ``$vector``:   The current vector
+  - ``$index``:   The index variable name
+
+A simple example for the contents of this loop would be (passed as a `templateString`)::
+
+  _active_${vector.id}[${index}] $operation;
+
+Where ``$operation`` is some operation. If the `templateString` does not end with a new line,
+then one is added automatically.
+
+The intention is that this function is to be used when you have a very simple operation
+to be performed in the same way on a range of vectors in possibly different fields.
+*@
+  @assert len($templateString) > 0
+  @#
+  @set $templateFeatureOrdering = ['AutoVectorise']
+  @set $dict = {'templateString': $templateString,
+                'originalTemplateString': $templateString,
+                'loopCountPrefixFunction': None,
+                'templateFunctions': []}
+  @silent $insertCodeForFeatures('loopOverVectorsWithInnerContentTemplateModifyTemplate',
+                                 $templateFeatureOrdering,
+                                 $dict)
+  @set $templateString = dict['templateString']
+  @# If the loopCountPrefixFunction is None, then provide an empty default
+  @set $loopCountPrefixFunction = dict['loopCountPrefixFunction'] or (lambda v: '')
+  @#
+  @# The template string should end with a new line, if it doesn't we'll add it
+  @if $templateString[-1] != '\n'
+    @set $templateString = $templateString + '\n'
+  @end if
+  @#
+  @set $templateString += '\n'.join(dict['templateFunctions'])
+  @#
+  @set $templateVariables = {'index': '_i0'}
+  @set $innerLoopTemplate = $templateObjectFromStringWithTemplateVariables($templateString, $templateVariables)
+  @#
+  @set $loopFeatureOrdering = ['AutoVectorise', 'OpenMP']
+  @silent $dict['extraIndent'] = 0
+  @silent $dict['template'] = $innerLoopTemplate
+  @for $vector in $vectors
+    @#
+    @# Get the loopCountPrefix from the loopCountPrefixFunction
+    @set $loopCountPrefix = $loopCountPrefixFunction($vector)
+    @#
+    @# Set the template's current vector
+    @silent $templateVariables['vector'] = $vector
+${insertCodeForFeatures('loopOverVectorsWithInnerContentTemplateBegin', $loopFeatureOrdering, $dict)}@slurp
+    @capture loopString
+      @if basis is None
+        @set $vectorSize = vector.allocSize
+      @else
+        @set $vectorSize = vector.sizeInBasis(basis)
+      @end if
+for (long _i0 = 0; _i0 < ${loopCountPrefix}${vectorSize}; _i0++) {
+  ${innerLoopTemplate, autoIndent=True}@slurp
+}
+    @end capture
+${loopString, extraIndent=dict['extraIndent']}
+${insertCodeForFeaturesInReverseOrder('loopOverVectorsWithInnerContentTemplateEnd', $loopFeatureOrdering, $dict)}@slurp
+  @end for
+ at end def
+
+ at def loopOverVectorsInBasisWithInnerContent($vectors, $basis, $innerContent)
+@*doc:
+Insert code to loop over vectors in a single field.
+Unlike the previous function, this function loops over a single field
+and only provides access to vectors in that field.
+
+The intention is that this function is used where a specific operation
+needs to be performed that does not require loops over individual dimensions,
+and so the resulting code can be simplified, and possibly made easier to
+optimise in the future with vectorisation and OpenMP.
+*@
+  @# All of the vectors must be in the same field
+  @set $fields = set([v.field for v in $vectors])
+  @#
+  @assert len($fields) == 1
+  @set $field = $anyObject($fields)
+  @#
+  @set $featureOrdering = ['OpenMP']
+  @#
+  @set $blankLineSeparator = ''
+  @#
+  @# Initialise index pointers
+  @for $vector in $vectors
+    @# Don't output a blank line for the first vector
+${blankLineSeparator}@slurp
+    @set $blankLineSeparator = '\n'
+    @#
+long _${vector.id}_index_pointer = 0;
+    @#
+    @for $componentNumber, $componentName in enumerate($vector.components)
+#define $componentName _active_${vector.id}[_${vector.id}_index_pointer + $componentNumber]
+    @end for
+  @end for
+  @set $dict = {'vectors': $vectors, 'loopCode': innerContent}
+${insertCodeForFeatures('loopOverVectorsWithInnerContentBegin', $featureOrdering, $dict)}@slurp
+for (long _i0 = 0; _i0 < ${field.sizeInBasis(basis)}; _i0++) {
+  ${insertCodeForFeaturesInReverseOrder('loopOverVectorsWithInnerContentEnd', $featureOrdering, $dict), autoIndent=True}@slurp
+  @#
+  ${innerContent, autoIndent=True}@slurp
+
+  @for $vector in $vectors
+  _${vector.id}_index_pointer += _${vector.id}_ncomponents;
+  @end for
+}
+  @for $vector in $vectors
+    @for $componentName in $vector.components
+#undef $componentName
+    @end for
+  @end for
+  @#
+ at end def
+
+ at def loopOverFieldInBasisWithVectorsAndInnerContent($field, $basis, $vectors, $innerLoopCode, $indexOverrides = None, $vectorOverrides = None, $loopingOrder = _ScriptElement.LoopingOrder.MemoryOrder, $preDimensionLoopOpeningCode = None, $postDimensionLoopClosingCode = None, vectorsNotNeedingDefines = None)
+@*doc:
+Insert code to loop over a fields points making available the given vectors
+Note that this code asserts that the field that will be iterated over is at
+most as fine as the fields underlying the vectors in each dimension that has
+more than one point.
+
+Note that the vectors CAN be from fields other than ``$field``, this makes it easy
+to use this code for moment groups. The only restriction is that the fields
+for the vectors cannot be coarser than ``$field`` (in dimensions that have more
+than one point). Though this could be changed if a use-case for this can be
+found such that the meaning of this would be well-defined.
+
+Optional arguments:
+
+  - `indexOverrides`: instead of looping over a dimension, use a specific value for its index.
+    This should be a dictionary mapping dimension names to a dictionary of field -> override
+    string pairs.
+    
+    For example, if you want to override the propagation dimension (``t``)::
+    
+      { 't': {some_field: 'some_t_index_for_field', some_other_field: 'etc'}}
+    
+  - `vectorOverrides`: instead of causing the component names to be directly mapped to the arrays
+    create variables for each component.
+  
+  - `loopingOrder`: One of the values of the `LoopingOrder` class. i.e. MemoryOrder, StrictlyAscendingOrder
+    or StrictlyDescendingOrder. For example, StrictlyAscendingOrder causes the loops over kspace dimensions
+    to be performed in strictly ascending order instead of starting at 0, working up to the maximum value,
+    and then doing the negative values in increasing order.
+  
+  - `preDimensionLoopOpeningCode`: a dictionary containing code to be put in the loop structure before
+    the loop for a given dimension has been opened. For example, if you want to insert code before the
+    ``x`` dimension, you would pass the following for `postDimensionLoopOpeningCode`::
+    
+      { 'x': lotsAndLotsOfPreLoopCode }
+    
+    Note that ``x`` must be the name of the dimension representation, not the dimension itself. i.e. ``kx`` instead
+    of ``x`` if the dimension is in Fourier space. This note applies to `postDimensionLoopClosingCode` as well.
+  
+  - `postDimensionLoopClosingCode`: a dictionary containing code to be put in the loop structure after
+    the loop for a given dimension has been closed. For example, if you want to insert code after the
+    ``x`` dimension, you would pass the following for `postDimensionLoopClosingCode`::
+    
+      { 'x': lotsAndLotsOfPostLoopCode }
+    
+  - `vectorsNotNeedingDefines`: a set of vectors for which C ``#define`` statements for vector components are
+    not wanted.
+
+*@
+  @#
+  @# Defaults
+  @#
+  @set indexOverrides = indexOverrides or {}
+  @set vectorOverrides = vectorOverrides or []
+  @set preDimensionLoopOpeningCode = preDimensionLoopOpeningCode or {}
+  @set postDimensionLoopClosingCode = postDimensionLoopClosingCode or {}
+  @set vectorsNotNeedingDefines = vectorsNotNeedingDefines or set()
+  @#
+  @set $featureOrdering = ['Driver']
+  @set $featuresDict = { 'field': field,
+                         'basis': basis,
+                         'vectors': vectors,
+                         'indexOverrides': indexOverrides,
+                         'vectorOverrides': vectorOverrides,
+                         'preDimensionLoopOpeningCode': preDimensionLoopOpeningCode,
+                         'postDimensionLoopClosingCode': postDimensionLoopClosingCode,
+                       }
+${insertCodeForFeatures('loopOverFieldInBasisWithVectorsAndInnerContentBegin', featureOrdering, featuresDict)}@slurp
+  @#
+  @# Some vectors will need to have their index pointers set explicitly.
+  @# These will be those which belong to fields with different dimensions.
+  @set $vectorsRequiringExplictIndexPointers = set([v for v in vectors if v.field.dimensions != field.dimensions])
+  @# 
+  @# If we have a loopingOrder other than MemoryOrder, then the vectors in
+  @# field $field will also need their index pointers set explicitly
+  @if $loopingOrder != $LoopingOrder.MemoryOrder
+    @silent vectorsRequiringExplictIndexPointers.update($vectors)
+  @end if
+  @#
+  @# Now determine the vectors not requiring explicit index pointers
+  @set $vectorsNotRequiringExplicitIndexPointers = set(vectors).difference(vectorsRequiringExplictIndexPointers)
+  @#
+  @set $indentLevel = 0
+  @#
+  @# Initialise index pointers
+  @for $vector in $vectors
+    @#
+long _${vector.id}_index_pointer = 0;
+    @if vector in vectorsNotNeedingDefines
+      @pass
+    @elif vector in vectorOverrides
+      @# This vector is in vectorOverrides, so instead of #defining, we want to create variables
+      @for componentName in vector.components
+$vector.type $componentName;
+      @end for
+    @else
+      @# If vector isn't in vectorOverrides or vectorsNotNeedingDefines, then we want to #define the vector's components
+      @for $componentNumber, $componentName in enumerate($vector.components)
+#define $componentName _active_${vector.id}[_${vector.id}_index_pointer + $componentNumber]
+      @end for
+    @end if
+  @end for
+  @# loop over geometry dimensions creating dimension variable names for those that
+  @# aren't in this field, but are in any of the $vectors fields, unless we have an index override for it.
+  @for $dimension in $geometry.dimensions
+    @if $field.hasDimension($dimension)
+      @continue
+    @end if
+    @#
+    @if len([v for v in vectors if v.field.hasDimension(dimension)]) == 0
+      @continue
+    @end if
+    @#
+    @set $dimRep = dimension.inBasis(basis)
+    @if indexOverrides.has_key(dimRep.name)
+      @continue
+    @end if
+
+${dimRep.createCoordinateVariableForSinglePointSample}@slurp
+
+  @end for
+  @#
+  @# loop over the dimensions opening the loops
+  @set $lastLoopDimRep = None
+  @for dimRep in field.inBasis(basis)
+    @#
+    @if dimRep.name in preDimensionLoopOpeningCode
+${preDimensionLoopOpeningCode[$dimRep.name], extraIndent=$indentLevel}@slurp
+    @end if
+    @if not indexOverrides.has_key(dimRep.name)
+      @# If there isn't an indexOverride for this dimension, then open a loop
+      @set $lastLoopDimRep = dimRep
+      @#
+      @set $loopOpeningFeatureOrdering = ['OpenMP']
+      @silent featuresDict.update({
+        'vectorsNotRequiringExplicitIndexPointers': vectorsNotRequiringExplicitIndexPointers,
+        'dimRep': dimRep,
+        'loopCode': innerLoopCode
+      })
+${insertCodeForFeatures('loopOverFieldInBasisWithVectorsAndInnerContentLoopOpenBegin', loopOpeningFeatureOrdering, featuresDict), extraIndent=indentLevel}@slurp
+      @#
+${dimRep.openLoop(loopingOrder=loopingOrder), extraIndent=indentLevel}@slurp
+      @set $indentLevel = $indentLevel + 2
+${insertCodeForFeaturesInReverseOrder('loopOverFieldInBasisWithVectorsAndInnerContentLoopOpenEnd', loopOpeningFeatureOrdering, featuresDict), extraIndent=indentLevel}@slurp
+    @else
+      @# We have an indexOverride for this dimension. 
+${prologueForOverriddenDimRepInFieldInBasisWithVectors($dimRep, $field, $basis, $vectors, $indexOverrides), extraIndent=$indentLevel}@slurp
+    @end if
+    @#
+  @end for
+  @#
+  @set $result = $setExplicitIndexPointersForVectorsWithFieldAndBasis(vectorsRequiringExplictIndexPointers, field, basis, indexOverrides)
+  @if result
+${result, extraIndent=indentLevel}@slurp
+  @end if
+  @#
+${innerLoopCode, extraIndent=$indentLevel}@slurp
+${epilogueToIntegrateOverriddenVectorsForSamplingFieldInBasis(vectorOverrides, field, basis), extraIndent=indentLevel}@slurp
+  @#
+  @if lastLoopDimRep
+    @# Increment the index pointers. This needs to be in a function in order to be able
+    @# to use the variable indentation required
+${incrementIndexPointersForVectorsWithFieldBasisAndLastLoopDimRep(vectorsNotRequiringExplicitIndexPointers, field, basis, lastLoopDimRep), extraIndent=indentLevel}@slurp
+  @end if
+  @#
+  @# loop over the dimensions (in reverse order) closing the loops
+  @#
+  @for dimRep in reversed(field.inBasis(basis))
+    @#
+    @# If there isn't an indexOverride for this dimension, then reduce the indent and close the loop
+    @if not indexOverrides.has_key(dimRep.name)
+      @set $indentLevel = indentLevel - 2
+${dimRep.closeLoop(loopingOrder=loopingOrder), extraIndent=indentLevel}@slurp
+    @end if
+    @#
+    @if $dimRep.name in postDimensionLoopClosingCode
+${postDimensionLoopClosingCode[dimRep.name], extraIndent=indentLevel}@slurp
+    @end if
+    @#
+  @end for
+  @#
+  @# Undefine vector components that weren't in vectorOverrides
+  @for vector in vectors
+    @if vector in vectorOverrides or vector in vectorsNotNeedingDefines
+      @continue
+    @end if
+    @for componentName in vector.components
+#undef $componentName
+    @end for
+  @end for
+  @# loop over geometry dimensions undefining dimension step variable names for those that
+  @# aren't in this field, but are in any of the $vectors fields, unless we have an index override for it.
+  @for $dimension in $geometry.dimensions
+    @if $field.hasDimension($dimension)
+      @continue
+    @end if
+    @#
+    @if len([v for v in vectors if v.field.hasDimension(dimension)]) == 0
+      @continue
+    @end if
+    @#
+    @set $dimRep = dimension.inBasis(basis)
+    @if indexOverrides.has_key(dimRep.name)
+      @continue
+    @end if
+#undef d${dimRep.name}
+  @end for
+  @#
+${insertCodeForFeaturesInReverseOrder('loopOverFieldInBasisWithVectorsAndInnerContentEnd', featureOrdering, featuresDict)}@slurp
+  @#
+ at end def
+
+
+ at def prologueForOverriddenDimRepInFieldInBasisWithVectors($dimRep, $field, $basis, $vectors, $indexOverrides)
+@#doc: Insert prologue for dimension $dimension when its index variable has been overridden
+  @#
+  @# As this field contains this dimension, we must make sure that the indexOverride dictionary contains
+  @# a value for this field
+  @assert $indexOverrides[$dimRep.name].has_key(field)
+  @#
+unsigned long ${dimRep.loopIndex} = ${indexOverrides[dimRep.name][field]};
+  @# loop over the vectors in field $field, because we need to fix up their index pointers
+  @# and those vectors with the same dimensions
+  @for $vector in [v for v in vectors if v.field.dimensions == field.dimensions]
+_${vector.id}_index_pointer += ${dimRep.loopIndex}@slurp
+ * ${field.localPointsInDimensionsAfterDimRepInBasis(dimRep, basis)};
+  @end for
+
+  @#
+ at end def
+
+
+ at def setExplicitIndexPointersForVectorsWithFieldAndBasis($vectors, $field, $basis, $indexOverrides)
+@#doc: Set index pointers for those vectors requiring it to be set explicitly
+  @#
+  @# There's no need to (re-)set the index pointer for fields that have no dimensions
+  @set $vectorsNeedingExplicitIndexPointers = [vector for vector in vectors if vector.field.dimensions]
+  @if len(vectorsNeedingExplicitIndexPointers) == 0
+    @return
+  @end if
+  @#
+  @# For the vectors that are not in the field $field, set their index pointers
+// Set index pointers explicitly for (some) vectors
+  @for vector in vectorsNeedingExplicitIndexPointers
+    @#
+_${vector.id}_index_pointer = ( 0 at slurp
+    @for dimRep in vector.field.inBasis(basis)
+${explicitIndexPointerTermForVectorAndDimRepWithFieldAndBasis(vector, dimRep, field, basis, indexOverrides)}@slurp
+    @end for
+ ) * _${vector.id}_ncomponents;
+  @end for
+  @#
+ at end def
+
+ at def explicitIndexPointerTermForVectorAndDimRepWithFieldAndBasis($vector, $dimRep, $field, $basis, $indexOverrides)
+  @#
+  @# Blank line for output formatting
+
+  @# Not all of the dimensions in the vector's field's dimensions will necessarily
+  @# be in $field's dimensions, and we need to do slightly different things when they
+  @# aren't in $field's dimensions.
+  @#
+  @# First, check the case that they both have this dimension
+  @set fieldDimRepList = [dr for dr in field.inBasis(basis) if dr.name == dimRep.name]
+  @#
+  @if fieldDimRepList
+    @# First, consider when they both contain this dimension
+    @#
+    @assert len(fieldDimRepList) == 1
+    @set $fieldDimRep = fieldDimRepList[0]
+    @#
+    @# If the lattices are the same, then there is nothing special to be done for this dimension
+    @# We also require that there are neither dimension could have a local offset
+    @set $hasLocalOffset = dimRep.hasLocalOffset or fieldDimRep.hasLocalOffset
+    @if dimRep.runtimeLattice == fieldDimRep.runtimeLattice and not hasLocalOffset
+   + ${fieldDimRep.loopIndex}@slurp
+ * $vector.field.localPointsInDimensionsAfterDimRepInBasis(dimRep, basis)@slurp
+    @else
+   + ( ${dimRep.localIndexFromIndexForDimensionRep(fieldDimRep)} )@slurp
+ * $vector.field.localPointsInDimensionsAfterDimRepInBasis(dimRep, basis)@slurp
+    @end if
+  @else
+    @# Now, consider when $field doesn't contain this dimension. If this dimension has an index override, then
+    @# use the index pointers from that.
+    @if indexOverrides.has_key(dimRep.name)
+      @# We do have an index override for this dimension
+      @#
+      @# Check that we actually have an entry for this vector's field
+      @assert indexOverrides[dimRep.name].has_key(vector.field)
+   + ${indexOverrides[dimRep.name][vector.field]}@slurp
+  * $vector.field.localPointsInDimensionsAfterDimRepInBasis(dimRep, basis)@slurp
+    @else
+      @# We don't have an index override for this dimension.
+      @# What happens in this case depends on whether or not the vector
+      @# is in fourier space in this dimension. If it is, then we want to take its
+      @# value at k=0 (the first element in this dimension). If it isn't in fourier
+      @# space, then we want to take its element in the middle.
+      @#
+      @# Either way, this is handled by the dimension. But we can't have this dimension distributed.
+      @assert not dimRep.hasLocalOffset, "Can't do single point samples with the distributed-mpi driver."
+   + ( ${dimRep.indexForSinglePointSample} )@slurp
+  * $vector.field.localPointsInDimensionsAfterDimRepInBasis(dimRep, basis)@slurp
+    @end if
+  @end if
+  @#
+ at end def
+
+
+ at def epilogueToIntegrateOverriddenVectorsForSamplingFieldInBasis($vectorOverrides, $field, $basis)
+@#doc: Integrate the overridden vectors
+  @#
+  @# Loop over the overridden vectors
+  @for $vector in $vectorOverrides
+
+    @# Determine which dimensions are being integrated over (if any)
+    @# These are the ones that are in $field, but not in the vector's field
+    @set $dimensionsIntegratedOver = [dim for dim in field.dimensions if not vector.field.hasDimension(dim)]
+    @#
+    @# Loop over the components in each vector
+    @for $componentNumber, $componentName in enumerate($vector.components)
+_active_${vector.id}[_${vector.id}_index_pointer + ${componentNumber}] += ${componentName}@slurp
+      @# Loop over the dimensions
+      @for $dimension in $dimensionsIntegratedOver
+ * d${dimension.inBasis(basis).name}@slurp
+      @end for
+;
+    @end for
+  @end for
+  @#
+ at end def
+
+
+ at def incrementIndexPointersForVectorsWithFieldBasisAndLastLoopDimRep($vectors, $field, $basis, $lastLoopDimRep)
+@#doc: Increment index pointers but only for those in field `field` or in a field with the same dimensions.
+  @#
+  @# For the vectors that are in the field $field, increment their index pointers.
+  @#
+  @# If none of $vectors have field $field, then there's nothing to do
+  @if len(vectors) == 0
+    @return
+  @end if
+// Increment index pointers for vectors in field $field.name (or having the same dimensions)
+  @for vector in vectors
+    @# We can only do this for vectors in $field
+    @# or that have the same dimensions
+    @assert vector.field.dimensions == field.dimensions
+    @#
+    @# Now we need to increment the vector
+    @# We need to know the last loop dimension because we could be looping over the second last dimension and not the last
+    @# because the last was overridden by an indexOverride. Hence the step may not be _stuff_ncomponents,
+    @# but _stuff_latticeN * _stuff_ncomponents (etc.)
+    @# This is needed for cross-propagation when cross-propagating along the last dimension.
+_${vector.id}_index_pointer += $field.localPointsInDimensionsAfterDimRepInBasis(lastLoopDimRep, basis) * _${vector.id}_ncomponents;
+  @end for
+
+  @#
+ at end def
+
+ at def evaluateComputedVectors($vectors, $static = True)
+@*doc: 
+Evaluate the computed vectors in an appropriate order taking into account dependencies.  
+All noises vectors must have the same static/dynamic type as that passed in.
+*@
+  @#
+  @for vector in self.evaluationOrderForVectors(vectors, static, predicate = lambda x: x.isComputed)
+${vector.functions['evaluate'].call()}
+  @end for
+  @#
+ at end def
+
+ at def copyVectors($vectors, $destPrefix, $srcPrefix = None)
+@#doc: Copy the contents of `vecSrc` into `vecDest`
+  @#
+  @for $vector in $vectors
+memcpy(${destPrefix}_${vector.id}, ${srcPrefix}_${vector.id}, sizeof(${vector.type}) * ${vector.allocSize});
+  @end for
+  @#
+ at end def
+
diff --git a/xpdeint/ScriptParser.py b/xpdeint/ScriptParser.py
new file mode 100644
index 0000000..d71f797
--- /dev/null
+++ b/xpdeint/ScriptParser.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+ScriptParser.py
+
+Created by Graham Dennis on 2007-12-29.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+## Subclasses for parsing specific scripts types should
+## override the following functions:
+##
+### canParseXMLDocument
+### -- return whether the subclass can parse the document
+### parseXMLDocument
+### --- return the top-level SimulationElement after parsing
+###     the script.
+
+class ScriptParser(object):
+    def canParseXMLDocument(self, xmlDocument):
+        return False
+    
+    def parseXMLDocument(self, xmlDocument, globalNameSpace):
+        return None
+    
+    def applyAttributeDictionaryToObject(self, attrDict, obj):
+        for attrName, attrValue in attrDict.iteritems():
+            setattr(obj, attrName, attrValue)
+    
+
diff --git a/xpdeint/Segments/BreakpointSegment.py b/xpdeint/Segments/BreakpointSegment.py
new file mode 100644
index 0000000..4488c65
--- /dev/null
+++ b/xpdeint/Segments/BreakpointSegment.py
@@ -0,0 +1,340 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Segments._BreakpointSegment import _BreakpointSegment
+from xpdeint.CallOnceGuards import callOnceGuard
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.320684
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Segments/BreakpointSegment.tmpl'
+__CHEETAH_srcLastModified__ = 'Wed Aug  1 11:52:34 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class BreakpointSegment(_BreakpointSegment):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(BreakpointSegment, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: segment $segmentNumber (Breakpoint) at line 28, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''segment ''')
+        _v = VFFSL(SL,"segmentNumber",True) # u'$segmentNumber' on line 28, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'$segmentNumber')) # from line 28, col 27.
+        write(u''' (Breakpoint)''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOnceGuard
+    def static_globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def static_globals at line 34, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(BreakpointSegment, self).static_globals()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''long _breakpointAutoNameCounter = 0;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def segmentFunctionBody(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def segmentFunctionBody($function) at line 45, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        _v = VFFSL(SL,"evaluateComputedVectors",False)(VFFSL(SL,"dependencies",True)) # u'${evaluateComputedVectors($dependencies)}' on line 46, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${evaluateComputedVectors($dependencies)}')) # from line 46, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"dependencies",True), VFFSL(SL,"breakpointBasis",True)) # u'${transformVectorsToBasis($dependencies, $breakpointBasis)}' on line 48, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($dependencies, $breakpointBasis)}')) # from line 48, col 1.
+        write(u'''
+''')
+        featureOrdering = ['Driver']
+        dict = {'extraIndent': 0}
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('breakpointBegin', featureOrdering, dict) # u"${insertCodeForFeatures('breakpointBegin', featureOrdering, dict)}" on line 52, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('breakpointBegin', featureOrdering, dict)}")) # from line 52, col 1.
+        extraIndent = dict['extraIndent']
+        write(u'''
+''')
+        _v = VFFSL(SL,"breakpointFunctionContents",True) # u'${breakpointFunctionContents, extraIndent=extraIndent}' on line 55, col 1
+        if _v is not None: write(_filter(_v, extraIndent=extraIndent, rawExpr=u'${breakpointFunctionContents, extraIndent=extraIndent}')) # from line 55, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('breakpointEnd', VFFSL(SL,"featureOrdering",True), dict) # u"${insertCodeForFeaturesInReverseOrder('breakpointEnd', $featureOrdering, dict)}" on line 57, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeaturesInReverseOrder('breakpointEnd', $featureOrdering, dict)}")) # from line 57, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def breakpointFunctionContents(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def breakpointFunctionContents at line 61, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''char *_baseFilename = (char*)malloc(255);
+''')
+        if not VFFSL(SL,"filename",True): # generated from line 64, col 3
+            #  If we don't have a filename, then we are auto-naming
+            write(u'''_breakpointAutoNameCounter++;
+snprintf(_baseFilename, 255, "%li%s", _breakpointAutoNameCounter, gsArgsAndValues.c_str());
+''')
+        else: # generated from line 68, col 3
+            #  We have a name, rip off the extension if its 'xsil'
+            baseFilename = VFFSL(SL,"filename",True)
+            if baseFilename.endswith('.xsil'): # generated from line 71, col 5
+                baseFilename = baseFilename[0:-5]
+            write(u'''snprintf(_baseFilename, 255, "%s%s", "''')
+            _v = VFFSL(SL,"baseFilename",True) # u'$baseFilename' on line 74, col 39
+            if _v is not None: write(_filter(_v, rawExpr=u'$baseFilename')) # from line 74, col 39.
+            write(u'''", gsArgsAndValues.c_str());
+''')
+        write(u'''
+''')
+        featureOrdering = ['Output']
+        _v = VFN(VFFSL(SL,"outputFormat",True),"writeOutSetup",False)('_baseFilename', self) # u"${outputFormat.writeOutSetup('_baseFilename', self)}" on line 78, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${outputFormat.writeOutSetup('_baseFilename', self)}")) # from line 78, col 1.
+        write(u'''
+''')
+        dependentVariables = [{'vector': vector, 'arrayName': ''.join([u'_active_',str(VFFSL(SL,"vector.id",True))]), 'components': vector.components} for vector in VFFSL(SL,"dependencies",True)]
+        writeOutDict = {'field': VFFSL(SL,"field",True),                        'basis': VFFSL(SL,"breakpointBasis",True),                        'fp': '_outfile',                        'baseFilename': "_baseFilename",                        'outputGroupFilenameSuffix': '',                        'dependentVariables': dependentVariables,                        'xsilElementName': "breakpoint",                        'groupID': 1                       }
+        _v = VFN(VFFSL(SL,"outputFormat",True),"writeOutFunctionImplementationBody",False)(writeOutDict) # u'${outputFormat.writeOutFunctionImplementationBody(writeOutDict)}' on line 90, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${outputFormat.writeOutFunctionImplementationBody(writeOutDict)}')) # from line 90, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"outputFormat.writeOutTearDown",True) # u'${outputFormat.writeOutTearDown}' on line 92, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${outputFormat.writeOutTearDown}')) # from line 92, col 1.
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # BreakpointSegment.tmpl
+        # 
+        # Created by Graham Dennis on 2008-03-15.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+''')
+        # 
+        #   Description of template
+        write(u'''
+''')
+        # 
+        #   Static globals
+        write(u'''
+''')
+        # 
+        #   Function implementations
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_BreakpointSegment= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(BreakpointSegment, '_initCheetahAttributes'):
+    templateAPIClass = getattr(BreakpointSegment, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(BreakpointSegment)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=BreakpointSegment()).run()
+
+
diff --git a/xpdeint/Segments/BreakpointSegment.tmpl b/xpdeint/Segments/BreakpointSegment.tmpl
new file mode 100644
index 0000000..774756a
--- /dev/null
+++ b/xpdeint/Segments/BreakpointSegment.tmpl
@@ -0,0 +1,96 @@
+@*
+BreakpointSegment.tmpl
+
+Created by Graham Dennis on 2008-03-15.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Segments._BreakpointSegment
+ at from xpdeint.CallOnceGuards import callOnceGuard
+
+@*
+  Description of template
+*@
+ at def description: segment $segmentNumber (Breakpoint)
+
+@*
+  Static globals
+*@
+@@callOnceGuard
+ at def static_globals
+  @#
+  @super
+  @#
+long _breakpointAutoNameCounter = 0;
+  @#
+ at end def
+
+@*
+  Function implementations
+*@
+ at def segmentFunctionBody($function)
+${evaluateComputedVectors($dependencies)}@slurp
+
+${transformVectorsToBasis($dependencies, $breakpointBasis)}@slurp
+
+  @set $featureOrdering = ['Driver']
+  @set $dict = {'extraIndent': 0}
+${insertCodeForFeatures('breakpointBegin', featureOrdering, dict)}@slurp
+  @set $extraIndent = dict['extraIndent']
+
+${breakpointFunctionContents, extraIndent=extraIndent}@slurp
+
+${insertCodeForFeaturesInReverseOrder('breakpointEnd', $featureOrdering, dict)}@slurp
+  @#
+ at end def
+
+ at def breakpointFunctionContents
+  @#
+char *_baseFilename = (char*)malloc(255);
+  @if not $filename
+    @# If we don't have a filename, then we are auto-naming
+_breakpointAutoNameCounter++;
+snprintf(_baseFilename, 255, "%li%s", _breakpointAutoNameCounter, gsArgsAndValues.c_str());
+  @else
+    @# We have a name, rip off the extension if its 'xsil'
+    @set baseFilename = $filename
+    @if baseFilename.endswith('.xsil')
+      @set baseFilename = baseFilename[0:-5]
+    @end if
+snprintf(_baseFilename, 255, "%s%s", "$baseFilename", gsArgsAndValues.c_str());
+  @end if
+
+  @set featureOrdering = ['Output']
+${outputFormat.writeOutSetup('_baseFilename', self)}@slurp
+
+  @set $dependentVariables = [{'vector': vector, 'arrayName': c'_active_${vector.id}', 'components': vector.components} for vector in $dependencies]
+  @set $writeOutDict = {'field': $field,
+                        'basis': $breakpointBasis,
+                        'fp': '_outfile',
+                        'baseFilename': "_baseFilename",
+                        'outputGroupFilenameSuffix': '',
+                        'dependentVariables': dependentVariables,
+                        'xsilElementName': "breakpoint",
+                        'groupID': 1
+                       }
+${outputFormat.writeOutFunctionImplementationBody(writeOutDict)}@slurp
+
+${outputFormat.writeOutTearDown}@slurp
+
+  @#
+ at end def
+
diff --git a/xpdeint/Segments/FilterSegment.py b/xpdeint/Segments/FilterSegment.py
new file mode 100644
index 0000000..488f2d4
--- /dev/null
+++ b/xpdeint/Segments/FilterSegment.py
@@ -0,0 +1,226 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Segments._FilterSegment import _FilterSegment
+from xpdeint.CallOnceGuards import callOncePerInstanceGuard
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.341438
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Segments/FilterSegment.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class FilterSegment(_FilterSegment):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(FilterSegment, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: segment $segmentNumber (Filter) at line 28, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''segment ''')
+        _v = VFFSL(SL,"segmentNumber",True) # u'$segmentNumber' on line 28, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'$segmentNumber')) # from line 28, col 27.
+        write(u''' (Filter)''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def segmentFunctionBody(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def segmentFunctionBody($function) at line 33, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        _v = VFFSL(SL,"evaluateComputedVectors",False)(VFFSL(SL,"dynamicVectorsNeedingPrecalculationForOperatorContainers",False)(VFFSL(SL,"operatorContainers",True))) # u'${evaluateComputedVectors($dynamicVectorsNeedingPrecalculationForOperatorContainers($operatorContainers))}' on line 34, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${evaluateComputedVectors($dynamicVectorsNeedingPrecalculationForOperatorContainers($operatorContainers))}')) # from line 34, col 1.
+        # 
+        for operatorContainer in VFFSL(SL,"operatorContainers",True): # generated from line 36, col 3
+            write(u'''
+''')
+            _v = VFN(VFFSL(SL,"operatorContainer",True),"evaluateOperators",False)(parentFunction = function) # u'${operatorContainer.evaluateOperators(parentFunction = function)}' on line 38, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${operatorContainer.evaluateOperators(parentFunction = function)}')) # from line 38, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # FilterSegment.tmpl
+        # 
+        # Created by Graham Dennis on 2008-03-13.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+''')
+        # 
+        #   Description of template
+        write(u'''
+''')
+        # 
+        #   Function implementations
+        write(u'''
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_FilterSegment= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(FilterSegment, '_initCheetahAttributes'):
+    templateAPIClass = getattr(FilterSegment, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(FilterSegment)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=FilterSegment()).run()
+
+
diff --git a/xpdeint/Segments/FilterSegment.tmpl b/xpdeint/Segments/FilterSegment.tmpl
new file mode 100644
index 0000000..4e12dbc
--- /dev/null
+++ b/xpdeint/Segments/FilterSegment.tmpl
@@ -0,0 +1,42 @@
+@*
+FilterSegment.tmpl
+
+Created by Graham Dennis on 2008-03-13.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Segments._FilterSegment
+ at from xpdeint.CallOnceGuards import callOncePerInstanceGuard
+
+@*
+  Description of template
+*@
+ at def description: segment $segmentNumber (Filter)
+
+@*
+  Function implementations
+*@
+ at def segmentFunctionBody($function)
+${evaluateComputedVectors($dynamicVectorsNeedingPrecalculationForOperatorContainers($operatorContainers))}@slurp
+  @#
+  @for $operatorContainer in $operatorContainers
+
+${operatorContainer.evaluateOperators(parentFunction = function)}@slurp
+  @end for
+  @#
+ at end def
+
diff --git a/xpdeint/Segments/Integrators/AdaptiveStep.py b/xpdeint/Segments/Integrators/AdaptiveStep.py
new file mode 100644
index 0000000..494b95d
--- /dev/null
+++ b/xpdeint/Segments/Integrators/AdaptiveStep.py
@@ -0,0 +1,1223 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Segments.Integrators.Integrator import Integrator
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.44971
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Segments/Integrators/AdaptiveStep.tmpl'
+__CHEETAH_srcLastModified__ = 'Mon Sep  3 14:15:51 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class AdaptiveStep(Integrator):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(AdaptiveStep, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: segment $segmentNumber ($stepper.name adaptive-step integrator) at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''segment ''')
+        _v = VFFSL(SL,"segmentNumber",True) # u'$segmentNumber' on line 24, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'$segmentNumber')) # from line 24, col 27.
+        write(u''' (''')
+        _v = VFFSL(SL,"stepper.name",True) # u'$stepper.name' on line 24, col 43
+        if _v is not None: write(_filter(_v, rawExpr=u'$stepper.name')) # from line 24, col 43.
+        write(u''' adaptive-step integrator)''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def functionPrototypes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def functionPrototypes at line 29, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(AdaptiveStep, self).functionPrototypes()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''real _segment''')
+        _v = VFFSL(SL,"segmentNumber",True) # u'${segmentNumber}' on line 33, col 14
+        if _v is not None: write(_filter(_v, rawExpr=u'${segmentNumber}')) # from line 33, col 14.
+        write(u'''_setup_sampling(bool* _next_sample_flag, long* _next_sample_counter);
+''')
+        # 
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 35, col 3
+            write(u'''real _segment''')
+            _v = VFFSL(SL,"segmentNumber",True) # u'${segmentNumber}' on line 36, col 14
+            if _v is not None: write(_filter(_v, rawExpr=u'${segmentNumber}')) # from line 36, col 14.
+            write(u'''_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 36, col 31
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 36, col 31.
+            write(u'''_timestep_error(''')
+            _v = VFFSL(SL,"vector.type",True) # u'${vector.type}' on line 36, col 59
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.type}')) # from line 36, col 59.
+            write(u'''* _checkfield);
+bool _segment''')
+            _v = VFFSL(SL,"segmentNumber",True) # u'${segmentNumber}' on line 37, col 14
+            if _v is not None: write(_filter(_v, rawExpr=u'${segmentNumber}')) # from line 37, col 14.
+            write(u'''_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 37, col 31
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 37, col 31.
+            write(u'''_reset(''')
+            _v = VFFSL(SL,"vector.type",True) # u'${vector.type}' on line 37, col 50
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.type}')) # from line 37, col 50.
+            write(u'''* _reset_to);
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def functionImplementations(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def functionImplementations at line 46, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(AdaptiveStep, self).functionImplementations()
+        if _v is not None: write(_filter(_v))
+        # 
+        _v = VFFSL(SL,"setupSamplingFunctionImplementation",True) # u'${setupSamplingFunctionImplementation}' on line 50, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${setupSamplingFunctionImplementation}')) # from line 50, col 1.
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 51, col 3
+            write(u'''
+''')
+            _v = VFFSL(SL,"timestepErrorFunctionImplementation",False)(VFFSL(SL,"vector",True)) # u'${timestepErrorFunctionImplementation($vector)}' on line 53, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${timestepErrorFunctionImplementation($vector)}')) # from line 53, col 1.
+            write(u'''
+''')
+            _v = VFFSL(SL,"resetFunctionImplementation",False)(VFFSL(SL,"vector",True)) # u'${resetFunctionImplementation($vector)}' on line 55, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${resetFunctionImplementation($vector)}')) # from line 55, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def setupSamplingFunctionImplementation(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def setupSamplingFunctionImplementation at line 61, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''real _segment''')
+        _v = VFFSL(SL,"segmentNumber",True) # u'${segmentNumber}' on line 63, col 14
+        if _v is not None: write(_filter(_v, rawExpr=u'${segmentNumber}')) # from line 63, col 14.
+        write(u'''_setup_sampling(bool* _next_sample_flag, long* _next_sample_counter)
+{
+  // The numbers of the moment groups that need to be sampled at the next sampling point.
+  // An entry of N+1 means "reached end of integration interval"
+  long _momentGroupNumbersNeedingSamplingNext[''')
+        _v = VFFSL(SL,"len",False)(VFFSL(SL,"samples",True)) + 1 # u'${len($samples) + 1}' on line 67, col 47
+        if _v is not None: write(_filter(_v, rawExpr=u'${len($samples) + 1}')) # from line 67, col 47.
+        write(u'''];
+  long _numberOfMomentGroupsToBeSampledNext = 1;
+  
+  long _previous_m = 1;
+  long _previous_M = 1;
+  
+  real _''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 73, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 73, col 9.
+        write(u'''_break_next = (real)''')
+        _v = VFFSL(SL,"interval",True) # u'${interval}' on line 73, col 52
+        if _v is not None: write(_filter(_v, rawExpr=u'${interval}')) # from line 73, col 52.
+        write(u''';
+  _momentGroupNumbersNeedingSamplingNext[0] = ''')
+        _v = VFFSL(SL,"len",False)(VFFSL(SL,"samples",True)) # u'${len($samples)}' on line 74, col 47
+        if _v is not None: write(_filter(_v, rawExpr=u'${len($samples)}')) # from line 74, col 47.
+        write(u''';
+  
+  // initialise all flags to false
+  for (long _i0 = 0; _i0 < ''')
+        _v = VFFSL(SL,"len",False)(VFFSL(SL,"samples",True)) + 1 # u'${len($samples) + 1}' on line 77, col 28
+        if _v is not None: write(_filter(_v, rawExpr=u'${len($samples) + 1}')) # from line 77, col 28.
+        write(u'''; _i0++)
+    _next_sample_flag[_i0] = false;
+  
+  /* Check if moment group needs sampling at the same time as another already discovered sample (or the final time).
+   * If so, add this moment group to the to-be-sampled list. If moment group demands sampling earlier than all
+   * previously noted moment groups, erase all previous ones from list and set the sample time to this earlier one.
+   */
+''')
+        for momentGroupNumber, sampleCount in enumerate(VFFSL(SL,"samples",True)): # generated from line 84, col 3
+            if VFFSL(SL,"sampleCount",True) == 0: # generated from line 85, col 5
+                continue
+            write(u'''  if (_next_sample_counter[''')
+            _v = VFFSL(SL,"momentGroupNumber",True) # u'$momentGroupNumber' on line 88, col 28
+            if _v is not None: write(_filter(_v, rawExpr=u'$momentGroupNumber')) # from line 88, col 28.
+            write(u'''] * _previous_M == _previous_m * ''')
+            _v = VFFSL(SL,"sampleCount",True) # u'$sampleCount' on line 88, col 79
+            if _v is not None: write(_filter(_v, rawExpr=u'$sampleCount')) # from line 88, col 79.
+            write(u''') {
+    _momentGroupNumbersNeedingSamplingNext[_numberOfMomentGroupsToBeSampledNext] = ''')
+            _v = VFFSL(SL,"momentGroupNumber",True) # u'$momentGroupNumber' on line 89, col 84
+            if _v is not None: write(_filter(_v, rawExpr=u'$momentGroupNumber')) # from line 89, col 84.
+            write(u''';
+    _numberOfMomentGroupsToBeSampledNext++;
+  } else if (_next_sample_counter[''')
+            _v = VFFSL(SL,"momentGroupNumber",True) # u'$momentGroupNumber' on line 91, col 35
+            if _v is not None: write(_filter(_v, rawExpr=u'$momentGroupNumber')) # from line 91, col 35.
+            write(u'''] * _previous_M < _previous_m * ''')
+            _v = VFFSL(SL,"sampleCount",True) # u'$sampleCount' on line 91, col 85
+            if _v is not None: write(_filter(_v, rawExpr=u'$sampleCount')) # from line 91, col 85.
+            write(u''') {
+    _''')
+            _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 92, col 6
+            if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 92, col 6.
+            write(u'''_break_next = _next_sample_counter[''')
+            _v = VFFSL(SL,"momentGroupNumber",True) # u'$momentGroupNumber' on line 92, col 64
+            if _v is not None: write(_filter(_v, rawExpr=u'$momentGroupNumber')) # from line 92, col 64.
+            write(u'''] * ((real)''')
+            _v = VFFSL(SL,"interval",True) # u'$interval' on line 92, col 93
+            if _v is not None: write(_filter(_v, rawExpr=u'$interval')) # from line 92, col 93.
+            write(u''') / ((real)''')
+            _v = VFFSL(SL,"sampleCount",True) # u'$sampleCount' on line 92, col 113
+            if _v is not None: write(_filter(_v, rawExpr=u'$sampleCount')) # from line 92, col 113.
+            write(u''');
+    _numberOfMomentGroupsToBeSampledNext = 1;
+    _momentGroupNumbersNeedingSamplingNext[0] = ''')
+            _v = VFFSL(SL,"momentGroupNumber",True) # u'$momentGroupNumber' on line 94, col 49
+            if _v is not None: write(_filter(_v, rawExpr=u'$momentGroupNumber')) # from line 94, col 49.
+            write(u''';
+    _previous_M = ''')
+            _v = VFFSL(SL,"sampleCount",True) # u'$sampleCount' on line 95, col 19
+            if _v is not None: write(_filter(_v, rawExpr=u'$sampleCount')) # from line 95, col 19.
+            write(u''';
+    _previous_m = _next_sample_counter[''')
+            _v = VFFSL(SL,"momentGroupNumber",True) # u'$momentGroupNumber' on line 96, col 40
+            if _v is not None: write(_filter(_v, rawExpr=u'$momentGroupNumber')) # from line 96, col 40.
+            write(u'''];
+  }
+  
+''')
+        write(u'''  // _momentGroupNumbersNeedingSamplingNext now contains the complete list of moment groups that need
+  // to be sampled at the next sampling point. Set their flags to true.
+  for (long _i0 = 0; _i0 < _numberOfMomentGroupsToBeSampledNext; _i0++)
+    _next_sample_flag[_momentGroupNumbersNeedingSamplingNext[_i0]] = true;
+  
+  return _''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 105, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 105, col 11.
+        write(u'''_break_next;
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def timestepErrorFunctionImplementation(self, vector, **KWS):
+
+
+
+        ## CHEETAH: generated from @def timestepErrorFunctionImplementation($vector) at line 111, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''real _segment''')
+        _v = VFFSL(SL,"segmentNumber",True) # u'${segmentNumber}' on line 113, col 14
+        if _v is not None: write(_filter(_v, rawExpr=u'${segmentNumber}')) # from line 113, col 14.
+        write(u'''_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 113, col 31
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 113, col 31.
+        write(u'''_timestep_error(''')
+        _v = VFFSL(SL,"vector.type",True) # u'${vector.type}' on line 113, col 59
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.type}')) # from line 113, col 59.
+        write(u'''* _checkfield)
+{
+  real _error = 1e-24;
+  real _temp_error = 0.0;
+  real _temp_mod = 0.0;
+
+''')
+        featureOrdering = ['Diagnostics']
+        dict = {'vector': vector}
+        write(u'''  ''')
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('timestepErrorBegin', featureOrdering, {'vector': vector}) # u"${insertCodeForFeatures('timestepErrorBegin', featureOrdering, {'vector': vector}), autoIndent=True}" on line 121, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeatures('timestepErrorBegin', featureOrdering, {'vector': vector}), autoIndent=True}")) # from line 121, col 3.
+        write(u'''  
+''')
+        if len(VFFSL(SL,"vector.field.dimensions",True)) > 0: # generated from line 123, col 3
+            #  FIXME: We need to have the capacity to have both a peak cutoff and an absolute cutoff
+            write(u'''  // Find the peak value for each component of the field
+  real _cutoff[_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 126, col 17
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 126, col 17.
+            write(u'''_ncomponents];
+  
+  for (long _i0 = 0; _i0 < _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 128, col 29
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 128, col 29.
+            write(u'''_ncomponents; _i0++)
+    _cutoff[_i0] = 0.0;
+  
+  {
+    ''')
+            _v = VFFSL(SL,"loopOverVectorsInBasisWithInnerContent",False)([vector], VFFSL(SL,"homeBasis",True), VFFSL(SL,"insideFindPeakLoops",False)(vector)) # u'${loopOverVectorsInBasisWithInnerContent([vector], $homeBasis, $insideFindPeakLoops(vector)), autoIndent=True}' on line 132, col 5
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${loopOverVectorsInBasisWithInnerContent([vector], $homeBasis, $insideFindPeakLoops(vector)), autoIndent=True}')) # from line 132, col 5.
+            write(u'''  }
+  ''')
+            _v = VFFSL(SL,"insertCodeForFeatures",False)('findMax', ['Driver'], {'variable': '_cutoff', 'count': ''.join([u'_',str(VFFSL(SL,"vector.id",True)),u'_ncomponents'])}) # u"${insertCodeForFeatures('findMax', ['Driver'], {'variable': '_cutoff', 'count': c'_${vector.id}_ncomponents'}), autoIndent=True}" on line 134, col 3
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeatures('findMax', ['Driver'], {'variable': '_cutoff', 'count': c'_${vector.id}_ncomponents'}), autoIndent=True}")) # from line 134, col 3.
+            write(u'''  
+  for (long _i0 = 0; _i0 < _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 136, col 29
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 136, col 29.
+            write(u'''_ncomponents; _i0++) {
+    if (_xmds_isnonfinite(_cutoff[_i0]))
+      // Return an error two times the tolerance in this case because the timestep must be reduced.
+      return 2.0*''')
+            _v = VFFSL(SL,"tolerance",True) # u'${tolerance}' on line 139, col 18
+            if _v is not None: write(_filter(_v, rawExpr=u'${tolerance}')) # from line 139, col 18.
+            write(u''';
+    _cutoff[_i0] *= ''')
+            _v = VFFSL(SL,"cutoff",True) # u'${cutoff}' on line 140, col 21
+            if _v is not None: write(_filter(_v, rawExpr=u'${cutoff}')) # from line 140, col 21.
+            write(u''';
+''')
+            if VFFSL(SL,"vector.type",True) == 'complex': # generated from line 141, col 5
+                #  multiply again because we are using norm for our complex vector and the cutoff should be interpreted in terms of
+                #  the absolute magnitude of the variables, not the mod-square
+                write(u'''    _cutoff[_i0] *= ''')
+                _v = VFFSL(SL,"cutoff",True) # u'${cutoff}' on line 144, col 21
+                if _v is not None: write(_filter(_v, rawExpr=u'${cutoff}')) # from line 144, col 21.
+                write(u''';
+''')
+            write(u'''  }
+''')
+        write(u'''  
+''')
+        #  Code for absolute cutoff should go here and modify
+        #  the _cutoff variables
+        # 
+        #  @for $absoluteCutoff in $absoluteCutoffs
+        #  // absolute cutoff for component '$absoluteCutoff.name'
+        #  if (_cutoff[${absoluteCutoff.componentIndex}])
+        #  @end for
+        # 
+        write(u'''  {
+    ''')
+        _v = VFFSL(SL,"loopOverVectorsInBasisWithInnerContent",False)([vector], VFFSL(SL,"homeBasis",True), VFFSL(SL,"insideFindMaxErrorLoops",False)(vector)) # u'${loopOverVectorsInBasisWithInnerContent([vector], $homeBasis, $insideFindMaxErrorLoops(vector)), autoIndent=True}' on line 158, col 5
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${loopOverVectorsInBasisWithInnerContent([vector], $homeBasis, $insideFindMaxErrorLoops(vector)), autoIndent=True}')) # from line 158, col 5.
+        write(u'''  }
+  ''')
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('findMax', ['Driver'], {'variable': '&_error', 'count': '1'}) # u"${insertCodeForFeatures('findMax', ['Driver'], {'variable': '&_error', 'count': '1'}), autoIndent=True}" on line 160, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeatures('findMax', ['Driver'], {'variable': '&_error', 'count': '1'}), autoIndent=True}")) # from line 160, col 3.
+        write(u'''  ''')
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('timestepErrorEnd', featureOrdering, dict) # u"${insertCodeForFeaturesInReverseOrder('timestepErrorEnd', featureOrdering, dict), autoIndent=True}" on line 161, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeaturesInReverseOrder('timestepErrorEnd', featureOrdering, dict), autoIndent=True}")) # from line 161, col 3.
+        write(u'''  
+  return _error;
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideFindPeakLoops(self, vector, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideFindPeakLoops($vector) at line 169, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''for (long _i1 = 0; _i1 < _''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 171, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 171, col 27.
+        write(u'''_ncomponents; _i1++) {
+''')
+        if VFFSL(SL,"vector.type",True) == 'complex': # generated from line 172, col 3
+            modFunction = 'mod2'
+        else: # generated from line 174, col 3
+            modFunction = 'abs'
+        write(u'''  _temp_mod = ''')
+        _v = VFFSL(SL,"modFunction",True) # u'${modFunction}' on line 177, col 15
+        if _v is not None: write(_filter(_v, rawExpr=u'${modFunction}')) # from line 177, col 15.
+        write(u'''(_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 177, col 31
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 177, col 31.
+        write(u'''[_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 177, col 45
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 177, col 45.
+        write(u'''_index_pointer + _i1]);
+  if (_xmds_isnonfinite(_temp_mod))
+    _cutoff[_i1] = INFINITY;
+  else if (_cutoff[_i1] < _temp_mod)
+    _cutoff[_i1] = _temp_mod;
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideFindMaxErrorLoops(self, vector, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideFindMaxErrorLoops($vector) at line 187, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''for (long  _i1 = 0; _i1 < _''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 189, col 28
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 189, col 28.
+        write(u'''_ncomponents; _i1++) {
+''')
+        if VFFSL(SL,"vector.type",True) == 'complex': # generated from line 190, col 3
+            modCutoffFunction = 'mod2'
+        else: # generated from line 192, col 3
+            modCutoffFunction = 'abs'
+        if len(VFFSL(SL,"vector.field.dimensions",True)) > 0: # generated from line 195, col 3
+            write(u'''  if (''')
+            _v = VFFSL(SL,"modCutoffFunction",True) # u'${modCutoffFunction}' on line 196, col 7
+            if _v is not None: write(_filter(_v, rawExpr=u'${modCutoffFunction}')) # from line 196, col 7.
+            write(u'''(_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 196, col 29
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 196, col 29.
+            write(u'''[_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 196, col 43
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 196, col 43.
+            write(u'''_index_pointer + _i1]) > _cutoff[_i1]) {
+    ''')
+            _v = VFFSL(SL,"updateMaximumError",False)(VFFSL(SL,"vector",True)) # u'${updateMaximumError($vector), autoIndent=True}' on line 197, col 5
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${updateMaximumError($vector), autoIndent=True}')) # from line 197, col 5.
+            write(u'''  }
+''')
+        else: # generated from line 199, col 3
+            write(u'''  ''')
+            _v = VFFSL(SL,"updateMaximumError",False)(VFFSL(SL,"vector",True)) # u'${updateMaximumError($vector), autoIndent=True}' on line 200, col 3
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${updateMaximumError($vector), autoIndent=True}')) # from line 200, col 3.
+        write(u'''}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideLookForNaNLoops(self, vector, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideLookForNaNLoops($vector) at line 206, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  No point in fancy logic trying to exit the test early if a NaN is found, even
+        #  though this is hot path code, since a NaN means we're about to exit the simulation
+        #  anyway. Worth having seperate code depending on whether the vector values are
+        #  real or complex though, since complex requires either two checks or taking the
+        #  modulus. Presumably two seperate Re(), Im() checks are faster than mod2
+        # 
+        write(u'''  for (long _i1 = 0; _i1 < _''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 214, col 29
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 214, col 29.
+        write(u'''_ncomponents; _i1++) {
+''')
+        if VFFSL(SL,"vector.type",True) == 'complex': # generated from line 215, col 3
+            write(u'''    if (_xmds_isnonfinite(_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 216, col 28
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 216, col 28.
+            write(u'''[_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 216, col 42
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 216, col 42.
+            write(u'''_index_pointer + _i1].Re())
+      || _xmds_isnonfinite(_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 217, col 29
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 217, col 29.
+            write(u'''[_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 217, col 43
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 217, col 43.
+            write(u'''_index_pointer + _i1].Im())) bNoNaNsPresent = false;
+''')
+        else: # generated from line 218, col 3
+            write(u'''    if (_xmds_isnonfinite(_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 219, col 28
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 219, col 28.
+            write(u'''[_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 219, col 42
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 219, col 42.
+            write(u'''_index_pointer + _i1])) bNoNaNsPresent = false;
+''')
+        write(u'''  }
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def updateMaximumError(self, vector, **KWS):
+
+
+
+        ## CHEETAH: generated from @def updateMaximumError($vector) at line 225, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''_temp_error = abs(_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 227, col 20
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 227, col 20.
+        write(u'''[_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 227, col 34
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 227, col 34.
+        write(u'''_index_pointer + _i1] - _checkfield[_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 227, col 83
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 227, col 83.
+        write(u'''_index_pointer + _i1]) / (0.5*abs(_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 227, col 130
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 227, col 130.
+        write(u'''[_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 227, col 144
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 227, col 144.
+        write(u'''_index_pointer + _i1]) + 0.5*abs(_checkfield[_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 227, col 202
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 227, col 202.
+        write(u'''_index_pointer + _i1]));
+
+if (_xmds_isnonfinite(_temp_error)) {
+  /* For _temp_error to be NaN, both the absolute value of the higher and lower order solutions
+     must BOTH be zero. This therefore implies that their difference is zero, and that there is no error. */
+  _temp_error = 0.0;
+}
+
+if (_error < _temp_error) // UNVECTORISABLE
+  _error = _temp_error;
+''')
+        # 
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('updateMaximumError', ['Diagnostics'], {'vector': vector}) # u"${insertCodeForFeatures('updateMaximumError', ['Diagnostics'], {'vector': vector})}" on line 238, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('updateMaximumError', ['Diagnostics'], {'vector': vector})}")) # from line 238, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def resetFunctionImplementation(self, vector, **KWS):
+
+
+
+        ## CHEETAH: generated from @def resetFunctionImplementation($vector) at line 243, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''bool _segment''')
+        _v = VFFSL(SL,"segmentNumber",True) # u'${segmentNumber}' on line 245, col 14
+        if _v is not None: write(_filter(_v, rawExpr=u'${segmentNumber}')) # from line 245, col 14.
+        write(u'''_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 245, col 31
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 245, col 31.
+        write(u'''_reset(''')
+        _v = VFFSL(SL,"vector.type",True) # u'${vector.type}' on line 245, col 50
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.type}')) # from line 245, col 50.
+        write(u'''* _reset_to_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 245, col 76
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 245, col 76.
+        write(u''')
+{
+  ''')
+        _v = VFFSL(SL,"copyVectors",False)([vector], destPrefix = '', srcPrefix = '_reset_to') # u"${copyVectors([vector], destPrefix = '', srcPrefix = '_reset_to'), autoIndent=True}" on line 247, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${copyVectors([vector], destPrefix = '', srcPrefix = '_reset_to'), autoIndent=True}")) # from line 247, col 3.
+        write(u"""  
+  /* return false if there's a NaN somewhere in the vector, otherwise return true */
+  bool bNoNaNsPresent = true;
+  {
+    """)
+        _v = VFFSL(SL,"loopOverVectorsInBasisWithInnerContent",False)([vector], VFFSL(SL,"homeBasis",True), VFFSL(SL,"insideLookForNaNLoops",False)(vector)) # u'${loopOverVectorsInBasisWithInnerContent([vector], $homeBasis, $insideLookForNaNLoops(vector)), autoIndent=True}' on line 252, col 5
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${loopOverVectorsInBasisWithInnerContent([vector], $homeBasis, $insideLookForNaNLoops(vector)), autoIndent=True}')) # from line 252, col 5.
+        write(u'''  }
+  return bNoNaNsPresent;
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def createToleranceVariable(self, **KWS):
+
+
+        """
+        This function returns the code that will create a _step variable,
+        including any modifications necessary due to the ErrorCheck feature.
+        """
+
+        ## CHEETAH: generated from @def createToleranceVariable at line 259, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''real _tolerance = ''')
+        _v = VFFSL(SL,"tolerance",True) # u'${tolerance}' on line 265, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${tolerance}')) # from line 265, col 19.
+        write(u''';
+''')
+        # 
+        featureOrdering = ['ErrorCheck']
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('createToleranceVariable', featureOrdering) # u"${insertCodeForFeatures('createToleranceVariable', featureOrdering)}" on line 268, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('createToleranceVariable', featureOrdering)}")) # from line 268, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def segmentFunctionBody(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def segmentFunctionBody($function) at line 272, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''real _step = ''')
+        _v = VFFSL(SL,"interval",True) # u'${interval}' on line 274, col 14
+        if _v is not None: write(_filter(_v, rawExpr=u'${interval}')) # from line 274, col 14.
+        write(u'''/(real)''')
+        _v = VFFSL(SL,"stepCount",True) # u'${stepCount}' on line 274, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepCount}')) # from line 274, col 32.
+        write(u''';
+real _old_step = _step;
+real _min_step = _step;
+real _max_step = _step;
+long _attempted_steps = 0;
+long _unsuccessful_steps = 0;
+
+''')
+        _v = VFFSL(SL,"createToleranceVariable",True) # u'${createToleranceVariable}' on line 281, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${createToleranceVariable}')) # from line 281, col 1.
+        #  Insert code for features
+        featureOrderingOuter = ['Stochastic']
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('integrateAdaptiveStepBegin', featureOrderingOuter) # u"${insertCodeForFeatures('integrateAdaptiveStepBegin', featureOrderingOuter)}" on line 284, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('integrateAdaptiveStepBegin', featureOrderingOuter)}")) # from line 284, col 1.
+        write(u'''
+real _error, _last_norm_error = 1.0;
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 287, col 3
+            write(u'''real _''')
+            _v = VFFSL(SL,"name",True) # u'${name}' on line 288, col 7
+            if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 288, col 7.
+            write(u'''_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 288, col 15
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 288, col 15.
+            write(u'''_error;
+''')
+        write(u'''
+bool _discard = false;
+bool _break_next = false;
+
+''')
+        momentGroupCount = len(VFFSL(SL,"momentGroups",True))
+        write(u'''bool _next_sample_flag[''')
+        _v = VFFSL(SL,"momentGroupCount",True) + 2 # u'${momentGroupCount + 2}' on line 295, col 24
+        if _v is not None: write(_filter(_v, rawExpr=u'${momentGroupCount + 2}')) # from line 295, col 24.
+        write(u'''];
+for (long _i0 = 0; _i0 < ''')
+        _v = VFFSL(SL,"momentGroupCount",True) + 2 # u'${momentGroupCount + 2}' on line 296, col 26
+        if _v is not None: write(_filter(_v, rawExpr=u'${momentGroupCount + 2}')) # from line 296, col 26.
+        write(u'''; _i0++)
+  _next_sample_flag[_i0] = false;
+
+long _next_sample_counter[''')
+        _v = VFFSL(SL,"momentGroupCount",True) # u'$momentGroupCount' on line 299, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'$momentGroupCount')) # from line 299, col 27.
+        write(u'''];
+for (long _i0 = 0; _i0 < ''')
+        _v = VFFSL(SL,"momentGroupCount",True) # u'$momentGroupCount' on line 300, col 26
+        if _v is not None: write(_filter(_v, rawExpr=u'$momentGroupCount')) # from line 300, col 26.
+        write(u'''; _i0++)
+  _next_sample_counter[_i0] = 1;
+
+real _''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 303, col 7
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 303, col 7.
+        write(u'''_local = 0.0;
+
+real _''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 305, col 7
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 305, col 7.
+        write(u'''_break_next = _''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 305, col 45
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 305, col 45.
+        write(u'''_setup_sampling(_next_sample_flag, _next_sample_counter);
+
+if ( (_''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 307, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 307, col 8.
+        write(u'''_local + _step)*(1.0 + _EPSILON) >= _''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 307, col 68
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 307, col 68.
+        write(u'''_break_next) {
+  _break_next = true;
+  _step = _''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 309, col 12
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 309, col 12.
+        write(u'''_break_next - _''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 309, col 50
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 309, col 50.
+        write(u'''_local;
+}
+
+''')
+        _v = VFFSL(SL,"allocate",True) # u'${allocate}' on line 312, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${allocate}')) # from line 312, col 1.
+        _v = VFFSL(SL,"initialise",True) # u'${initialise}' on line 313, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${initialise}')) # from line 313, col 1.
+        _v = VFFSL(SL,"localInitialise",True) # u'${localInitialise}' on line 314, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${localInitialise}')) # from line 314, col 1.
+        write(u'''
+do {
+''')
+        featureOrderingOuterLoop = ['MaxIterations', 'Output', 'ErrorCheck']
+        write(u'''  ''')
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('integrateAdaptiveStepOuterLoopBegin', featureOrderingOuterLoop) # u"${insertCodeForFeatures('integrateAdaptiveStepOuterLoopBegin', featureOrderingOuterLoop), autoIndent=True}" on line 318, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeatures('integrateAdaptiveStepOuterLoopBegin', featureOrderingOuterLoop), autoIndent=True}")) # from line 318, col 3.
+        write(u'''  
+  ''')
+        _v = VFFSL(SL,"preSingleStep",True) # u'${preSingleStep, autoIndent=True}' on line 320, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${preSingleStep, autoIndent=True}')) # from line 320, col 3.
+        write(u'''  do {
+''')
+        #  Insert code for features
+        featureOrderingInnerLoop = ['Stochastic']
+        write(u'''    ''')
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('integrateAdaptiveStepInnerLoopBegin', featureOrderingInnerLoop) # u"${insertCodeForFeatures('integrateAdaptiveStepInnerLoopBegin', featureOrderingInnerLoop), autoIndent=True}" on line 324, col 5
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeatures('integrateAdaptiveStepInnerLoopBegin', featureOrderingInnerLoop), autoIndent=True}")) # from line 324, col 5.
+        write(u'''    
+    ''')
+        _v = VFN(VFFSL(SL,"stepper",True),"singleIntegrationStep",False)(function) # u'${stepper.singleIntegrationStep(function), autoIndent=True}' on line 326, col 5
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${stepper.singleIntegrationStep(function), autoIndent=True}')) # from line 326, col 5.
+        write(u'''    
+    ''')
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('integrateAdaptiveStepInnerLoopEnd', featureOrderingInnerLoop) # u"${insertCodeForFeaturesInReverseOrder('integrateAdaptiveStepInnerLoopEnd', featureOrderingInnerLoop), autoIndent=True}" on line 328, col 5
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeaturesInReverseOrder('integrateAdaptiveStepInnerLoopEnd', featureOrderingInnerLoop), autoIndent=True}")) # from line 328, col 5.
+        write(u'''    
+    _error = 0.0;
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 331, col 3
+            write(u'''    
+    _''')
+            _v = VFFSL(SL,"name",True) # u'${name}' on line 333, col 6
+            if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 333, col 6.
+            write(u'''_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 333, col 14
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 333, col 14.
+            write(u'''_error = _''')
+            _v = VFFSL(SL,"name",True) # u'${name}' on line 333, col 36
+            if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 333, col 36.
+            write(u'''_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 333, col 44
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 333, col 44.
+            write(u'''_timestep_error(_''')
+            _v = VFFSL(SL,"stepper.errorFieldName",True) # u'${stepper.errorFieldName}' on line 333, col 73
+            if _v is not None: write(_filter(_v, rawExpr=u'${stepper.errorFieldName}')) # from line 333, col 73.
+            write(u'''_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 333, col 99
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 333, col 99.
+            write(u''');
+    if (_''')
+            _v = VFFSL(SL,"name",True) # u'${name}' on line 334, col 10
+            if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 334, col 10.
+            write(u'''_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 334, col 18
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 334, col 18.
+            write(u'''_error > _error)
+      _error = _''')
+            _v = VFFSL(SL,"name",True) # u'${name}' on line 335, col 17
+            if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 335, col 17.
+            write(u'''_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 335, col 25
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 335, col 25.
+            write(u'''_error;
+''')
+        write(u'''    
+    _attempted_steps++;
+    
+''')
+        featureOrderingForToleranceChecking = ['Diagnostics', 'Stochastic']
+        write(u'''    if (_error < _tolerance) {
+      ''')
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('adaptiveStepSucceeded', VFFSL(SL,"featureOrderingForToleranceChecking",True)) # u"${insertCodeForFeatures('adaptiveStepSucceeded', $featureOrderingForToleranceChecking), autoIndent=True}" on line 342, col 7
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeatures('adaptiveStepSucceeded', $featureOrderingForToleranceChecking), autoIndent=True}")) # from line 342, col 7.
+        write(u'''      _''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 343, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 343, col 8.
+        write(u'''_local += _step;
+      if (_step > _max_step)
+        _max_step = _step;
+      if (!_break_next && _step < _min_step)
+        _min_step = _step;
+      _discard = false;
+    } else {
+      ''')
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('adaptiveStepFailed', VFFSL(SL,"featureOrderingForToleranceChecking",True)) # u"${insertCodeForFeatures('adaptiveStepFailed', $featureOrderingForToleranceChecking), autoIndent=True}" on line 350, col 7
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeatures('adaptiveStepFailed', $featureOrderingForToleranceChecking), autoIndent=True}")) # from line 350, col 7.
+        write(u'''      ''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 351, col 7
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 351, col 7.
+        write(u''' -= _step;
+
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 353, col 3
+            write(u'''      if (_''')
+            _v = VFFSL(SL,"name",True) # u'${name}' on line 354, col 12
+            if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 354, col 12.
+            write(u'''_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 354, col 20
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 354, col 20.
+            write(u'''_reset(_''')
+            _v = VFFSL(SL,"stepper.resetFieldName",True) # u'${stepper.resetFieldName}' on line 354, col 40
+            if _v is not None: write(_filter(_v, rawExpr=u'${stepper.resetFieldName}')) # from line 354, col 40.
+            write(u'''_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 354, col 66
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 354, col 66.
+            write(u''') == false) {
+
+        _LOG(_WARNING_LOG_LEVEL, "WARNING: NaN present. Integration halted at ''')
+            _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 356, col 79
+            if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 356, col 79.
+            write(u''' = %e.\\n"
+                           "         Non-finite number in integration vector \\"''')
+            _v = VFFSL(SL,"vector.name",True) # u'${vector.name}' on line 357, col 80
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.name}')) # from line 357, col 80.
+            write(u'''\\" in segment ''')
+            _v = VFFSL(SL,"segmentNumber",True) # u'${segmentNumber}' on line 357, col 108
+            if _v is not None: write(_filter(_v, rawExpr=u'${segmentNumber}')) # from line 357, col 108.
+            write(u'''.\\n", ''')
+            _v = VFFSL(SL,"propagationDimension",True) # u'$propagationDimension' on line 357, col 130
+            if _v is not None: write(_filter(_v, rawExpr=u'$propagationDimension')) # from line 357, col 130.
+            write(u''');
+        ''')
+            _v = VFFSL(SL,"earlyTerminationCode",True) # u'${earlyTerminationCode, autoIndent=True}' on line 358, col 9
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${earlyTerminationCode, autoIndent=True}')) # from line 358, col 9.
+            write(u'''      }
+''')
+        write(u'''
+      ''')
+        _v = VFN(VFFSL(SL,"functions",True)['ipEvolve'],"call",False)(_exponent = -1, parentFunction=function) # u"${functions['ipEvolve'].call(_exponent = -1, parentFunction=function)}" on line 362, col 7
+        if _v is not None: write(_filter(_v, rawExpr=u"${functions['ipEvolve'].call(_exponent = -1, parentFunction=function)}")) # from line 362, col 7.
+        write(u'''
+      
+      _discard = true;
+      _break_next = false;
+      _unsuccessful_steps++;
+    }
+    
+    _old_step = _step;
+    
+    // Resize step
+    if (_error < 0.5*_tolerance || _error > _tolerance) {
+      const real _safetyFactor = 0.90;
+      real _scalingFactor = _safetyFactor * pow(abs(_error/_tolerance), real(-0.7/''')
+        _v = VFFSL(SL,"integrationOrder",True) # u'${integrationOrder}' on line 374, col 83
+        if _v is not None: write(_filter(_v, rawExpr=u'${integrationOrder}')) # from line 374, col 83.
+        write(u''')) * pow(_last_norm_error, real(0.4/''')
+        _v = VFFSL(SL,"integrationOrder",True) # u'${integrationOrder}' on line 374, col 138
+        if _v is not None: write(_filter(_v, rawExpr=u'${integrationOrder}')) # from line 374, col 138.
+        write(u"""));
+      _scalingFactor = MAX(_scalingFactor, 1.0/5.0);
+      _scalingFactor = MIN(_scalingFactor, 7.0);
+      if (_error > _tolerance && _scalingFactor > 1.0) {
+        // If our step failed don't try and increase our step size. That would be silly.
+        _scalingFactor = _safetyFactor * pow(abs(_error/_tolerance), real(-1.0/""")
+        _v = VFFSL(SL,"integrationOrder",True) # u'${integrationOrder}' on line 379, col 80
+        if _v is not None: write(_filter(_v, rawExpr=u'${integrationOrder}')) # from line 379, col 80.
+        write(u'''));
+      }
+      _old_step = _step;
+      _last_norm_error = pow(_safetyFactor/_scalingFactor*pow(_last_norm_error, real(0.4/''')
+        _v = VFFSL(SL,"integrationOrder",True) # u'${integrationOrder}' on line 382, col 90
+        if _v is not None: write(_filter(_v, rawExpr=u'${integrationOrder}')) # from line 382, col 90.
+        write(u''')), real(''')
+        _v = VFFSL(SL,"integrationOrder",True) # u'${integrationOrder}' on line 382, col 118
+        if _v is not None: write(_filter(_v, rawExpr=u'${integrationOrder}')) # from line 382, col 118.
+        write(u'''/0.7));
+      _step *= _scalingFactor;
+    }
+    
+  } while (_discard);
+  ''')
+        _v = VFFSL(SL,"postSingleStep",True) # u'${postSingleStep, autoIndent=True}' on line 387, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${postSingleStep, autoIndent=True}')) # from line 387, col 3.
+        write(u'''  
+  ''')
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('integrateAdaptiveStepOuterLoopEnd', featureOrderingOuterLoop) # u"${insertCodeForFeaturesInReverseOrder('integrateAdaptiveStepOuterLoopEnd', featureOrderingOuterLoop), autoIndent=True}" on line 389, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeaturesInReverseOrder('integrateAdaptiveStepOuterLoopEnd', featureOrderingOuterLoop), autoIndent=True}")) # from line 389, col 3.
+        write(u'''} while (!_next_sample_flag[''')
+        _v = VFFSL(SL,"momentGroupCount",True) + 1 # u'${momentGroupCount + 1}' on line 390, col 29
+        if _v is not None: write(_filter(_v, rawExpr=u'${momentGroupCount + 1}')) # from line 390, col 29.
+        write(u''']);
+
+''')
+        _v = VFFSL(SL,"localFinalise",True) # u'${localFinalise}' on line 392, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${localFinalise}')) # from line 392, col 1.
+        _v = VFFSL(SL,"finalise",True) # u'${finalise}' on line 393, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${finalise}')) # from line 393, col 1.
+        _v = VFFSL(SL,"free",True) # u'${free}' on line 394, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${free}')) # from line 394, col 1.
+        # 
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('integrateAdaptiveStepEnd', featureOrderingOuter) # u"${insertCodeForFeaturesInReverseOrder('integrateAdaptiveStepEnd', featureOrderingOuter)}" on line 396, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeaturesInReverseOrder('integrateAdaptiveStepEnd', featureOrderingOuter)}")) # from line 396, col 1.
+        write(u'''
+_LOG(_SEGMENT_LOG_LEVEL, "Segment ''')
+        _v = VFFSL(SL,"segmentNumber",True) # u'${segmentNumber}' on line 398, col 35
+        if _v is not None: write(_filter(_v, rawExpr=u'${segmentNumber}')) # from line 398, col 35.
+        write(u''': minimum timestep: %e maximum timestep: %e\\n", _min_step, _max_step);
+_LOG(_SEGMENT_LOG_LEVEL, "  Attempted %li steps, %.2f%% steps failed.\\n", _attempted_steps, (100.0*_unsuccessful_steps)/_attempted_steps);
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''F''')
+        # 
+        # AdaptiveStep.tmpl
+        # 
+        # Created by Graham Dennis on 2007-11-16.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+''')
+        # 
+        #   Function prototypes
+        write(u'''
+
+''')
+        # 
+        #   Function implementations
+        write(u'''
+
+
+
+
+
+
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_AdaptiveStep= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(AdaptiveStep, '_initCheetahAttributes'):
+    templateAPIClass = getattr(AdaptiveStep, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(AdaptiveStep)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=AdaptiveStep()).run()
+
+
diff --git a/xpdeint/Segments/Integrators/AdaptiveStep.tmpl b/xpdeint/Segments/Integrators/AdaptiveStep.tmpl
new file mode 100644
index 0000000..adf1153
--- /dev/null
+++ b/xpdeint/Segments/Integrators/AdaptiveStep.tmpl
@@ -0,0 +1,401 @@
+F@*
+AdaptiveStep.tmpl
+
+Created by Graham Dennis on 2007-11-16.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Segments.Integrators.Integrator
+
+ at def description: segment $segmentNumber ($stepper.name adaptive-step integrator)
+
+@*
+  Function prototypes
+*@
+ at def functionPrototypes
+  @#
+  @super
+  @#
+real _segment${segmentNumber}_setup_sampling(bool* _next_sample_flag, long* _next_sample_counter);
+  @#
+  @for $vector in $integrationVectors
+real _segment${segmentNumber}_${vector.id}_timestep_error(${vector.type}* _checkfield);
+bool _segment${segmentNumber}_${vector.id}_reset(${vector.type}* _reset_to);
+  @end for
+  @#
+ at end def
+
+
+@*
+  Function implementations
+*@
+ at def functionImplementations
+  @#
+  @super
+  @#
+${setupSamplingFunctionImplementation}@slurp
+  @for $vector in $integrationVectors
+
+${timestepErrorFunctionImplementation($vector)}@slurp
+
+${resetFunctionImplementation($vector)}@slurp
+  @end for
+  @#
+ at end def
+
+
+ at def setupSamplingFunctionImplementation
+  @#
+real _segment${segmentNumber}_setup_sampling(bool* _next_sample_flag, long* _next_sample_counter)
+{
+  // The numbers of the moment groups that need to be sampled at the next sampling point.
+  // An entry of N+1 means "reached end of integration interval"
+  long _momentGroupNumbersNeedingSamplingNext[${len($samples) + 1}];
+  long _numberOfMomentGroupsToBeSampledNext = 1;
+  
+  long _previous_m = 1;
+  long _previous_M = 1;
+  
+  real _${propagationDimension}_break_next = (real)${interval};
+  _momentGroupNumbersNeedingSamplingNext[0] = ${len($samples)};
+  
+  // initialise all flags to false
+  for (long _i0 = 0; _i0 < ${len($samples) + 1}; _i0++)
+    _next_sample_flag[_i0] = false;
+  
+  /* Check if moment group needs sampling at the same time as another already discovered sample (or the final time).
+   * If so, add this moment group to the to-be-sampled list. If moment group demands sampling earlier than all
+   * previously noted moment groups, erase all previous ones from list and set the sample time to this earlier one.
+   */
+  @for $momentGroupNumber, $sampleCount in enumerate($samples)
+    @if $sampleCount == 0
+      @continue
+    @end if
+  if (_next_sample_counter[$momentGroupNumber] * _previous_M == _previous_m * $sampleCount) {
+    _momentGroupNumbersNeedingSamplingNext[_numberOfMomentGroupsToBeSampledNext] = $momentGroupNumber;
+    _numberOfMomentGroupsToBeSampledNext++;
+  } else if (_next_sample_counter[$momentGroupNumber] * _previous_M < _previous_m * $sampleCount) {
+    _${propagationDimension}_break_next = _next_sample_counter[$momentGroupNumber] * ((real)$interval) / ((real)$sampleCount);
+    _numberOfMomentGroupsToBeSampledNext = 1;
+    _momentGroupNumbersNeedingSamplingNext[0] = $momentGroupNumber;
+    _previous_M = $sampleCount;
+    _previous_m = _next_sample_counter[$momentGroupNumber];
+  }
+  
+  @end for
+  // _momentGroupNumbersNeedingSamplingNext now contains the complete list of moment groups that need
+  // to be sampled at the next sampling point. Set their flags to true.
+  for (long _i0 = 0; _i0 < _numberOfMomentGroupsToBeSampledNext; _i0++)
+    _next_sample_flag[_momentGroupNumbersNeedingSamplingNext[_i0]] = true;
+  
+  return _${propagationDimension}_break_next;
+}
+  @#
+ at end def
+
+
+ at def timestepErrorFunctionImplementation($vector)
+  @#
+real _segment${segmentNumber}_${vector.id}_timestep_error(${vector.type}* _checkfield)
+{
+  real _error = 1e-24;
+  real _temp_error = 0.0;
+  real _temp_mod = 0.0;
+
+  @set $featureOrdering = ['Diagnostics']
+  @set $dict = {'vector': vector}
+  ${insertCodeForFeatures('timestepErrorBegin', featureOrdering, {'vector': vector}), autoIndent=True}@slurp
+  
+  @if len($vector.field.dimensions) > 0
+    @# FIXME: We need to have the capacity to have both a peak cutoff and an absolute cutoff
+  // Find the peak value for each component of the field
+  real _cutoff[_${vector.id}_ncomponents];
+  
+  for (long _i0 = 0; _i0 < _${vector.id}_ncomponents; _i0++)
+    _cutoff[_i0] = 0.0;
+  
+  {
+    ${loopOverVectorsInBasisWithInnerContent([vector], $homeBasis, $insideFindPeakLoops(vector)), autoIndent=True}@slurp
+  }
+  ${insertCodeForFeatures('findMax', ['Driver'], {'variable': '_cutoff', 'count': c'_${vector.id}_ncomponents'}), autoIndent=True}@slurp
+  
+  for (long _i0 = 0; _i0 < _${vector.id}_ncomponents; _i0++) {
+    if (_xmds_isnonfinite(_cutoff[_i0]))
+      // Return an error two times the tolerance in this case because the timestep must be reduced.
+      return 2.0*${tolerance};
+    _cutoff[_i0] *= ${cutoff};
+    @if $vector.type == 'complex'
+      @# multiply again because we are using norm for our complex vector and the cutoff should be interpreted in terms of
+      @# the absolute magnitude of the variables, not the mod-square
+    _cutoff[_i0] *= ${cutoff};
+    @end if
+  }
+  @end if
+  
+  @# Code for absolute cutoff should go here and modify
+  @# the _cutoff variables
+  @#
+  @# @for $absoluteCutoff in $absoluteCutoffs
+  @# // absolute cutoff for component '$absoluteCutoff.name'
+  @# if (_cutoff[${absoluteCutoff.componentIndex}])
+  @# @end for
+  @#
+  {
+    ${loopOverVectorsInBasisWithInnerContent([vector], $homeBasis, $insideFindMaxErrorLoops(vector)), autoIndent=True}@slurp
+  }
+  ${insertCodeForFeatures('findMax', ['Driver'], {'variable': '&_error', 'count': '1'}), autoIndent=True}@slurp
+  ${insertCodeForFeaturesInReverseOrder('timestepErrorEnd', featureOrdering, dict), autoIndent=True}@slurp
+  
+  return _error;
+}
+  @#
+ at end def
+
+
+ at def insideFindPeakLoops($vector)
+  @#
+for (long _i1 = 0; _i1 < _${vector.id}_ncomponents; _i1++) {
+  @if $vector.type == 'complex'
+    @set $modFunction = 'mod2'
+  @else
+    @set $modFunction = 'abs'
+  @end if
+  _temp_mod = ${modFunction}(_${vector.id}[_${vector.id}_index_pointer + _i1]);
+  if (_xmds_isnonfinite(_temp_mod))
+    _cutoff[_i1] = INFINITY;
+  else if (_cutoff[_i1] < _temp_mod)
+    _cutoff[_i1] = _temp_mod;
+}
+  @#
+ at end def
+
+
+ at def insideFindMaxErrorLoops($vector)
+  @#
+for (long  _i1 = 0; _i1 < _${vector.id}_ncomponents; _i1++) {
+  @if $vector.type == 'complex'
+    @set $modCutoffFunction = 'mod2'
+  @else
+    @set $modCutoffFunction = 'abs'
+  @end if
+  @if len($vector.field.dimensions) > 0
+  if (${modCutoffFunction}(_${vector.id}[_${vector.id}_index_pointer + _i1]) > _cutoff[_i1]) {
+    ${updateMaximumError($vector), autoIndent=True}@slurp
+  }
+  @else
+  ${updateMaximumError($vector), autoIndent=True}@slurp
+  @end if
+}
+  @#
+ at end def
+
+ at def insideLookForNaNLoops($vector)
+  @#
+  @# No point in fancy logic trying to exit the test early if a NaN is found, even
+  @# though this is hot path code, since a NaN means we're about to exit the simulation
+  @# anyway. Worth having seperate code depending on whether the vector values are
+  @# real or complex though, since complex requires either two checks or taking the
+  @# modulus. Presumably two seperate Re(), Im() checks are faster than mod2
+  @#
+  for (long _i1 = 0; _i1 < _${vector.id}_ncomponents; _i1++) {
+  @if $vector.type == 'complex'
+    if (_xmds_isnonfinite(_${vector.id}[_${vector.id}_index_pointer + _i1].Re())
+      || _xmds_isnonfinite(_${vector.id}[_${vector.id}_index_pointer + _i1].Im())) bNoNaNsPresent = false;
+  @else
+    if (_xmds_isnonfinite(_${vector.id}[_${vector.id}_index_pointer + _i1])) bNoNaNsPresent = false;
+  @end if
+  }
+  @#
+ at end def
+
+ at def updateMaximumError($vector)
+  @#
+_temp_error = abs(_${vector.id}[_${vector.id}_index_pointer + _i1] - _checkfield[_${vector.id}_index_pointer + _i1]) / (0.5*abs(_${vector.id}[_${vector.id}_index_pointer + _i1]) + 0.5*abs(_checkfield[_${vector.id}_index_pointer + _i1]));
+
+if (_xmds_isnonfinite(_temp_error)) {
+  /* For _temp_error to be NaN, both the absolute value of the higher and lower order solutions
+     must BOTH be zero. This therefore implies that their difference is zero, and that there is no error. */
+  _temp_error = 0.0;
+}
+
+if (_error < _temp_error) // UNVECTORISABLE
+  _error = _temp_error;
+  @#
+${insertCodeForFeatures('updateMaximumError', ['Diagnostics'], {'vector': vector})}@slurp
+  @#
+ at end def
+
+
+ at def resetFunctionImplementation($vector)
+  @#
+bool _segment${segmentNumber}_${vector.id}_reset(${vector.type}* _reset_to_${vector.id})
+{
+  ${copyVectors([vector], destPrefix = '', srcPrefix = '_reset_to'), autoIndent=True}@slurp
+  
+  /* return false if there's a NaN somewhere in the vector, otherwise return true */
+  bool bNoNaNsPresent = true;
+  {
+    ${loopOverVectorsInBasisWithInnerContent([vector], $homeBasis, $insideLookForNaNLoops(vector)), autoIndent=True}@slurp
+  }
+  return bNoNaNsPresent;
+}
+  @#
+ at end def
+
+ at def createToleranceVariable
+@*doc:
+This function returns the code that will create a _step variable,
+including any modifications necessary due to the ErrorCheck feature.
+*@
+  @#
+real _tolerance = ${tolerance};
+  @#
+  @set $featureOrdering = ['ErrorCheck']
+${insertCodeForFeatures('createToleranceVariable', featureOrdering)}@slurp
+  @#
+ at end def
+
+ at def segmentFunctionBody($function)
+  @#
+real _step = ${interval}/(real)${stepCount};
+real _old_step = _step;
+real _min_step = _step;
+real _max_step = _step;
+long _attempted_steps = 0;
+long _unsuccessful_steps = 0;
+
+${createToleranceVariable}@slurp
+  @# Insert code for features
+  @set $featureOrderingOuter = ['Stochastic']
+${insertCodeForFeatures('integrateAdaptiveStepBegin', featureOrderingOuter)}@slurp
+
+real _error, _last_norm_error = 1.0;
+  @for $vector in $integrationVectors
+real _${name}_${vector.id}_error;
+  @end for
+
+bool _discard = false;
+bool _break_next = false;
+
+  @set $momentGroupCount = len($momentGroups)
+bool _next_sample_flag[${momentGroupCount + 2}];
+for (long _i0 = 0; _i0 < ${momentGroupCount + 2}; _i0++)
+  _next_sample_flag[_i0] = false;
+
+long _next_sample_counter[$momentGroupCount];
+for (long _i0 = 0; _i0 < $momentGroupCount; _i0++)
+  _next_sample_counter[_i0] = 1;
+
+real _${propagationDimension}_local = 0.0;
+
+real _${propagationDimension}_break_next = _${name}_setup_sampling(_next_sample_flag, _next_sample_counter);
+
+if ( (_${propagationDimension}_local + _step)*(1.0 + _EPSILON) >= _${propagationDimension}_break_next) {
+  _break_next = true;
+  _step = _${propagationDimension}_break_next - _${propagationDimension}_local;
+}
+
+${allocate}@slurp
+${initialise}@slurp
+${localInitialise}@slurp
+
+do {
+  @set $featureOrderingOuterLoop = ['MaxIterations', 'Output', 'ErrorCheck']
+  ${insertCodeForFeatures('integrateAdaptiveStepOuterLoopBegin', featureOrderingOuterLoop), autoIndent=True}@slurp
+  
+  ${preSingleStep, autoIndent=True}@slurp
+  do {
+  @# Insert code for features
+  @set $featureOrderingInnerLoop = ['Stochastic']
+    ${insertCodeForFeatures('integrateAdaptiveStepInnerLoopBegin', featureOrderingInnerLoop), autoIndent=True}@slurp
+    
+    ${stepper.singleIntegrationStep(function), autoIndent=True}@slurp
+    
+    ${insertCodeForFeaturesInReverseOrder('integrateAdaptiveStepInnerLoopEnd', featureOrderingInnerLoop), autoIndent=True}@slurp
+    
+    _error = 0.0;
+  @for $vector in $integrationVectors
+    
+    _${name}_${vector.id}_error = _${name}_${vector.id}_timestep_error(_${stepper.errorFieldName}_${vector.id});
+    if (_${name}_${vector.id}_error > _error)
+      _error = _${name}_${vector.id}_error;
+  @end for
+    
+    _attempted_steps++;
+    
+  @set $featureOrderingForToleranceChecking = ['Diagnostics', 'Stochastic']
+    if (_error < _tolerance) {
+      ${insertCodeForFeatures('adaptiveStepSucceeded', $featureOrderingForToleranceChecking), autoIndent=True}@slurp
+      _${propagationDimension}_local += _step;
+      if (_step > _max_step)
+        _max_step = _step;
+      if (!_break_next && _step < _min_step)
+        _min_step = _step;
+      _discard = false;
+    } else {
+      ${insertCodeForFeatures('adaptiveStepFailed', $featureOrderingForToleranceChecking), autoIndent=True}@slurp
+      ${propagationDimension} -= _step;
+
+  @for $vector in $integrationVectors
+      if (_${name}_${vector.id}_reset(_${stepper.resetFieldName}_${vector.id}) == false) {
+
+        _LOG(_WARNING_LOG_LEVEL, "WARNING: NaN present. Integration halted at ${propagationDimension} = %e.\n"
+                           "         Non-finite number in integration vector \"${vector.name}\" in segment ${segmentNumber}.\n", $propagationDimension);
+        ${earlyTerminationCode, autoIndent=True}@slurp 
+      }
+  @end for
+
+      ${functions['ipEvolve'].call(_exponent = -1, parentFunction=function)}
+      
+      _discard = true;
+      _break_next = false;
+      _unsuccessful_steps++;
+    }
+    
+    _old_step = _step;
+    
+    // Resize step
+    if (_error < 0.5*_tolerance || _error > _tolerance) {
+      const real _safetyFactor = 0.90;
+      real _scalingFactor = _safetyFactor * pow(abs(_error/_tolerance), real(-0.7/${integrationOrder})) * pow(_last_norm_error, real(0.4/${integrationOrder}));
+      _scalingFactor = MAX(_scalingFactor, 1.0/5.0);
+      _scalingFactor = MIN(_scalingFactor, 7.0);
+      if (_error > _tolerance && _scalingFactor > 1.0) {
+        // If our step failed don't try and increase our step size. That would be silly.
+        _scalingFactor = _safetyFactor * pow(abs(_error/_tolerance), real(-1.0/${integrationOrder}));
+      }
+      _old_step = _step;
+      _last_norm_error = pow(_safetyFactor/_scalingFactor*pow(_last_norm_error, real(0.4/${integrationOrder})), real(${integrationOrder}/0.7));
+      _step *= _scalingFactor;
+    }
+    
+  } while (_discard);
+  ${postSingleStep, autoIndent=True}@slurp
+  
+  ${insertCodeForFeaturesInReverseOrder('integrateAdaptiveStepOuterLoopEnd', featureOrderingOuterLoop), autoIndent=True}@slurp
+} while (!_next_sample_flag[${momentGroupCount + 1}]);
+
+${localFinalise}@slurp
+${finalise}@slurp
+${free}@slurp
+  @#
+${insertCodeForFeaturesInReverseOrder('integrateAdaptiveStepEnd', featureOrderingOuter)}@slurp
+
+_LOG(_SEGMENT_LOG_LEVEL, "Segment ${segmentNumber}: minimum timestep: %e maximum timestep: %e\n", _min_step, _max_step);
+_LOG(_SEGMENT_LOG_LEVEL, "  Attempted %li steps, %.2f%% steps failed.\n", _attempted_steps, (100.0*_unsuccessful_steps)/_attempted_steps);
+  @#
+ at end def
diff --git a/xpdeint/Segments/Integrators/FixedStep.py b/xpdeint/Segments/Integrators/FixedStep.py
new file mode 100644
index 0000000..d73813f
--- /dev/null
+++ b/xpdeint/Segments/Integrators/FixedStep.py
@@ -0,0 +1,788 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Segments.Integrators._FixedStep import _FixedStep
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.573614
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Segments/Integrators/FixedStep.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class FixedStep(_FixedStep):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(FixedStep, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: segment $segmentNumber ($stepper.name fixed-step integrator) at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''segment ''')
+        _v = VFFSL(SL,"segmentNumber",True) # u'$segmentNumber' on line 24, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'$segmentNumber')) # from line 24, col 27.
+        write(u''' (''')
+        _v = VFFSL(SL,"stepper.name",True) # u'$stepper.name' on line 24, col 43
+        if _v is not None: write(_filter(_v, rawExpr=u'$stepper.name')) # from line 24, col 43.
+        write(u''' fixed-step integrator)''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def functionPrototypes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def functionPrototypes at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(FixedStep, self).functionPrototypes()
+        if _v is not None: write(_filter(_v))
+        # 
+        if VFFSL(SL,"cross",True): # generated from line 31, col 3
+            write(u'''void _''')
+            _v = VFFSL(SL,"name",True) # u'${name}' on line 32, col 7
+            if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 32, col 7.
+            write(u'''_initialise_cross_propagation();
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def functionImplementations(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def functionImplementations at line 37, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(FixedStep, self).functionImplementations()
+        if _v is not None: write(_filter(_v))
+        # 
+        if VFFSL(SL,"cross",True): # generated from line 41, col 3
+            write(u'''
+''')
+            _v = VFFSL(SL,"initialiseCrossPropagationFunctionImplementation",True) # u'${initialiseCrossPropagationFunctionImplementation}' on line 43, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${initialiseCrossPropagationFunctionImplementation}')) # from line 43, col 1.
+            write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def localInitialise(self, **KWS):
+
+
+        """
+        This function returns the local initialisation code for the integrator.
+        """
+
+        ## CHEETAH: generated from @def localInitialise at line 49, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(FixedStep, self).localInitialise()
+        if _v is not None: write(_filter(_v))
+        # 
+        if VFFSL(SL,"cross",True): # generated from line 56, col 3
+            write(u'''
+_''')
+            _v = VFFSL(SL,"name",True) # u'${name}' on line 58, col 2
+            if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 58, col 2.
+            write(u'''_initialise_cross_propagation();
+
+''')
+            integrationDimRep = VFN(VFN(VFFSL(SL,"parent.field",True),"dimensionWithName",False)(VFFSL(SL,"propagationDimension",True)),"inBasis",False)(VFFSL(SL,"parent.operatorBasis",True))
+            if VFFSL(SL,"propagationDirection",True) == '+': # generated from line 61, col 5
+                initialValue = integrationDimRep.minimum
+            else: # generated from line 63, col 5
+                initialValue = integrationDimRep.maximum
+            _v = VFFSL(SL,"integrationDimRep.type",True) # u'${integrationDimRep.type}' on line 66, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${integrationDimRep.type}')) # from line 66, col 1.
+            write(u''' ''')
+            _v = VFFSL(SL,"integrationDimRep.name",True) # u'${integrationDimRep.name}' on line 66, col 27
+            if _v is not None: write(_filter(_v, rawExpr=u'${integrationDimRep.name}')) # from line 66, col 27.
+            write(u''' = ''')
+            _v = VFFSL(SL,"initialValue",True) # u'${initialValue}' on line 66, col 55
+            if _v is not None: write(_filter(_v, rawExpr=u'${initialValue}')) # from line 66, col 55.
+            write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def createStepVariable(self, **KWS):
+
+
+        """
+        This function returns the code that will create a _step variable,
+        including any modifications necessary due to the ErrorCheck feature.
+        """
+
+        ## CHEETAH: generated from @def createStepVariable at line 72, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''real _step = ''')
+        _v = VFFSL(SL,"step",True) # u'${step}' on line 78, col 14
+        if _v is not None: write(_filter(_v, rawExpr=u'${step}')) # from line 78, col 14.
+        write(u''';
+real _noiseStep = ''')
+        _v = VFFSL(SL,"step",True) # u'${step}' on line 79, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${step}')) # from line 79, col 19.
+        write(u''';
+''')
+        # 
+        featureOrdering = ['ErrorCheck']
+        # 
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('createFixedStepVariable', featureOrdering) # u"${insertCodeForFeatures('createFixedStepVariable', featureOrdering)}" on line 83, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('createFixedStepVariable', featureOrdering)}")) # from line 83, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def segmentFunctionBody(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def segmentFunctionBody($function) at line 88, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"createStepVariable",True) # u'${createStepVariable}' on line 90, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${createStepVariable}')) # from line 90, col 1.
+        # 
+        featureOrderingOuter = ['Stochastic']
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('integrateFixedStepBegin', featureOrderingOuter) # u"${insertCodeForFeatures('integrateFixedStepBegin', featureOrderingOuter)}" on line 93, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('integrateFixedStepBegin', featureOrderingOuter)}")) # from line 93, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"allocate",True) # u'${allocate}' on line 95, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${allocate}')) # from line 95, col 1.
+        _v = VFFSL(SL,"initialise",True) # u'${initialise}' on line 96, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${initialise}')) # from line 96, col 1.
+        _v = VFFSL(SL,"localInitialise",True) # u'${localInitialise}' on line 97, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${localInitialise}')) # from line 97, col 1.
+        write(u'''
+for (long _istep = 0; _istep < ''')
+        _v = VFFSL(SL,"stepCount",True) # u'${stepCount}' on line 99, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepCount}')) # from line 99, col 32.
+        write(u'''; _istep++) {
+''')
+        #  Insert code for features
+        featureOrderingInner = ['Output', 'ErrorCheck', 'Stochastic']
+        # 
+        dict = {'extraIndent': 0}
+        write(u'''  ''')
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('integrateFixedStepInnerLoopBegin', featureOrderingInner, dict) # u"${insertCodeForFeatures('integrateFixedStepInnerLoopBegin', featureOrderingInner, dict), autoIndent=True}" on line 104, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeatures('integrateFixedStepInnerLoopBegin', featureOrderingInner, dict), autoIndent=True}")) # from line 104, col 3.
+        extraIndent = VFFSL(SL,"dict.extraIndent",True)
+        write(u'''  
+  ''')
+        _v = VFFSL(SL,"preSingleStep",True) # u'${preSingleStep, autoIndent=True, extraIndent=extraIndent}' on line 107, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, extraIndent=extraIndent, rawExpr=u'${preSingleStep, autoIndent=True, extraIndent=extraIndent}')) # from line 107, col 3.
+        write(u'''  ''')
+        _v = VFN(VFFSL(SL,"stepper",True),"singleIntegrationStep",False)(function) # u'${stepper.singleIntegrationStep(function), autoIndent=True, extraIndent=extraIndent}' on line 108, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, extraIndent=extraIndent, rawExpr=u'${stepper.singleIntegrationStep(function), autoIndent=True, extraIndent=extraIndent}')) # from line 108, col 3.
+        write(u'''  ''')
+        _v = VFFSL(SL,"postSingleStep",True) # u'${postSingleStep, autoIndent=True, extraIndent=extraIndent}' on line 109, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, extraIndent=extraIndent, rawExpr=u'${postSingleStep, autoIndent=True, extraIndent=extraIndent}')) # from line 109, col 3.
+        write(u'''  
+''')
+        if VFFSL(SL,"cross",True): # generated from line 111, col 3
+            #  If we are cross-integrating, then we now need to copy our result back
+            #  into the original arrays for the integration vectors
+            write(u'''  ''')
+            _v = VFFSL(SL,"copyResultIntoIntegrationArrays",True) # u'${copyResultIntoIntegrationArrays, autoIndent=True, extraIndent=extraIndent}' on line 114, col 3
+            if _v is not None: write(_filter(_v, autoIndent=True, extraIndent=extraIndent, rawExpr=u'${copyResultIntoIntegrationArrays, autoIndent=True, extraIndent=extraIndent}')) # from line 114, col 3.
+            write(u'''  
+''')
+        # 
+        write(u'''  ''')
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('integrateFixedStepInnerLoopEnd', featureOrderingInner, dict) # u"${insertCodeForFeaturesInReverseOrder('integrateFixedStepInnerLoopEnd', featureOrderingInner, dict), autoIndent=True}" on line 118, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeaturesInReverseOrder('integrateFixedStepInnerLoopEnd', featureOrderingInner, dict), autoIndent=True}")) # from line 118, col 3.
+        write(u'''}
+
+''')
+        _v = VFFSL(SL,"localFinalise",True) # u'${localFinalise}' on line 121, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${localFinalise}')) # from line 121, col 1.
+        _v = VFFSL(SL,"finalise",True) # u'${finalise}' on line 122, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${finalise}')) # from line 122, col 1.
+        _v = VFFSL(SL,"free",True) # u'${free}' on line 123, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${free}')) # from line 123, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('integrateFixedStepEnd', featureOrderingOuter) # u"${insertCodeForFeaturesInReverseOrder('integrateFixedStepEnd', featureOrderingOuter)}" on line 125, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeaturesInReverseOrder('integrateFixedStepEnd', featureOrderingOuter)}")) # from line 125, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def reducedFieldCopy(self, vectorMap, templateString, positiveIndexOverride=None, negativeIndexOverride=None, **KWS):
+
+
+
+        ## CHEETAH: generated from @def reducedFieldCopy($vectorMap, $templateString, $positiveIndexOverride = None, $negativeIndexOverride = None) at line 132, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        if VFFSL(SL,"propagationDirection",True) == '+': # generated from line 134, col 3
+            if VFFSL(SL,"positiveIndexOverride",True): # generated from line 135, col 5
+                indexOverrideValue = VFFSL(SL,"positiveIndexOverride",True)
+            else: # generated from line 137, col 5
+                indexOverrideValue = '_istep'
+        else: # generated from line 140, col 3
+            if VFFSL(SL,"negativeIndexOverride",True): # generated from line 141, col 5
+                indexOverrideValue = VFFSL(SL,"negativeIndexOverride",True)
+            else: # generated from line 143, col 5
+                propDimRep = VFN(VFN(VFFSL(SL,"parent.field",True),"dimensionWithName",False)(VFFSL(SL,"propagationDimension",True)),"inBasis",False)(VFFSL(SL,"parent.operatorBasis",True))
+                indexOverrideValue = ''.join([u'(',str(VFFSL(SL,"propDimRep.globalLattice",True)),u' - _istep - 1)'])
+        # 
+        #  Create the index overrides dictionary. We only need to override the propagation dimension
+        indexOverrides = {VFFSL(SL,"propagationDimension",True): dict([(v.field, indexOverrideValue) for v in vectorMap.values()])}
+        # 
+        setOfVectorsToLoopOver = set(vectorMap.keys())
+        setOfVectorsToLoopOver.update(vectorMap.values())
+        # 
+        innerLoopTemplate = VFFSL(SL,"templateObjectFromStringWithTemplateVariables",False)(VFFSL(SL,"templateString",True), {'componentIndex': '_icomp'})
+        # 
+        ## START CAPTURE REGION: _60672172 loopContents at line 157, col 3 in the source.
+        _orig_trans_60672172 = trans
+        _wasBuffering_60672172 = self._CHEETAH__isBuffering
+        self._CHEETAH__isBuffering = True
+        trans = _captureCollector_60672172 = DummyTransaction()
+        write = _captureCollector_60672172.response().write
+        for reducedVector, vector in VFN(VFFSL(SL,"vectorMap",True),"iteritems",False)(): # generated from line 158, col 5
+            if vector.field.hasDimensionName(VFFSL(SL,"propagationDimension",True)): # generated from line 159, col 7
+                propagationDimensionObject = vector.field.dimensionWithName(VFFSL(SL,"propagationDimension",True))
+                innerLoopTemplate.skipSize = VFFSL(SL,"propagationDirection",True) +                                              VFN(VFFSL(SL,"vector.field",True),"localPointsInDimensionsAfterDimRepInBasis",False)(propagationDimensionObject.inBasis(VFFSL(SL,"homeBasis",True)), VFFSL(SL,"homeBasis",True))
+            innerLoopTemplate.reducedVector = reducedVector
+            innerLoopTemplate.vector = vector
+            write(u'''for (long _icomp = 0; _icomp < _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 166, col 33
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 166, col 33.
+            write(u'''_ncomponents; _icomp++) {
+  ''')
+            _v = VFFSL(SL,"innerLoopTemplate",True) # u'${innerLoopTemplate, autoIndent=True}' on line 167, col 3
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${innerLoopTemplate, autoIndent=True}')) # from line 167, col 3.
+            write(u'''}
+''')
+            del innerLoopTemplate.skipSize
+        trans = _orig_trans_60672172
+        write = trans.response().write
+        self._CHEETAH__isBuffering = _wasBuffering_60672172 
+        loopContents = _captureCollector_60672172.response().getvalue()
+        del _orig_trans_60672172
+        del _captureCollector_60672172
+        del _wasBuffering_60672172
+        # 
+        _v = VFFSL(SL,"loopOverFieldInBasisWithVectorsAndInnerContent",False)(VFFSL(SL,"parent.reducedField",True), VFFSL(SL,"homeBasis",True), VFFSL(SL,"setOfVectorsToLoopOver",True),
+                                                 VFFSL(SL,"loopContents",True), indexOverrides = VFFSL(SL,"indexOverrides",True),
+                                                 vectorsNotNeedingDefines = VFFSL(SL,"setOfVectorsToLoopOver",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverFieldInBasisWithVectorsAndInnerContent($parent.reducedField, $homeBasis, $setOfVectorsToLoopOver,\n                                                 $loopContents, indexOverrides = $indexOverrides,\n                                                 vectorsNotNeedingDefines = $setOfVectorsToLoopOver)}')) # from line 173, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def initialiseCrossPropagationFunctionImplementation(self, **KWS):
+
+
+        """
+        Return code for initialising the boundary conditions of a cross-propagation integrator.
+        
+          This code both sets the boundary conditions and copies in the first values for the
+          dependencies into the local dependency arrays.
+        """
+
+        ## CHEETAH: generated from @def initialiseCrossPropagationFunctionImplementation at line 180, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''void _''')
+        _v = VFFSL(SL,"name",True) # u'${name}' on line 188, col 7
+        if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 188, col 7.
+        write(u'''_initialise_cross_propagation()
+{
+''')
+        positiveIndexOverride = '0'
+        basis = VFFSL(SL,"parent.operatorBasis",True)
+        propDimRep = VFN(VFN(VFFSL(SL,"parent.field",True),"dimensionWithName",False)(VFFSL(SL,"propagationDimension",True)),"inBasis",False)(basis)
+        negativeIndexOverride = ''.join([u'(',str(VFFSL(SL,"propDimRep.globalLattice",True)),u' - 1)'])
+        # 
+        combinedLoopVectorMap = VFN(VFFSL(SL,"integrationVectorMap",True),"copy",False)()
+        combinedLoopVectorMap.update(VFFSL(SL,"dependencyMap",True))
+        # 
+        vectorsNeedingTransforms = set(combinedLoopVectorMap.values())
+        boundaryConditionDependencies = VFN(VFN(VFFSL(SL,"parent",True),"codeBlocks",True)['boundaryCondition'],"dependencies",True)
+        vectorsNeedingTransforms.update(boundaryConditionDependencies)
+        write(u'''  ''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(vectorsNeedingTransforms, basis) # u'${transformVectorsToBasis(vectorsNeedingTransforms, basis), autoIndent=True}' on line 201, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${transformVectorsToBasis(vectorsNeedingTransforms, basis), autoIndent=True}')) # from line 201, col 3.
+        write(u'''  
+''')
+        if VFFSL(SL,"propagationDirection",True) == '+': # generated from line 203, col 3
+            index = VFFSL(SL,"positiveIndexOverride",True)
+        else: # generated from line 205, col 3
+            index = VFFSL(SL,"negativeIndexOverride",True)
+        write(u'''  real ''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'$propagationDimension' on line 208, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'$propagationDimension')) # from line 208, col 8.
+        write(u''' = ''')
+        _v = VFFSL(SL,"propDimRep.arrayName",True) # u'${propDimRep.arrayName}' on line 208, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'${propDimRep.arrayName}')) # from line 208, col 32.
+        write(u'''[''')
+        _v = VFFSL(SL,"index",True) # u'$index' on line 208, col 56
+        if _v is not None: write(_filter(_v, rawExpr=u'$index')) # from line 208, col 56.
+        write(u'''];
+  
+  // Copy the initial value of the cross-propagation integration vectors and dependencies into our local arrays
+  {
+    ''')
+        _v = VFFSL(SL,"reducedFieldCopy",False)(combinedLoopVectorMap,
+"""_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex}];
+""", positiveIndexOverride = VFFSL(SL,"positiveIndexOverride",True), negativeIndexOverride = VFFSL(SL,"negativeIndexOverride",True))
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${reducedFieldCopy(combinedLoopVectorMap,\n"""_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex}];\n""", positiveIndexOverride = $positiveIndexOverride, negativeIndexOverride = $negativeIndexOverride), autoIndent=True}')) # from line 212, col 5.
+        for reducedVector in VFN(VFFSL(SL,"combinedLoopVectorMap",True),"keys",False)(): # generated from line 215, col 5
+            if VFFSL(SL,"reducedVector.needsTransforms",True): # generated from line 216, col 7
+                write(u'''      _''')
+                _v = VFFSL(SL,"reducedVector.id",True) # u'${reducedVector.id}' on line 217, col 8
+                if _v is not None: write(_filter(_v, rawExpr=u'${reducedVector.id}')) # from line 217, col 8.
+                write(u'''_basis = ''')
+                _v = VFFSL(SL,"basisIndexForBasis",False)(VFN(VFFSL(SL,"reducedVector.field",True),"basisForBasis",False)(VFFSL(SL,"basis",True))) # u'$basisIndexForBasis($reducedVector.field.basisForBasis($basis))' on line 217, col 36
+                if _v is not None: write(_filter(_v, rawExpr=u'$basisIndexForBasis($reducedVector.field.basisForBasis($basis))')) # from line 217, col 36.
+                write(u'''; 
+''')
+        write(u'''  }
+  
+''')
+        # 
+        write(u'''  // Set the boundary condition
+  {
+    ''')
+        _v = VFN(VFN(VFFSL(SL,"parent",True),"codeBlocks",True)['boundaryCondition'],"loop",False)(self.boundaryConditionCode) # u"${parent.codeBlocks['boundaryCondition'].loop(self.boundaryConditionCode), autoIndent=True}" on line 225, col 5
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${parent.codeBlocks['boundaryCondition'].loop(self.boundaryConditionCode), autoIndent=True}")) # from line 225, col 5.
+        write(u'''  }
+
+  // Copy the initial value of the integration vectors back into their main arrays
+  {
+    ''')
+        _v = VFFSL(SL,"reducedFieldCopy",False)(VFFSL(SL,"integrationVectorMap",True),
+"""_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex}];
+""", positiveIndexOverride = VFFSL(SL,"positiveIndexOverride",True), negativeIndexOverride = VFFSL(SL,"negativeIndexOverride",True))
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${reducedFieldCopy($integrationVectorMap,\n"""_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex}];\n""", positiveIndexOverride = $positiveIndexOverride, negativeIndexOverride = $negativeIndexOverride), autoIndent=True}')) # from line 230, col 5.
+        write(u'''  }
+  
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def boundaryConditionCode(self, codeString, **KWS):
+
+
+
+        ## CHEETAH: generated from @def boundaryConditionCode($codeString) at line 239, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''// ********** Boundary condition code ***********
+''')
+        _v = VFFSL(SL,"codeString",True) # u'${codeString}' on line 242, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${codeString}')) # from line 242, col 1.
+        write(u'''// **********************************************
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def copyResultIntoIntegrationArrays(self, **KWS):
+
+
+        """
+        Returns code to copy the result of our cross-propagation step back into the original arrays
+          for the integation vectors.
+        """
+
+        ## CHEETAH: generated from @def copyResultIntoIntegrationArrays at line 248, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''// Copy the result back into the original array.
+{
+  ''')
+        _v = VFFSL(SL,"reducedFieldCopy",False)(VFFSL(SL,"integrationVectorMap",True), 
+"""
+_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + ${skipSize} * _${vector.id}_ncomponents] = \
+  _active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}];
+""")
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${reducedFieldCopy($integrationVectorMap, \n"""\n_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + ${skipSize} * _${vector.id}_ncomponents] = \\\n  _active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}];\n"""), autoIndent=True}')) # from line 256, col 3.
+        write(u'''}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def updateDependenciesForNextStep(self, **KWS):
+
+
+        """
+        Return code to update our dependencies vectors from the originals for the next step.
+        """
+
+        ## CHEETAH: generated from @def updateDependenciesForNextStep at line 266, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''// Update the dependencies for the next step
+{
+  ''')
+        _v = VFFSL(SL,"reducedFieldCopy",False)(VFFSL(SL,"dependencyMap",True),
+"""
+_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = \
+  _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + ${skipSize} * _${vector.id}_ncomponents];
+""")
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${reducedFieldCopy($dependencyMap,\n"""\n_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = \\\n  _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + ${skipSize} * _${vector.id}_ncomponents];\n"""), autoIndent=True}')) # from line 273, col 3.
+        write(u'''}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # FixedStep.tmpl
+        # 
+        # Created by Graham Dennis on 2007-10-20.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+
+
+
+''')
+        #  ---- Cross-propagation methods ----
+        write(u'''
+
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_FixedStep= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(FixedStep, '_initCheetahAttributes'):
+    templateAPIClass = getattr(FixedStep, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(FixedStep)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=FixedStep()).run()
+
+
diff --git a/xpdeint/Segments/Integrators/FixedStep.tmpl b/xpdeint/Segments/Integrators/FixedStep.tmpl
new file mode 100644
index 0000000..352e58e
--- /dev/null
+++ b/xpdeint/Segments/Integrators/FixedStep.tmpl
@@ -0,0 +1,281 @@
+@*
+FixedStep.tmpl
+
+Created by Graham Dennis on 2007-10-20.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Segments.Integrators._FixedStep
+
+ at def description: segment $segmentNumber ($stepper.name fixed-step integrator)
+
+
+ at def functionPrototypes
+  @#
+  @super
+  @#
+  @if $cross
+void _${name}_initialise_cross_propagation();
+  @end if
+  @#
+ at end def
+
+ at def functionImplementations
+  @#
+  @super
+  @#
+  @if $cross
+
+${initialiseCrossPropagationFunctionImplementation}@slurp
+
+  @end if
+  @#
+ at end def
+
+ at def localInitialise
+@*doc:
+  This function returns the local initialisation code for the integrator.
+*@
+  @#
+  @super
+  @#
+  @if $cross
+
+_${name}_initialise_cross_propagation();
+
+    @set $integrationDimRep = $parent.field.dimensionWithName($propagationDimension).inBasis($parent.operatorBasis)
+    @if $propagationDirection == '+'
+      @set $initialValue = integrationDimRep.minimum
+    @else
+      @set $initialValue = integrationDimRep.maximum
+    @end if
+${integrationDimRep.type} ${integrationDimRep.name} = ${initialValue};
+  @end if
+  @#
+ at end def
+
+
+ at def createStepVariable
+@*doc:
+This function returns the code that will create a _step variable,
+including any modifications necessary due to the ErrorCheck feature.
+*@
+  @#
+real _step = ${step};
+real _noiseStep = ${step};
+  @#
+  @set $featureOrdering = ['ErrorCheck']
+  @#
+${insertCodeForFeatures('createFixedStepVariable', featureOrdering)}@slurp
+  @#
+ at end def
+
+
+ at def segmentFunctionBody($function)
+  @#
+${createStepVariable}@slurp
+  @#
+  @set $featureOrderingOuter = ['Stochastic']
+${insertCodeForFeatures('integrateFixedStepBegin', featureOrderingOuter)}@slurp
+
+${allocate}@slurp
+${initialise}@slurp
+${localInitialise}@slurp
+
+for (long _istep = 0; _istep < ${stepCount}; _istep++) {
+  @# Insert code for features
+  @set $featureOrderingInner = ['Output', 'ErrorCheck', 'Stochastic']
+  @#
+  @set $dict = {'extraIndent': 0}
+  ${insertCodeForFeatures('integrateFixedStepInnerLoopBegin', featureOrderingInner, dict), autoIndent=True}@slurp
+  @set $extraIndent = $dict.extraIndent
+  
+  ${preSingleStep, autoIndent=True, extraIndent=extraIndent}@slurp
+  ${stepper.singleIntegrationStep(function), autoIndent=True, extraIndent=extraIndent}@slurp
+  ${postSingleStep, autoIndent=True, extraIndent=extraIndent}@slurp
+  
+  @if $cross
+    @# If we are cross-integrating, then we now need to copy our result back
+    @# into the original arrays for the integration vectors
+  ${copyResultIntoIntegrationArrays, autoIndent=True, extraIndent=extraIndent}@slurp
+  
+  @end if
+  @#
+  ${insertCodeForFeaturesInReverseOrder('integrateFixedStepInnerLoopEnd', featureOrderingInner, dict), autoIndent=True}@slurp
+}
+
+${localFinalise}@slurp
+${finalise}@slurp
+${free}@slurp
+
+${insertCodeForFeaturesInReverseOrder('integrateFixedStepEnd', featureOrderingOuter)}@slurp
+  @#
+ at end def
+
+
+@# ---- Cross-propagation methods ----
+
+ at def reducedFieldCopy($vectorMap, $templateString, $positiveIndexOverride = None, $negativeIndexOverride = None)
+  @#
+  @if $propagationDirection == '+'
+    @if $positiveIndexOverride
+      @set $indexOverrideValue = $positiveIndexOverride
+    @else
+      @set $indexOverrideValue = '_istep'
+    @end if
+  @else
+    @if $negativeIndexOverride
+      @set $indexOverrideValue = $negativeIndexOverride
+    @else
+      @set $propDimRep = $parent.field.dimensionWithName($propagationDimension).inBasis($parent.operatorBasis)
+      @set $indexOverrideValue = c'(${propDimRep.globalLattice} - _istep - 1)'
+    @end if
+  @end if
+  @#
+  @# Create the index overrides dictionary. We only need to override the propagation dimension
+  @set $indexOverrides = {$propagationDimension: dict([(v.field, indexOverrideValue) for v in vectorMap.values()])}
+  @#
+  @set $setOfVectorsToLoopOver = set(vectorMap.keys())
+  @silent setOfVectorsToLoopOver.update(vectorMap.values())
+  @#
+  @set $innerLoopTemplate = $templateObjectFromStringWithTemplateVariables($templateString, {'componentIndex': '_icomp'})
+  @#
+  @capture loopContents
+    @for $reducedVector, $vector in $vectorMap.iteritems()
+      @if vector.field.hasDimensionName($propagationDimension)
+        @set $propagationDimensionObject = vector.field.dimensionWithName($propagationDimension)
+        @silent innerLoopTemplate.skipSize = $propagationDirection + \
+                                             $vector.field.localPointsInDimensionsAfterDimRepInBasis(propagationDimensionObject.inBasis($homeBasis), $homeBasis)
+      @end if
+      @silent innerLoopTemplate.reducedVector = reducedVector
+      @silent innerLoopTemplate.vector = vector
+for (long _icomp = 0; _icomp < _${vector.id}_ncomponents; _icomp++) {
+  ${innerLoopTemplate, autoIndent=True}@slurp
+}
+      @del innerLoopTemplate.skipSize
+    @end for
+  @end capture
+  @#
+${loopOverFieldInBasisWithVectorsAndInnerContent($parent.reducedField, $homeBasis, $setOfVectorsToLoopOver,
+                                                 $loopContents, indexOverrides = $indexOverrides,
+                                                 vectorsNotNeedingDefines = $setOfVectorsToLoopOver)}@slurp
+  @#
+ at end def
+
+
+ at def initialiseCrossPropagationFunctionImplementation
+@*doc:
+  Return code for initialising the boundary conditions of a cross-propagation integrator.
+
+  This code both sets the boundary conditions and copies in the first values for the
+  dependencies into the local dependency arrays.
+*@
+  @#
+void _${name}_initialise_cross_propagation()
+{
+  @set $positiveIndexOverride = '0'
+  @set $basis = $parent.operatorBasis
+  @set $propDimRep = $parent.field.dimensionWithName($propagationDimension).inBasis(basis)
+  @set $negativeIndexOverride = c'(${propDimRep.globalLattice} - 1)'
+  @#
+  @set $combinedLoopVectorMap = $integrationVectorMap.copy()
+  @silent combinedLoopVectorMap.update($dependencyMap)
+  @#
+  @set $vectorsNeedingTransforms = set(combinedLoopVectorMap.values())
+  @set $boundaryConditionDependencies = $parent.codeBlocks['boundaryCondition'].dependencies
+  @silent vectorsNeedingTransforms.update(boundaryConditionDependencies)
+  ${transformVectorsToBasis(vectorsNeedingTransforms, basis), autoIndent=True}@slurp
+  
+  @if $propagationDirection == '+'
+    @set $index = $positiveIndexOverride
+  @else
+    @set $index = $negativeIndexOverride
+  @end if
+  real $propagationDimension = ${propDimRep.arrayName}[$index];
+  
+  // Copy the initial value of the cross-propagation integration vectors and dependencies into our local arrays
+  {
+    ${reducedFieldCopy(combinedLoopVectorMap,
+"""_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex}];
+""", positiveIndexOverride = $positiveIndexOverride, negativeIndexOverride = $negativeIndexOverride), autoIndent=True}@slurp
+    @for $reducedVector in $combinedLoopVectorMap.keys()
+      @if $reducedVector.needsTransforms
+      _${reducedVector.id}_basis = $basisIndexForBasis($reducedVector.field.basisForBasis($basis)); 
+      @end if
+    @end for
+  }
+  
+  @#
+  // Set the boundary condition
+  {
+    ${parent.codeBlocks['boundaryCondition'].loop(self.boundaryConditionCode), autoIndent=True}@slurp
+  }
+
+  // Copy the initial value of the integration vectors back into their main arrays
+  {
+    ${reducedFieldCopy($integrationVectorMap,
+"""_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex}];
+""", positiveIndexOverride = $positiveIndexOverride, negativeIndexOverride = $negativeIndexOverride), autoIndent=True}@slurp
+  }
+  
+}
+  @#
+ at end def
+
+ at def boundaryConditionCode($codeString)
+  @#
+// ********** Boundary condition code ***********
+${codeString}@slurp
+// **********************************************
+  @#
+ at end def
+
+
+ at def copyResultIntoIntegrationArrays
+@*doc:
+  Returns code to copy the result of our cross-propagation step back into the original arrays
+  for the integation vectors.
+*@
+  @#
+// Copy the result back into the original array.
+{
+  ${reducedFieldCopy($integrationVectorMap, 
+"""
+_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + ${skipSize} * _${vector.id}_ncomponents] = \
+  _active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}];
+"""), autoIndent=True}@slurp
+}
+  @#
+ at end def
+
+
+ at def updateDependenciesForNextStep
+@*doc:
+  Return code to update our dependencies vectors from the originals for the next step.
+*@
+  @#
+// Update the dependencies for the next step
+{
+  ${reducedFieldCopy($dependencyMap,
+"""
+_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = \
+  _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + ${skipSize} * _${vector.id}_ncomponents];
+"""), autoIndent=True}@slurp
+}
+  @#
+ at end def
+
diff --git a/xpdeint/Segments/Integrators/FixedStepWithCross.py b/xpdeint/Segments/Integrators/FixedStepWithCross.py
new file mode 100644
index 0000000..f7def13
--- /dev/null
+++ b/xpdeint/Segments/Integrators/FixedStepWithCross.py
@@ -0,0 +1,229 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Segments.Integrators._FixedStepWithCross import _FixedStepWithCross
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.44179
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Segments/Integrators/FixedStepWithCross.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class FixedStepWithCross(_FixedStepWithCross):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(FixedStepWithCross, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def leftRightDeltaAFunctionBody(self, function, replacementOperatorContainer, **KWS):
+
+
+
+        ## CHEETAH: generated from @def leftRightDeltaAFunctionBody($function, $replacementOperatorContainer) at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  First evaluate any computed vector that any of our operators may depend on
+        _v = VFFSL(SL,"evaluateComputedVectors",False)(VFFSL(SL,"dynamicVectorsNeedingPrecalculationForOperatorContainers",False)(VFFSL(SL,"intraStepOperatorContainers",True)), static = False) # u'${evaluateComputedVectors($dynamicVectorsNeedingPrecalculationForOperatorContainers($intraStepOperatorContainers), static = False)}' on line 27, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${evaluateComputedVectors($dynamicVectorsNeedingPrecalculationForOperatorContainers($intraStepOperatorContainers), static = False)}')) # from line 27, col 1.
+        # 
+        #  Then loop over operators that come before the delta A operators in the order in which
+        #  they appear in the xmds script.
+        # 
+        for operatorContainer in VFFSL(SL,"intraStepOperatorContainers",True): # generated from line 32, col 3
+            write(u'''
+''')
+            _v = VFN(VFFSL(SL,"operatorContainer",True),"evaluatePreDeltaAOperators",False)(parentFunction = function) # u'${operatorContainer.evaluatePreDeltaAOperators(parentFunction = function)}' on line 34, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${operatorContainer.evaluatePreDeltaAOperators(parentFunction = function)}')) # from line 34, col 1.
+        # 
+        #  Now loop over delta A operators
+        #  See the comment in _Integrator about why this needs to be done in
+        #  this particular order
+        for operatorContainer in VFFSL(SL,"intraStepOperatorContainersInFieldDescendingOrder",True): # generated from line 40, col 3
+            #  Blank line for formatting
+            write(u'''
+''')
+            if not operatorContainer == VFFSL(SL,"operatorContainerToOverride",True): # generated from line 43, col 5
+                _v = VFN(VFFSL(SL,"operatorContainer",True),"evaluateDeltaAOperator",False)(parentFunction = function) # u'${operatorContainer.evaluateDeltaAOperator(parentFunction = function)}' on line 44, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${operatorContainer.evaluateDeltaAOperator(parentFunction = function)}')) # from line 44, col 1.
+            else: # generated from line 45, col 5
+                _v = VFN(VFFSL(SL,"replacementOperatorContainer",True),"evaluateDeltaAOperator",False)(parentFunction = function) # u'${replacementOperatorContainer.evaluateDeltaAOperator(parentFunction = function)}' on line 46, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${replacementOperatorContainer.evaluateDeltaAOperator(parentFunction = function)}')) # from line 46, col 1.
+        # 
+        #  Lastly, loop over the operators that come after the delta a operators in the order in
+        #  which they appear in the xmds script.
+        # 
+        for operatorContainer in VFFSL(SL,"intraStepOperatorContainers",True): # generated from line 53, col 3
+            #  Blank line for formatting
+            write(u'''
+''')
+            _v = VFN(VFFSL(SL,"operatorContainer",True),"evaluatePostDeltaAOperators",False)(parentFunction = function) # u'${operatorContainer.evaluatePostDeltaAOperators(parentFunction = function)}' on line 56, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${operatorContainer.evaluatePostDeltaAOperators(parentFunction = function)}')) # from line 56, col 1.
+        # 
+        write(u'''
+''')
+        integrationVectorsNeedingUpdating = VFFSL(SL,"integrationVectors",True)
+        integrationVectorsNeedingUpdating.difference_update(replacementOperatorContainer.deltaAOperator.integrationVectors)
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectorsNeedingUpdating",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectorsNeedingUpdating, $homeBasis), autoIndent=True}' on line 62, col 1
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${transformVectorsToBasis($integrationVectorsNeedingUpdating, $homeBasis), autoIndent=True}')) # from line 62, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectorsNeedingUpdating",True),
+''.join([u'// a = oldcopy + a\n_\\${vector.id}[\\$index] += _',str(VFFSL(SL,"name",True)),u'_oldcopy_\\${vector.id}[\\$index];\n']), basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectorsNeedingUpdating,\nc"""// a = oldcopy + a\n_\\${vector.id}[\\$index] += _${name}_oldcopy_\\${vector.id}[\\$index];\n""", basis = $homeBasis)}')) # from line 64, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # FixedStepWithCross.tmpl
+        # 
+        # Created by Graham Dennis on 2008-11-12.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_FixedStepWithCross= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(FixedStepWithCross, '_initCheetahAttributes'):
+    templateAPIClass = getattr(FixedStepWithCross, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(FixedStepWithCross)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=FixedStepWithCross()).run()
+
+
diff --git a/xpdeint/Segments/Integrators/FixedStepWithCross.tmpl b/xpdeint/Segments/Integrators/FixedStepWithCross.tmpl
new file mode 100644
index 0000000..534cb30
--- /dev/null
+++ b/xpdeint/Segments/Integrators/FixedStepWithCross.tmpl
@@ -0,0 +1,70 @@
+@*
+FixedStepWithCross.tmpl
+
+Created by Graham Dennis on 2008-11-12.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Segments.Integrators._FixedStepWithCross
+
+ at def leftRightDeltaAFunctionBody($function, $replacementOperatorContainer)
+  @#
+  @# First evaluate any computed vector that any of our operators may depend on
+${evaluateComputedVectors($dynamicVectorsNeedingPrecalculationForOperatorContainers($intraStepOperatorContainers), static = False)}@slurp
+  @#
+  @# Then loop over operators that come before the delta A operators in the order in which
+  @# they appear in the xmds script.
+  @#
+  @for $operatorContainer in $intraStepOperatorContainers
+
+${operatorContainer.evaluatePreDeltaAOperators(parentFunction = function)}@slurp
+  @end for
+  @#
+  @# Now loop over delta A operators
+  @# See the comment in _Integrator about why this needs to be done in
+  @# this particular order
+  @for $operatorContainer in $intraStepOperatorContainersInFieldDescendingOrder
+    @# Blank line for formatting
+
+    @if not operatorContainer == $operatorContainerToOverride
+${operatorContainer.evaluateDeltaAOperator(parentFunction = function)}@slurp
+    @else
+${replacementOperatorContainer.evaluateDeltaAOperator(parentFunction = function)}@slurp
+    @end if
+  @end for
+  @#
+  @# Lastly, loop over the operators that come after the delta a operators in the order in
+  @# which they appear in the xmds script.
+  @#
+  @for $operatorContainer in $intraStepOperatorContainers
+    @# Blank line for formatting
+
+${operatorContainer.evaluatePostDeltaAOperators(parentFunction = function)}@slurp
+  @end for
+  @#
+
+  @set $integrationVectorsNeedingUpdating = $integrationVectors
+  @silent integrationVectorsNeedingUpdating.difference_update(replacementOperatorContainer.deltaAOperator.integrationVectors)
+${transformVectorsToBasis($integrationVectorsNeedingUpdating, $homeBasis), autoIndent=True}@slurp
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectorsNeedingUpdating,
+c"""// a = oldcopy + a
+_\${vector.id}[\$index] += _${name}_oldcopy_\${vector.id}[\$index];
+""", basis = $homeBasis)}@slurp
+  @#
+ at end def
+
diff --git a/xpdeint/Segments/Integrators/Integrator.py b/xpdeint/Segments/Integrators/Integrator.py
new file mode 100644
index 0000000..bb049e2
--- /dev/null
+++ b/xpdeint/Segments/Integrators/Integrator.py
@@ -0,0 +1,644 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Segments.Integrators._Integrator import _Integrator
+from xpdeint.CallOnceGuards import callOncePerInstanceGuard
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.656601
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Segments/Integrators/Integrator.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class Integrator(_Integrator):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(Integrator, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: segment $segmentNumber ($stepper.name Integrator) at line 25, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''segment ''')
+        _v = VFFSL(SL,"segmentNumber",True) # u'$segmentNumber' on line 25, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'$segmentNumber')) # from line 25, col 27.
+        write(u''' (''')
+        _v = VFFSL(SL,"stepper.name",True) # u'$stepper.name' on line 25, col 43
+        if _v is not None: write(_filter(_v, rawExpr=u'$stepper.name')) # from line 25, col 43.
+        write(u''' Integrator)''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def globals at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(Integrator, self).globals()
+        if _v is not None: write(_filter(_v))
+        # 
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 31, col 3
+            #  Loop over the variables that need to be created
+            for arrayName in VFFSL(SL,"extraIntegrationArrayNames",True): # generated from line 33, col 5
+                _v = VFFSL(SL,"vector.type",True) # u'${vector.type}' on line 34, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.type}')) # from line 34, col 1.
+                write(u'''* _''')
+                _v = VFFSL(SL,"name",True) # u'${name}' on line 34, col 18
+                if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 34, col 18.
+                write(u'''_''')
+                _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 34, col 26
+                if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 34, col 26.
+                write(u'''_''')
+                _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 34, col 39
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 34, col 39.
+                write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def deltaAFunctionBody(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def deltaAFunctionBody($function) at line 40, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  First evaluate any computed vector that any of our operators may depend on
+        _v = VFFSL(SL,"evaluateComputedVectors",False)(VFFSL(SL,"dynamicVectorsNeedingPrecalculationForOperatorContainers",False)(VFFSL(SL,"intraStepOperatorContainers",True)), static = False) # u'${evaluateComputedVectors($dynamicVectorsNeedingPrecalculationForOperatorContainers($intraStepOperatorContainers), static = False)}' on line 43, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${evaluateComputedVectors($dynamicVectorsNeedingPrecalculationForOperatorContainers($intraStepOperatorContainers), static = False)}')) # from line 43, col 1.
+        # 
+        #  Then loop over operators that come before the delta A operators in the order in which
+        #  they appear in the xmds script.
+        # 
+        for operatorContainer in VFFSL(SL,"intraStepOperatorContainers",True): # generated from line 48, col 3
+            write(u'''
+''')
+            _v = VFN(VFFSL(SL,"operatorContainer",True),"evaluatePreDeltaAOperators",False)(parentFunction = function) # u'${operatorContainer.evaluatePreDeltaAOperators(parentFunction = function)}' on line 50, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${operatorContainer.evaluatePreDeltaAOperators(parentFunction = function)}')) # from line 50, col 1.
+        # 
+        #  Now loop over delta A operators
+        #  See the comment in _Integrator about why this needs to be done in
+        #  this particular order
+        for operatorContainer in VFFSL(SL,"intraStepOperatorContainersInFieldDescendingOrder",True): # generated from line 56, col 3
+            #  Blank line for formatting
+            write(u'''
+''')
+            _v = VFN(VFFSL(SL,"operatorContainer",True),"evaluateDeltaAOperator",False)(parentFunction = function) # u'${operatorContainer.evaluateDeltaAOperator(parentFunction = function)}' on line 59, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${operatorContainer.evaluateDeltaAOperator(parentFunction = function)}')) # from line 59, col 1.
+        # 
+        #  Lastly, loop over the operators that come after the delta a operators in the order in
+        #  which they appear in the xmds script.
+        # 
+        for operatorContainer in VFFSL(SL,"intraStepOperatorContainers",True): # generated from line 65, col 3
+            #  Blank line for formatting
+            write(u'''
+''')
+            _v = VFN(VFFSL(SL,"operatorContainer",True),"evaluatePostDeltaAOperators",False)(parentFunction = function) # u'${operatorContainer.evaluatePostDeltaAOperators(parentFunction = function)}' on line 68, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${operatorContainer.evaluatePostDeltaAOperators(parentFunction = function)}')) # from line 68, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def preSingleStep(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def preSingleStep at line 73, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"evaluateComputedVectors",False)(VFFSL(SL,"dynamicVectorsNeedingPrecalculationForOperatorContainers",False)(VFFSL(SL,"stepStartOperatorContainers",True))) # u'${evaluateComputedVectors($dynamicVectorsNeedingPrecalculationForOperatorContainers($stepStartOperatorContainers))}' on line 75, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${evaluateComputedVectors($dynamicVectorsNeedingPrecalculationForOperatorContainers($stepStartOperatorContainers))}')) # from line 75, col 1.
+        # 
+        for operatorContainer in VFFSL(SL,"stepStartOperatorContainers",True): # generated from line 77, col 3
+            write(u'''
+''')
+            _v = VFN(VFFSL(SL,"operatorContainer",True),"evaluateOperators",False)(_step = '_step') # u"${operatorContainer.evaluateOperators(_step = '_step')}" on line 79, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u"${operatorContainer.evaluateOperators(_step = '_step')}")) # from line 79, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def postSingleStep(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def postSingleStep at line 84, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        featureOrdering = ['HaltNonFinite']
+        # 
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('postSingleStep', featureOrdering) # u"${insertCodeForFeatures('postSingleStep', featureOrdering)}" on line 88, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('postSingleStep', featureOrdering)}")) # from line 88, col 1.
+        # 
+        _v = VFFSL(SL,"evaluateComputedVectors",False)(VFFSL(SL,"dynamicVectorsNeedingPrecalculationForOperatorContainers",False)(VFFSL(SL,"stepEndOperatorContainers",True))) # u'${evaluateComputedVectors($dynamicVectorsNeedingPrecalculationForOperatorContainers($stepEndOperatorContainers))}' on line 90, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${evaluateComputedVectors($dynamicVectorsNeedingPrecalculationForOperatorContainers($stepEndOperatorContainers))}')) # from line 90, col 1.
+        # 
+        for operatorContainer in VFFSL(SL,"stepEndOperatorContainers",True): # generated from line 92, col 3
+            write(u'''
+''')
+            _v = VFN(VFFSL(SL,"operatorContainer",True),"evaluateOperators",False)(_step = '_step') # u"${operatorContainer.evaluateOperators(_step = '_step')}" on line 94, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u"${operatorContainer.evaluateOperators(_step = '_step')}")) # from line 94, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOncePerInstanceGuard
+    def allocate(self, **KWS):
+
+
+        """
+        Allocate additional arrays needed for the integrator
+        
+        This is a call once-per-instance function because we may want to do the initialisation
+        (and clean-up) for this segment in a parent segment for efficiency reasons (if, for
+        example we are looping over this segment, or we are running multiple paths).
+        """
+
+        ## CHEETAH: generated from @def allocate at line 100, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(Integrator, self).allocate()
+        if _v is not None: write(_filter(_v))
+        # 
+        #  Loop over the vectors creating the arrays
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 112, col 3
+            #  Loop over the variables that need to be created
+            for arrayName in VFFSL(SL,"extraIntegrationArrayNames",True): # generated from line 114, col 5
+                write(u'''_''')
+                _v = VFFSL(SL,"name",True) # u'${name}' on line 115, col 2
+                if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 115, col 2.
+                write(u'''_''')
+                _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 115, col 10
+                if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 115, col 10.
+                write(u'''_''')
+                _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 115, col 23
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 115, col 23.
+                write(u''' = ''')
+                write(u'''(''')
+                _v = VFFSL(SL,"vector.type",True) # u'${vector.type}' on line 116, col 2
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.type}')) # from line 116, col 2.
+                write(u'''*) xmds_malloc(sizeof(''')
+                _v = VFFSL(SL,"vector.type",True) # u'${vector.type}' on line 116, col 38
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.type}')) # from line 116, col 38.
+                write(u''') * MAX(''')
+                _v = VFFSL(SL,"vector.allocSize",True) # u'${vector.allocSize}' on line 116, col 60
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.allocSize}')) # from line 116, col 60.
+                write(u''',1));
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOncePerInstanceGuard
+    def free(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def free at line 123, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(Integrator, self).free()
+        if _v is not None: write(_filter(_v))
+        # 
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 127, col 3
+            for arrayName in VFFSL(SL,"extraIntegrationArrayNames",True): # generated from line 128, col 5
+                write(u'''xmds_free(_''')
+                _v = VFFSL(SL,"name",True) # u'${name}' on line 129, col 12
+                if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 129, col 12.
+                write(u'''_''')
+                _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 129, col 20
+                if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 129, col 20.
+                write(u'''_''')
+                _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 129, col 33
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 129, col 33.
+                write(u''');
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def localInitialise(self, **KWS):
+
+
+        """
+        Because the initialisation for the integrator could be in a different function,
+        we need to set up pointers in the integrator to the appropriate arrays.
+        """
+
+        ## CHEETAH: generated from @def localInitialise at line 135, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 141, col 3
+            #  Loop over the variables that need to be created
+            for arrayName in VFFSL(SL,"extraIntegrationArrayNames",True): # generated from line 143, col 5
+                _v = VFFSL(SL,"vector.type",True) # u'${vector.type}' on line 144, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.type}')) # from line 144, col 1.
+                write(u'''* _''')
+                _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 144, col 18
+                if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 144, col 18.
+                write(u'''_''')
+                _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 144, col 31
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 144, col 31.
+                write(u''' = _''')
+                _v = VFFSL(SL,"name",True) # u'${name}' on line 144, col 47
+                if _v is not None: write(_filter(_v, rawExpr=u'${name}')) # from line 144, col 47.
+                write(u'''_''')
+                _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 144, col 55
+                if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 144, col 55.
+                write(u'''_''')
+                _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 144, col 68
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 144, col 68.
+                write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"stepper.localInitialise",True) # u'${stepper.localInitialise}' on line 148, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepper.localInitialise}')) # from line 148, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def localFinalise(self, **KWS):
+
+
+        """
+        Because the finalisation for the integrator could be in a different function,
+        we need to be able to insert code at the end of the integrator as well.
+        """
+
+        ## CHEETAH: generated from @def localFinalise at line 152, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''_SEGMENT''')
+        _v = VFFSL(SL,"segmentNumber",True) # u'${segmentNumber}' on line 158, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${segmentNumber}')) # from line 158, col 9.
+        write(u'''_END:;
+''')
+        _v = VFFSL(SL,"stepper.localFinalise",True) # u'${stepper.localFinalise}' on line 159, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${stepper.localFinalise}')) # from line 159, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def earlyTerminationCode(self, **KWS):
+
+
+        """
+        This method writes code that should be executed if the integrator needs
+        to be terminated early
+        """
+
+        ## CHEETAH: generated from @def earlyTerminationCode at line 163, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        for mg, sampleCount in zip(VFFSL(SL,"momentGroups",True), VFFSL(SL,"samples",True)): # generated from line 169, col 3
+            if not VFFSL(SL,"sampleCount",True): # generated from line 170, col 5
+                continue
+            # 
+            for dim in filter(lambda x: not x.transverse, mg.outputField.dimensions): # generated from line 174, col 5
+                dimRep = dim.inBasis(mg.outputBasis)
+                write(u'''if (''')
+                _v = VFFSL(SL,"dimRep.prefix",True) # u'${dimRep.prefix}' on line 176, col 5
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.prefix}')) # from line 176, col 5.
+                write(u'''_index_''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 176, col 28
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 176, col 28.
+                write(u''' < ''')
+                _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 176, col 45
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 176, col 45.
+                write(u''')
+  _''')
+                _v = VFFSL(SL,"mg.name",True) # u'${mg.name}' on line 177, col 4
+                if _v is not None: write(_filter(_v, rawExpr=u'${mg.name}')) # from line 177, col 4.
+                write(u'''_sample();
+''')
+        write(u'''
+goto _SEGMENT''')
+        _v = VFFSL(SL,"segmentNumber",True) # u'${segmentNumber}' on line 181, col 14
+        if _v is not None: write(_filter(_v, rawExpr=u'${segmentNumber}')) # from line 181, col 14.
+        write(u'''_END;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # Integrator.tmpl
+        # 
+        # Created by Graham Dennis on 2007-10-20.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_Integrator= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(Integrator, '_initCheetahAttributes'):
+    templateAPIClass = getattr(Integrator, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(Integrator)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=Integrator()).run()
+
+
diff --git a/xpdeint/Segments/Integrators/Integrator.tmpl b/xpdeint/Segments/Integrators/Integrator.tmpl
new file mode 100644
index 0000000..2e2c578
--- /dev/null
+++ b/xpdeint/Segments/Integrators/Integrator.tmpl
@@ -0,0 +1,183 @@
+@*
+Integrator.tmpl
+
+Created by Graham Dennis on 2007-10-20.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Segments.Integrators._Integrator
+ at from xpdeint.CallOnceGuards import callOncePerInstanceGuard
+
+ at def description: segment $segmentNumber ($stepper.name Integrator)
+
+ at def globals
+  @#
+  @super
+  @#
+  @for $vector in $integrationVectors
+    @# Loop over the variables that need to be created
+    @for $arrayName in $extraIntegrationArrayNames
+${vector.type}* _${name}_${arrayName}_${vector.id};
+    @end for
+  @end for
+  @#
+ at end def
+
+ at def deltaAFunctionBody($function)
+  @#
+  @# First evaluate any computed vector that any of our operators may depend on
+${evaluateComputedVectors($dynamicVectorsNeedingPrecalculationForOperatorContainers($intraStepOperatorContainers), static = False)}@slurp
+  @#
+  @# Then loop over operators that come before the delta A operators in the order in which
+  @# they appear in the xmds script.
+  @#
+  @for $operatorContainer in $intraStepOperatorContainers
+
+${operatorContainer.evaluatePreDeltaAOperators(parentFunction = function)}@slurp
+  @end for
+  @#
+  @# Now loop over delta A operators
+  @# See the comment in _Integrator about why this needs to be done in
+  @# this particular order
+  @for $operatorContainer in $intraStepOperatorContainersInFieldDescendingOrder
+    @# Blank line for formatting
+
+${operatorContainer.evaluateDeltaAOperator(parentFunction = function)}@slurp
+  @end for
+  @#
+  @# Lastly, loop over the operators that come after the delta a operators in the order in
+  @# which they appear in the xmds script.
+  @#
+  @for $operatorContainer in $intraStepOperatorContainers
+    @# Blank line for formatting
+
+${operatorContainer.evaluatePostDeltaAOperators(parentFunction = function)}@slurp
+  @end for
+  @#
+ at end def
+
+ at def preSingleStep
+  @#
+${evaluateComputedVectors($dynamicVectorsNeedingPrecalculationForOperatorContainers($stepStartOperatorContainers))}@slurp
+  @#
+  @for $operatorContainer in $stepStartOperatorContainers
+
+${operatorContainer.evaluateOperators(_step = '_step')}@slurp
+  @end for
+  @#
+ at end def
+
+ at def postSingleStep
+  @#
+  @set $featureOrdering = ['HaltNonFinite']
+  @#
+${insertCodeForFeatures('postSingleStep', featureOrdering)}@slurp
+  @#
+${evaluateComputedVectors($dynamicVectorsNeedingPrecalculationForOperatorContainers($stepEndOperatorContainers))}@slurp
+  @#
+  @for $operatorContainer in $stepEndOperatorContainers
+
+${operatorContainer.evaluateOperators(_step = '_step')}@slurp
+  @end for
+  @#
+ at end def
+
+@@callOncePerInstanceGuard
+ at def allocate
+@*doc:
+Allocate additional arrays needed for the integrator
+
+This is a call once-per-instance function because we may want to do the initialisation
+(and clean-up) for this segment in a parent segment for efficiency reasons (if, for
+example we are looping over this segment, or we are running multiple paths).
+*@
+  @#
+  @super
+  @#
+  @# Loop over the vectors creating the arrays
+  @for $vector in $integrationVectors
+    @# Loop over the variables that need to be created
+    @for $arrayName in $extraIntegrationArrayNames
+_${name}_${arrayName}_${vector.id} = @slurp
+(${vector.type}*) xmds_malloc(sizeof(${vector.type}) * MAX(${vector.allocSize},1));
+    @end for
+  @end for
+  @#
+ at end def
+
+@@callOncePerInstanceGuard
+ at def free
+  @#
+  @super
+  @#
+  @for $vector in $integrationVectors
+    @for $arrayName in $extraIntegrationArrayNames
+xmds_free(_${name}_${arrayName}_${vector.id});
+    @end for
+  @end for
+  @#
+ at end def
+
+ at def localInitialise
+@*doc:
+Because the initialisation for the integrator could be in a different function,
+we need to set up pointers in the integrator to the appropriate arrays.
+*@
+  @#
+  @for $vector in $integrationVectors
+    @# Loop over the variables that need to be created
+    @for $arrayName in $extraIntegrationArrayNames
+${vector.type}* _${arrayName}_${vector.id} = _${name}_${arrayName}_${vector.id};
+    @end for
+  @end for
+
+${stepper.localInitialise}@slurp
+  @#
+ at end def
+
+ at def localFinalise
+@*doc:
+Because the finalisation for the integrator could be in a different function,
+we need to be able to insert code at the end of the integrator as well.
+*@
+  @#
+_SEGMENT${segmentNumber}_END:;
+${stepper.localFinalise}@slurp
+  @#
+ at end def
+
+ at def earlyTerminationCode
+@*doc:
+This method writes code that should be executed if the integrator needs
+to be terminated early
+*@
+  @#
+  @for mg, sampleCount in zip($momentGroups, $samples)
+    @if not $sampleCount
+      @continue
+    @end if
+    @#
+    @for dim in filter(lambda x: not x.transverse, mg.outputField.dimensions)
+      @set $dimRep = dim.inBasis(mg.outputBasis)
+if (${dimRep.prefix}_index_${dimRep.name} < ${dimRep.globalLattice})
+  _${mg.name}_sample();
+    @end for
+  @end for
+
+goto _SEGMENT${segmentNumber}_END;
+  @#
+ at end def
diff --git a/xpdeint/Segments/Integrators/RK45Stepper.py b/xpdeint/Segments/Integrators/RK45Stepper.py
new file mode 100644
index 0000000..1948154
--- /dev/null
+++ b/xpdeint/Segments/Integrators/RK45Stepper.py
@@ -0,0 +1,651 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Segments.Integrators._Stepper import _Stepper
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.711689
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Segments/Integrators/RK45Stepper.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class RK45Stepper(_Stepper):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(RK45Stepper, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def name(self, **KWS):
+
+
+
+        ## Generated from @def name: RK45 at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''RK45''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def localInitialise(self, **KWS):
+
+
+        """
+        Initialise all of the Cash-Karp coefficients, etc.
+        """
+
+        ## CHEETAH: generated from @def localInitialise at line 34, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(RK45Stepper, self).localInitialise()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''
+// Cash-Karp coefficients
+real _a_raw[7];
+real _a[7];
+real _b[7][7];
+real _c[7];
+real _cs[7];
+// linear combinations for the (k_i)s
+real _d[4];
+real _e[5];
+real _f[6];
+real _g[7];
+
+_a_raw[0]=0.0;
+_a_raw[1]=0.0;
+_a_raw[2]=1.0/5;
+_a_raw[3]=3.0/10;
+_a_raw[4]=3.0/5;
+_a_raw[5]=1.0;
+_a_raw[6]=7.0/8.0;
+
+_a[0]=0.0;
+_a[1]=0.0;
+for(long _i0 = 2; _i0 < 7; _i0++)
+  _a[_i0] = _a_raw[_i0] - _a_raw[_i0-1];
+
+_b[2][1]=1.0/5;
+_b[3][1]=3.0/40;
+_b[3][2]=9.0/40;
+_b[4][1]=3.0/10;
+_b[4][2]=-9.0/10;
+_b[4][3]=6.0/5;
+_b[5][1]=-11.0/54;
+_b[5][2]=5.0/2;
+_b[5][3]=-70.0/27;
+_b[5][4]=35.0/27;
+_b[6][1]=1631.0/55296;
+_b[6][2]=175.0/512;
+_b[6][3]=575.0/13824;
+_b[6][4]=44275.0/110592;
+_b[6][5]=253.0/4096;
+
+_c[0]=0.0;
+_c[1]=37.0/378;
+_c[2]=0.0;
+_c[3]=250.0/621;
+_c[4]=125.0/594;
+_c[5]=0.0;
+_c[6]=512.0/1771;
+
+_cs[0]=0.0;
+_cs[1]=2825.0/27648;
+_cs[2]=0.0;
+_cs[3]=18575.0/48384;
+_cs[4]=13525.0/55296;
+_cs[5]=277.0/14336;
+_cs[6]=1.0/4;
+
+_d[0]=0.0;
+_d[1]=1.0-_b[3][1]/_c[1];
+_d[2]=_b[3][1]/_c[1];
+_d[3]=_b[3][2];
+
+_e[0]=0.0;
+_e[1]=1.0-_b[4][1]/_c[1];
+_e[2]=_b[4][1]/_c[1];
+_e[3]=_b[4][2];
+_e[4]=_b[4][3];
+
+_f[0]=0.0;
+_f[1]=1.0-_b[5][1]/_c[1];
+_f[2]=_b[5][1]/_c[1];
+_f[3]=_b[5][2];
+_f[4]=_b[5][3]-_b[5][1]/_c[1]*_c[3];
+_f[5]=_b[5][4]-_b[5][1]/_c[1]*_c[4];
+
+real _den=_c[1]*_cs[4]-_cs[1]*_c[4];
+_g[0]=0.0;
+_g[1]=( _b[6][4]*(_cs[1]-_c[1]) + _b[6][1]*(_c[4]-_cs[4]) )/_den + 1.0;
+_g[2]=  _b[6][2];
+_g[3]=( _b[6][4]*(_cs[1]*_c[3] - _c[1]*_cs[3]) + _b[6][1]*(_cs[3]*_c[4] - _c[3]*_cs[4]) )/_den + _b[6][3];
+_g[4]=( _b[6][1]*_cs[4]-_b[6][4]*_cs[1] )/_den;
+_g[5]=  _b[6][5] + _cs[5]*( _b[6][1]*_c[4]-_b[6][4]*_c[1] )/_den;
+_g[6]=( -_b[6][1]*_c[4]+_b[6][4]*_c[1] )/_den;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def singleIntegrationStep(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def singleIntegrationStep($function) at line 131, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        arguments = {'_step': '_step'}
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 134, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 134, col 1.
+        write(u'''
+// a_k = y1
+''')
+        _v = VFFSL(SL,"copyVectors",False)(VFFSL(SL,"integrationVectors",True), '_akfield') # u"${copyVectors($integrationVectors, '_akfield')}" on line 137, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${copyVectors($integrationVectors, '_akfield')}")) # from line 137, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction=function)}" on line 139, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction=function)}")) # from line 139, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +1, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}" on line 142, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}")) # from line 142, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 143, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 143, col 1.
+        write(u'''
+// y2 = y1
+''')
+        _v = VFFSL(SL,"copyVectors",False)(VFFSL(SL,"integrationVectors",True), '_checkfield') # u"${copyVectors($integrationVectors, '_checkfield')}" on line 146, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${copyVectors($integrationVectors, '_checkfield')}")) # from line 146, col 1.
+        write(u'''
+// a_i = y1
+''')
+        _v = VFFSL(SL,"copyVectors",False)(VFFSL(SL,"integrationVectors",True), '_aifield') # u"${copyVectors($integrationVectors, '_aifield')}" on line 149, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${copyVectors($integrationVectors, '_aifield')}")) # from line 149, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 151, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 152, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 152, col 9.
+            write(u''' = _akfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 152, col 33
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 152, col 33.
+            write(u''';
+''')
+        write(u'''
+// a_k = G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 156, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 156, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[a_k]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +1, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}" on line 159, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}")) # from line 159, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 160, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 160, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""// y1 = y1 + c_1*a_k
+_${vector.id}[$index] += _c[1]*_akfield_${vector.id}[$index];
+// y2 = y2 + cs_1*a_k
+_checkfield_${vector.id}[$index] += _cs[1]*_akfield_${vector.id}[$index];
+// a_k = a_i + b_21*a_k
+_akfield_${vector.id}[$index] = _aifield_${vector.id}[$index] + _b[2][1]*_akfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""// y1 = y1 + c_1*a_k\n_${vector.id}[$index] += _c[1]*_akfield_${vector.id}[$index];\n// y2 = y2 + cs_1*a_k\n_checkfield_${vector.id}[$index] += _cs[1]*_akfield_${vector.id}[$index];\n// a_k = a_i + b_21*a_k\n_akfield_${vector.id}[$index] = _aifield_${vector.id}[$index] + _b[2][1]*_akfield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 162, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 171, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 171, col 1.
+        write(u''' += _a[2] * _step;
+
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 2, _arrayIndex = 1, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 2, _arrayIndex = 1, parentFunction=function)}" on line 173, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 2, _arrayIndex = 1, parentFunction=function)}")) # from line 173, col 1.
+        write(u'''
+
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -2, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -2, parentFunction=function)}" on line 175, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -2, parentFunction=function)}")) # from line 175, col 1.
+        write(u'''
+
+// a_k = G[a_k, t + aa_2*dt]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 178, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 178, col 1.
+        write(u'''
+
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +2, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +2, parentFunction=function)}" on line 180, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +2, parentFunction=function)}")) # from line 180, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 181, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 181, col 1.
+        write(u'''
+// c_2 == cs_2 == 0
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""// a_j = d_1*a_i + d_2*y1 + d_3*a_k
+_ajfield_${vector.id}[$index] = _d[1]*_aifield_${vector.id}[$index] + _d[2]*_${vector.id}[$index] + _d[3]*_akfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""// a_j = d_1*a_i + d_2*y1 + d_3*a_k\n_ajfield_${vector.id}[$index] = _d[1]*_aifield_${vector.id}[$index] + _d[2]*_${vector.id}[$index] + _d[3]*_akfield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 184, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 189, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 189, col 1.
+        write(u''' += _a[3] * _step;
+
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 191, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 192, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 192, col 9.
+            write(u''' = _ajfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 192, col 33
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 192, col 33.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 3, _arrayIndex = 1, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 3, _arrayIndex = 1, parentFunction=function)}" on line 195, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 3, _arrayIndex = 1, parentFunction=function)}")) # from line 195, col 1.
+        write(u'''
+
+// a_j = D((a_3 - a_2)*dt)[a_j]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -3, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -3, parentFunction=function)}" on line 198, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -3, parentFunction=function)}")) # from line 198, col 1.
+        write(u'''
+
+// a_j = G[a_j, t + aa_3*dt]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 201, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 201, col 1.
+        write(u'''
+
+// a_j = D(-(a_3 - a_2)*dt)[a_j]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +3, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +3, parentFunction=function)}" on line 204, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +3, parentFunction=function)}")) # from line 204, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 205, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 205, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""// a_l = e_1*a_i + e_2*y1 + e_3*a_k + e_4*a_j
+_alfield_${vector.id}[$index] = _e[1]*_aifield_${vector.id}[$index] + _e[2]*_${vector.id}[$index] + _e[3]*_akfield_${vector.id}[$index] + _e[4]*_ajfield_${vector.id}[$index];
+// y1 = y1 + c_3*a_j
+_${vector.id}[$index] += _c[3]*_ajfield_${vector.id}[$index];
+// y2 = y2 + cs_3*a_j
+_checkfield_${vector.id}[$index] += _cs[3]*_ajfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""// a_l = e_1*a_i + e_2*y1 + e_3*a_k + e_4*a_j\n_alfield_${vector.id}[$index] = _e[1]*_aifield_${vector.id}[$index] + _e[2]*_${vector.id}[$index] + _e[3]*_akfield_${vector.id}[$index] + _e[4]*_ajfield_${vector.id}[$index];\n// y1 = y1 + c_3*a_j\n_${vector.id}[$index] += _c[3]*_ajfield_${vector.id}[$index];\n// y2 = y2 + cs_3*a_j\n_checkfield_${vector.id}[$index] += _cs [...]
+        write(u'''
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 216, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 216, col 1.
+        write(u''' += _a[4] * _step;
+
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 218, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 219, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 219, col 9.
+            write(u''' = _alfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 219, col 33
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 219, col 33.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 4, _arrayIndex = 1, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 4, _arrayIndex = 1, parentFunction=function)}" on line 222, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 4, _arrayIndex = 1, parentFunction=function)}")) # from line 222, col 1.
+        write(u'''
+
+// a_l = D((a_4 - a_2)*dt)[a_l]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -4, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -4, parentFunction=function)}" on line 225, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -4, parentFunction=function)}")) # from line 225, col 1.
+        write(u'''
+
+// a_l = G[a_l, t + aa_4*dt]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 228, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 228, col 1.
+        write(u'''
+
+// a_l = D(-(a_4 - a_2)*dt)[a_l]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +4, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +4, parentFunction=function)}" on line 231, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +4, parentFunction=function)}")) # from line 231, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 232, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 232, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""// y1 = y1 + c_4*a_l
+_${vector.id}[$index] += _c[4]*_alfield_${vector.id}[$index];
+// y2 = y2 + cs_4*a_l
+_checkfield_${vector.id}[$index] += _cs[4]*_alfield_${vector.id}[$index];
+// a_l = f_1*a_i + f_2*y1 + f_3*a_k + f_4*a_j + f_5*a_l
+_alfield_${vector.id}[$index] = _f[1]*_aifield_${vector.id}[$index] + _f[2]*_${vector.id}[$index] + _f[3]*_akfield_${vector.id}[$index] + _f[4]*_ajfield_${vector.id}[$index] + _f[5]*_alfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""// y1 = y1 + c_4*a_l\n_${vector.id}[$index] += _c[4]*_alfield_${vector.id}[$index];\n// y2 = y2 + cs_4*a_l\n_checkfield_${vector.id}[$index] += _cs[4]*_alfield_${vector.id}[$index];\n// a_l = f_1*a_i + f_2*y1 + f_3*a_k + f_4*a_j + f_5*a_l\n_alfield_${vector.id}[$index] = _f[1]*_aifield_${vector.id}[$index] + _f[2]*_${vector.id}[$index] + _f[3]*_akfield_${vector.id}[$i [...]
+        write(u'''
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 243, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 243, col 1.
+        write(u''' += _a[5] * _step;
+
+// a_l = G[a_l, t + aa_5*dt]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 246, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 246, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 247, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 247, col 1.
+        write(u'''
+// c_5 == 0
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""// y2 = y2 + cs_5*a_l
+_checkfield_${vector.id}[$index] += _cs[5]*_alfield_${vector.id}[$index];
+// a_l = g_1*a_i + g_2*a_k + g_3*a_j + g_4*y_1 + g_5*a_l + g_6*y2
+_alfield_${vector.id}[$index] = _g[1]*_aifield_${vector.id}[$index] + _g[2]*_akfield_${vector.id}[$index] + _g[3]*_ajfield_${vector.id}[$index] + _g[4]*_${vector.id}[$index] + _g[5]*_alfield_${vector.id}[$index] + _g[6]*_checkfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""// y2 = y2 + cs_5*a_l\n_checkfield_${vector.id}[$index] += _cs[5]*_alfield_${vector.id}[$index];\n// a_l = g_1*a_i + g_2*a_k + g_3*a_j + g_4*y_1 + g_5*a_l + g_6*y2\n_alfield_${vector.id}[$index] = _g[1]*_aifield_${vector.id}[$index] + _g[2]*_akfield_${vector.id}[$index] + _g[3]*_ajfield_${vector.id}[$index] + _g[4]*_${vector.id}[$index] + _g[5]*_alfield_${vector.id}[$ [...]
+        write(u'''
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 257, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 257, col 1.
+        write(u''' += _a[6] * _step;
+
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 5, _arrayIndex = 1, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 5, _arrayIndex = 1, parentFunction=function)}" on line 259, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 5, _arrayIndex = 1, parentFunction=function)}")) # from line 259, col 1.
+        write(u'''
+
+// a_l = D((a_6 - a_2)*dt)[a_l]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -5, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -5, parentFunction=function)}" on line 262, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -5, parentFunction=function)}")) # from line 262, col 1.
+        write(u'''
+
+// a_l = G[a_l, t + aa_6*dt]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 265, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 265, col 1.
+        write(u'''
+
+// a_l = D(-(a_6 - a_2)*dt)[a_l]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +5, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +5, parentFunction=function)}" on line 268, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +5, parentFunction=function)}")) # from line 268, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 269, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 269, col 1.
+        write(u'''
+// c_5 == 0
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""// y1 = y1 + c_6*a_l
+_${vector.id}[$index] += _c[6]*_alfield_${vector.id}[$index];
+// y2 = y2 + cs_6*a_l
+_checkfield_${vector.id}[$index] += _cs[6]*_alfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""// y1 = y1 + c_6*a_l\n_${vector.id}[$index] += _c[6]*_alfield_${vector.id}[$index];\n// y2 = y2 + cs_6*a_l\n_checkfield_${vector.id}[$index] += _cs[6]*_alfield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 272, col 1.
+        write(u'''
+// t -> t + dt
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 280, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 280, col 1.
+        write(u''' -= _a[6]*_step;
+
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 282, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 283, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 283, col 9.
+            write(u''' = _checkfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 283, col 36
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 283, col 36.
+            write(u''';
+''')
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 286, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 287, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 287, col 9.
+            write(u''' = _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 287, col 25
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 287, col 25.
+            write(u''';
+''')
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # RK45Stepper.tmpl
+        # 
+        # Created by Graham Dennis on 2007-11-16.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+''')
+        # 
+        #   Single integration step (ARK45)
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    ipPropagationStepFractions = ['1.0', '4.0/5.0', '7.0/10.0', '2.0/5.0', '1.0/8.0']
+
+    nonconstantIPFields = 2
+
+    extraIntegrationArrayNames = ['akfield', 'aifield', 'ajfield', 'alfield', 'checkfield']
+
+    errorFieldName = 'checkfield'
+
+    resetFieldName = 'aifield'
+
+    integrationOrder = 5.0
+
+    _mainCheetahMethod_for_RK45Stepper= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(RK45Stepper, '_initCheetahAttributes'):
+    templateAPIClass = getattr(RK45Stepper, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(RK45Stepper)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=RK45Stepper()).run()
+
+
diff --git a/xpdeint/Segments/Integrators/RK45Stepper.tmpl b/xpdeint/Segments/Integrators/RK45Stepper.tmpl
new file mode 100644
index 0000000..0da8802
--- /dev/null
+++ b/xpdeint/Segments/Integrators/RK45Stepper.tmpl
@@ -0,0 +1,291 @@
+@*
+RK45Stepper.tmpl
+
+Created by Graham Dennis on 2007-11-16.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Segments.Integrators._Stepper
+
+ at def name: RK45
+ at attr $ipPropagationStepFractions = ['1.0', '4.0/5.0', '7.0/10.0', '2.0/5.0', '1.0/8.0']
+ at attr $nonconstantIPFields = 2
+ at attr $extraIntegrationArrayNames = ['akfield', 'aifield', 'ajfield', 'alfield', 'checkfield']
+
+ at attr $errorFieldName = 'checkfield'
+ at attr $resetFieldName = 'aifield'
+
+ at attr $integrationOrder = 5.0
+
+ at def localInitialise
+@*doc:
+Initialise all of the Cash-Karp coefficients, etc.
+*@
+  @#
+  @super
+  @#
+
+// Cash-Karp coefficients
+real _a_raw[7];
+real _a[7];
+real _b[7][7];
+real _c[7];
+real _cs[7];
+// linear combinations for the (k_i)s
+real _d[4];
+real _e[5];
+real _f[6];
+real _g[7];
+
+_a_raw[0]=0.0;
+_a_raw[1]=0.0;
+_a_raw[2]=1.0/5;
+_a_raw[3]=3.0/10;
+_a_raw[4]=3.0/5;
+_a_raw[5]=1.0;
+_a_raw[6]=7.0/8.0;
+
+_a[0]=0.0;
+_a[1]=0.0;
+for(long _i0 = 2; _i0 < 7; _i0++)
+  _a[_i0] = _a_raw[_i0] - _a_raw[_i0-1];
+
+_b[2][1]=1.0/5;
+_b[3][1]=3.0/40;
+_b[3][2]=9.0/40;
+_b[4][1]=3.0/10;
+_b[4][2]=-9.0/10;
+_b[4][3]=6.0/5;
+_b[5][1]=-11.0/54;
+_b[5][2]=5.0/2;
+_b[5][3]=-70.0/27;
+_b[5][4]=35.0/27;
+_b[6][1]=1631.0/55296;
+_b[6][2]=175.0/512;
+_b[6][3]=575.0/13824;
+_b[6][4]=44275.0/110592;
+_b[6][5]=253.0/4096;
+
+_c[0]=0.0;
+_c[1]=37.0/378;
+_c[2]=0.0;
+_c[3]=250.0/621;
+_c[4]=125.0/594;
+_c[5]=0.0;
+_c[6]=512.0/1771;
+
+_cs[0]=0.0;
+_cs[1]=2825.0/27648;
+_cs[2]=0.0;
+_cs[3]=18575.0/48384;
+_cs[4]=13525.0/55296;
+_cs[5]=277.0/14336;
+_cs[6]=1.0/4;
+
+_d[0]=0.0;
+_d[1]=1.0-_b[3][1]/_c[1];
+_d[2]=_b[3][1]/_c[1];
+_d[3]=_b[3][2];
+
+_e[0]=0.0;
+_e[1]=1.0-_b[4][1]/_c[1];
+_e[2]=_b[4][1]/_c[1];
+_e[3]=_b[4][2];
+_e[4]=_b[4][3];
+
+_f[0]=0.0;
+_f[1]=1.0-_b[5][1]/_c[1];
+_f[2]=_b[5][1]/_c[1];
+_f[3]=_b[5][2];
+_f[4]=_b[5][3]-_b[5][1]/_c[1]*_c[3];
+_f[5]=_b[5][4]-_b[5][1]/_c[1]*_c[4];
+
+real _den=_c[1]*_cs[4]-_cs[1]*_c[4];
+_g[0]=0.0;
+_g[1]=( _b[6][4]*(_cs[1]-_c[1]) + _b[6][1]*(_c[4]-_cs[4]) )/_den + 1.0;
+_g[2]=  _b[6][2];
+_g[3]=( _b[6][4]*(_cs[1]*_c[3] - _c[1]*_cs[3]) + _b[6][1]*(_cs[3]*_c[4] - _c[3]*_cs[4]) )/_den + _b[6][3];
+_g[4]=( _b[6][1]*_cs[4]-_b[6][4]*_cs[1] )/_den;
+_g[5]=  _b[6][5] + _cs[5]*( _b[6][1]*_c[4]-_b[6][4]*_c[1] )/_den;
+_g[6]=( -_b[6][1]*_c[4]+_b[6][4]*_c[1] )/_den;
+  @#
+ at end def
+
+@*
+  Single integration step (ARK45)
+*@
+ at def singleIntegrationStep($function)
+  @#
+  @set $arguments = {'_step': '_step'}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// a_k = y1
+${copyVectors($integrationVectors, '_akfield')}@slurp
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// y2 = y1
+${copyVectors($integrationVectors, '_checkfield')}@slurp
+
+// a_i = y1
+${copyVectors($integrationVectors, '_aifield')}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akfield_${vector.id};
+  @end for
+
+// a_k = G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i = D(a_2*dt)[a_k]
+${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""// y1 = y1 + c_1*a_k
+_${vector.id}[$index] += _c[1]*_akfield_${vector.id}[$index];
+// y2 = y2 + cs_1*a_k
+_checkfield_${vector.id}[$index] += _cs[1]*_akfield_${vector.id}[$index];
+// a_k = a_i + b_21*a_k
+_akfield_${vector.id}[$index] = _aifield_${vector.id}[$index] + _b[2][1]*_akfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+${propagationDimension} += _a[2] * _step;
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 2, _arrayIndex = 1, parentFunction=function)}
+
+${callFunction('ipEvolve', arguments, _exponent = -2, parentFunction=function)}
+
+// a_k = G[a_k, t + aa_2*dt]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+${callFunction('ipEvolve', arguments, _exponent = +2, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// c_2 == cs_2 == 0
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""// a_j = d_1*a_i + d_2*y1 + d_3*a_k
+_ajfield_${vector.id}[$index] = _d[1]*_aifield_${vector.id}[$index] + _d[2]*_${vector.id}[$index] + _d[3]*_akfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+${propagationDimension} += _a[3] * _step;
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _ajfield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 3, _arrayIndex = 1, parentFunction=function)}
+
+// a_j = D((a_3 - a_2)*dt)[a_j]
+${callFunction('ipEvolve', arguments, _exponent = -3, parentFunction=function)}
+
+// a_j = G[a_j, t + aa_3*dt]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_j = D(-(a_3 - a_2)*dt)[a_j]
+${callFunction('ipEvolve', arguments, _exponent = +3, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""// a_l = e_1*a_i + e_2*y1 + e_3*a_k + e_4*a_j
+_alfield_${vector.id}[$index] = _e[1]*_aifield_${vector.id}[$index] + _e[2]*_${vector.id}[$index] + _e[3]*_akfield_${vector.id}[$index] + _e[4]*_ajfield_${vector.id}[$index];
+// y1 = y1 + c_3*a_j
+_${vector.id}[$index] += _c[3]*_ajfield_${vector.id}[$index];
+// y2 = y2 + cs_3*a_j
+_checkfield_${vector.id}[$index] += _cs[3]*_ajfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+${propagationDimension} += _a[4] * _step;
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _alfield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 4, _arrayIndex = 1, parentFunction=function)}
+
+// a_l = D((a_4 - a_2)*dt)[a_l]
+${callFunction('ipEvolve', arguments, _exponent = -4, parentFunction=function)}
+
+// a_l = G[a_l, t + aa_4*dt]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_l = D(-(a_4 - a_2)*dt)[a_l]
+${callFunction('ipEvolve', arguments, _exponent = +4, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""// y1 = y1 + c_4*a_l
+_${vector.id}[$index] += _c[4]*_alfield_${vector.id}[$index];
+// y2 = y2 + cs_4*a_l
+_checkfield_${vector.id}[$index] += _cs[4]*_alfield_${vector.id}[$index];
+// a_l = f_1*a_i + f_2*y1 + f_3*a_k + f_4*a_j + f_5*a_l
+_alfield_${vector.id}[$index] = _f[1]*_aifield_${vector.id}[$index] + _f[2]*_${vector.id}[$index] + _f[3]*_akfield_${vector.id}[$index] + _f[4]*_ajfield_${vector.id}[$index] + _f[5]*_alfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+${propagationDimension} += _a[5] * _step;
+
+// a_l = G[a_l, t + aa_5*dt]
+${callFunction('deltaA', arguments, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// c_5 == 0
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""// y2 = y2 + cs_5*a_l
+_checkfield_${vector.id}[$index] += _cs[5]*_alfield_${vector.id}[$index];
+// a_l = g_1*a_i + g_2*a_k + g_3*a_j + g_4*y_1 + g_5*a_l + g_6*y2
+_alfield_${vector.id}[$index] = _g[1]*_aifield_${vector.id}[$index] + _g[2]*_akfield_${vector.id}[$index] + _g[3]*_ajfield_${vector.id}[$index] + _g[4]*_${vector.id}[$index] + _g[5]*_alfield_${vector.id}[$index] + _g[6]*_checkfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+${propagationDimension} += _a[6] * _step;
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 5, _arrayIndex = 1, parentFunction=function)}
+
+// a_l = D((a_6 - a_2)*dt)[a_l]
+${callFunction('ipEvolve', arguments, _exponent = -5, parentFunction=function)}
+
+// a_l = G[a_l, t + aa_6*dt]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_l = D(-(a_6 - a_2)*dt)[a_l]
+${callFunction('ipEvolve', arguments, _exponent = +5, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// c_5 == 0
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""// y1 = y1 + c_6*a_l
+_${vector.id}[$index] += _c[6]*_alfield_${vector.id}[$index];
+// y2 = y2 + cs_6*a_l
+_checkfield_${vector.id}[$index] += _cs[6]*_alfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+// t -> t + dt
+${propagationDimension} -= _a[6]*_step;
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _checkfield_${vector.id};
+  @end for
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _${vector.id};
+  @end for
+
+  @#
+ at end def
diff --git a/xpdeint/Segments/Integrators/RK4Stepper.py b/xpdeint/Segments/Integrators/RK4Stepper.py
new file mode 100644
index 0000000..7d80b3c
--- /dev/null
+++ b/xpdeint/Segments/Integrators/RK4Stepper.py
@@ -0,0 +1,461 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Segments.Integrators._Stepper import _Stepper
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.730721
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Segments/Integrators/RK4Stepper.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class RK4Stepper(_Stepper):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(RK4Stepper, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def name(self, **KWS):
+
+
+
+        ## Generated from @def name: RK4 at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''RK4''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def singleIntegrationStep(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def singleIntegrationStep($function) at line 37, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        arguments = {'_step': '_step', VFFSL(SL,"propagationDimension",True): VFFSL(SL,"propagationDimension",True)}
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 40, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 40, col 1.
+        write(u'''
+// a_k = a
+''')
+        _v = VFFSL(SL,"copyVectors",False)(VFFSL(SL,"integrationVectors",True), '_akfield') # u"${copyVectors($integrationVectors, '_akfield')}" on line 43, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${copyVectors($integrationVectors, '_akfield')}")) # from line 43, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction = function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction = function)}" on line 45, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction = function)}")) # from line 45, col 1.
+        write(u'''
+
+// a = D[a]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +1, parentFunction = function) # u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction = function)}" on line 48, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction = function)}")) # from line 48, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 49, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 49, col 1.
+        write(u'''
+// a_i = a
+''')
+        _v = VFFSL(SL,"copyVectors",False)(VFFSL(SL,"integrationVectors",True), '_aifield') # u"${copyVectors($integrationVectors, '_aifield')}" on line 52, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${copyVectors($integrationVectors, '_aifield')}")) # from line 52, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 54, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 55, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 55, col 9.
+            write(u''' = _akfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 55, col 33
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 55, col 33.
+            write(u''';
+''')
+        write(u'''  
+// a_k = G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction = function) # u"${callFunction('deltaA', arguments, parentFunction = function)}" on line 59, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction = function)}")) # from line 59, col 1.
+        write(u'''
+
+// a_k = D[a_k]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +1, parentFunction = function) # u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction = function)}" on line 62, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction = function)}")) # from line 62, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 63, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 63, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True), 
+"""// a = a + a_k/6
+_${vector.id}[$index] += _akfield_${vector.id}[$index]/6.0;
+// a_k = a_i + a_k/2
+_akfield_${vector.id}[$index] = _aifield_${vector.id}[$index] + 0.5*_akfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors, \n"""// a = a + a_k/6\n_${vector.id}[$index] += _akfield_${vector.id}[$index]/6.0;\n// a_k = a_i + a_k/2\n_akfield_${vector.id}[$index] = _aifield_${vector.id}[$index] + 0.5*_akfield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 65, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 72, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 72, col 1.
+        write(u''' += 0.5*_step;
+''')
+        if VFFSL(SL,"cross",True): # generated from line 73, col 3
+            write(u'''
+''')
+            _v = VFFSL(SL,"interpolateDependencies",True) # u'${interpolateDependencies}' on line 75, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${interpolateDependencies}')) # from line 75, col 1.
+        write(u'''
+// a_k = G[a_k, t + h/2]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction = function) # u"${callFunction('deltaA', arguments, parentFunction = function)}" on line 79, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction = function)}")) # from line 79, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 80, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 80, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""// a = a + a_k/3
+_${vector.id}[$index] += _akfield_${vector.id}[$index]/3.0;
+// a_k = a_i + a_k/2
+_akfield_${vector.id}[$index] = _aifield_${vector.id}[$index] + 0.5*_akfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""// a = a + a_k/3\n_${vector.id}[$index] += _akfield_${vector.id}[$index]/3.0;\n// a_k = a_i + a_k/2\n_akfield_${vector.id}[$index] = _aifield_${vector.id}[$index] + 0.5*_akfield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 82, col 1.
+        write(u'''
+// a_k = G[a_k, t + h/2]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction = function) # u"${callFunction('deltaA', arguments, parentFunction = function)}" on line 90, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction = function)}")) # from line 90, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 91, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 91, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""// a = a + a_k/3
+_${vector.id}[$index] += _akfield_${vector.id}[$index]/3.0;
+// a_k = a_i + a_k
+_akfield_${vector.id}[$index] = _aifield_${vector.id}[$index] + _akfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""// a = a + a_k/3\n_${vector.id}[$index] += _akfield_${vector.id}[$index]/3.0;\n// a_k = a_i + a_k\n_akfield_${vector.id}[$index] = _aifield_${vector.id}[$index] + _akfield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 93, col 1.
+        write(u'''
+// a_k = D[a_k]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +1, parentFunction = function) # u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction = function)}" on line 101, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction = function)}")) # from line 101, col 1.
+        write(u'''
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 103, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 103, col 1.
+        write(u''' += 0.5*_step;
+''')
+        if VFFSL(SL,"cross",True): # generated from line 104, col 3
+            write(u'''
+''')
+            _v = VFFSL(SL,"updateDependenciesForNextStep",True) # u'${updateDependenciesForNextStep}' on line 106, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${updateDependenciesForNextStep}')) # from line 106, col 1.
+        write(u'''
+// a_k = G[a_k, t + h]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction = function) # u"${callFunction('deltaA', arguments, parentFunction = function)}" on line 110, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction = function)}")) # from line 110, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 111, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 111, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 113, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 114, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 114, col 9.
+            write(u''' = _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 114, col 25
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 114, col 25.
+            write(u''';
+''')
+        write(u'''
+// a = D[a]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +1, parentFunction = function) # u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction = function)}" on line 118, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction = function)}")) # from line 118, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 119, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 119, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True), 
+"""// a = a + a_k/6
+_${vector.id}[$index] += _akfield_${vector.id}[$index]/6.0;
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors, \n"""// a = a + a_k/6\n_${vector.id}[$index] += _akfield_${vector.id}[$index]/6.0;\n""", basis = $homeBasis)}')) # from line 121, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def interpolateDependencies(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def interpolateDependencies at line 129, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  Insert code to interpolate the dependency vectors onto the half-step point.
+        #  
+        write(u'''// Create 4th order midpoint interpolation for dependencies
+if (_istep == 0) {
+  // We are at the first point
+  ''')
+        _v = VFFSL(SL,"reducedFieldCopy",False)(VFFSL(SL,"integrator.dependencyMap",True), 
+"""
+_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = \\
+    1.0/16.0*( 5.0*_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex}]
+            + 15.0*_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + ${skipSize} * _${vector.id}_ncomponents]
+            -  5.0*_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + 2 * ${skipSize} * _${vector.id}_ncomponents]
+            +      _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + 3 * ${skipSize} * _${vector.id}_ncomponents]);
+""")
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${reducedFieldCopy($integrator.dependencyMap, \n"""\n_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = \\\\\n    1.0/16.0*( 5.0*_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex}]\n            + 15.0*_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + ${skipSize} * _${vector.id}_ncomponents]\n            -  5.0*_active_${vector.id}[_${vector.id} [...]
+        write(u'''} else if (_istep == (''')
+        _v = VFFSL(SL,"integrator.stepCount",True) # u'${integrator.stepCount}' on line 144, col 23
+        if _v is not None: write(_filter(_v, rawExpr=u'${integrator.stepCount}')) # from line 144, col 23.
+        write(u''' - 1)) {
+  // We are at the last point
+  ''')
+        _v = VFFSL(SL,"reducedFieldCopy",False)(VFFSL(SL,"integrator.dependencyMap",True), 
+"""
+_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = \\
+    1.0/16.0*(15.0*_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex}]
+            +  5.0*_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + ${skipSize} * _${vector.id}_ncomponents]
+            -  5.0*_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} - ${skipSize} * _${vector.id}_ncomponents]
+            +      _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} - 2 * ${skipSize} * _${vector.id}_ncomponents]);
+""")
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${reducedFieldCopy($integrator.dependencyMap, \n"""\n_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = \\\\\n    1.0/16.0*(15.0*_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex}]\n            +  5.0*_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + ${skipSize} * _${vector.id}_ncomponents]\n            -  5.0*_active_${vector.id}[_${vector.id} [...]
+        write(u'''} else {
+  // We are somewhere in the middle
+  ''')
+        _v = VFFSL(SL,"reducedFieldCopy",False)(VFFSL(SL,"integrator.dependencyMap",True), 
+"""
+_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = \\
+    9.0/16.0*(_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex}]
+            + _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + ${skipSize} * _${vector.id}_ncomponents])
+  - 1.0/16.0*(_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} - ${skipSize} * _${vector.id}_ncomponents]
+            + _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + 2 * ${skipSize} * _${vector.id}_ncomponents]);
+""")
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${reducedFieldCopy($integrator.dependencyMap, \n"""\n_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = \\\\\n    9.0/16.0*(_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex}]\n            + _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + ${skipSize} * _${vector.id}_ncomponents])\n  - 1.0/16.0*(_active_${vector.id}[_${vector.id}_index_pointer [...]
+        write(u'''}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # RK4Stepper.tmpl
+        # 
+        # Created by Graham Dennis on 2007-09-23.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+''')
+        # 
+        #   Single integration step (RK4)
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    ipPropagationStepFractions = ['0.5']
+
+    nonconstantIPFields = 1
+
+    extraIntegrationArrayNames = ['akfield', 'aifield']
+
+    isCrossCapable = True
+
+    resetFieldName = 'aifield'
+
+    integrationOrder = 4.0
+
+    _mainCheetahMethod_for_RK4Stepper= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(RK4Stepper, '_initCheetahAttributes'):
+    templateAPIClass = getattr(RK4Stepper, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(RK4Stepper)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=RK4Stepper()).run()
+
+
diff --git a/xpdeint/Segments/Integrators/RK4Stepper.tmpl b/xpdeint/Segments/Integrators/RK4Stepper.tmpl
new file mode 100644
index 0000000..db282fd
--- /dev/null
+++ b/xpdeint/Segments/Integrators/RK4Stepper.tmpl
@@ -0,0 +1,166 @@
+@*
+RK4Stepper.tmpl
+
+Created by Graham Dennis on 2007-09-23.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Segments.Integrators._Stepper
+
+ at def name: RK4
+ at attr $ipPropagationStepFractions = ['0.5']
+ at attr $nonconstantIPFields = 1
+ at attr $extraIntegrationArrayNames = ['akfield', 'aifield']
+ at attr $isCrossCapable = True
+
+ at attr $resetFieldName = 'aifield'
+
+ at attr $integrationOrder = 4.0
+
+@*
+  Single integration step (RK4)
+*@
+ at def singleIntegrationStep($function)
+  @#
+  @set $arguments = {'_step': '_step', $propagationDimension: $propagationDimension}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// a_k = a
+${copyVectors($integrationVectors, '_akfield')}@slurp
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction = function)}
+
+// a = D[a]
+${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction = function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// a_i = a
+${copyVectors($integrationVectors, '_aifield')}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akfield_${vector.id};
+  @end for
+  
+// a_k = G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction = function)}
+
+// a_k = D[a_k]
+${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction = function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors, 
+"""// a = a + a_k/6
+_${vector.id}[$index] += _akfield_${vector.id}[$index]/6.0;
+// a_k = a_i + a_k/2
+_akfield_${vector.id}[$index] = _aifield_${vector.id}[$index] + 0.5*_akfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+${propagationDimension} += 0.5*_step;
+  @if $cross
+
+${interpolateDependencies}@slurp
+  @end if
+
+// a_k = G[a_k, t + h/2]
+${callFunction('deltaA', arguments, parentFunction = function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""// a = a + a_k/3
+_${vector.id}[$index] += _akfield_${vector.id}[$index]/3.0;
+// a_k = a_i + a_k/2
+_akfield_${vector.id}[$index] = _aifield_${vector.id}[$index] + 0.5*_akfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+// a_k = G[a_k, t + h/2]
+${callFunction('deltaA', arguments, parentFunction = function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""// a = a + a_k/3
+_${vector.id}[$index] += _akfield_${vector.id}[$index]/3.0;
+// a_k = a_i + a_k
+_akfield_${vector.id}[$index] = _aifield_${vector.id}[$index] + _akfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+// a_k = D[a_k]
+${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction = function)}
+
+${propagationDimension} += 0.5*_step;
+  @if $cross
+
+${updateDependenciesForNextStep}@slurp
+  @end if
+
+// a_k = G[a_k, t + h]
+${callFunction('deltaA', arguments, parentFunction = function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _${vector.id};
+  @end for
+
+// a = D[a]
+${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction = function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors, 
+"""// a = a + a_k/6
+_${vector.id}[$index] += _akfield_${vector.id}[$index]/6.0;
+""", basis = $homeBasis)}@slurp
+  @#
+ at end def
+
+
+ at def interpolateDependencies
+  @#
+  @# Insert code to interpolate the dependency vectors onto the half-step point.
+  @# 
+// Create 4th order midpoint interpolation for dependencies
+if (_istep == 0) {
+  // We are at the first point
+  ${reducedFieldCopy($integrator.dependencyMap, 
+"""
+_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = \\
+    1.0/16.0*( 5.0*_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex}]
+            + 15.0*_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + ${skipSize} * _${vector.id}_ncomponents]
+            -  5.0*_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + 2 * ${skipSize} * _${vector.id}_ncomponents]
+            +      _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + 3 * ${skipSize} * _${vector.id}_ncomponents]);
+"""), autoIndent=True}@slurp
+} else if (_istep == (${integrator.stepCount} - 1)) {
+  // We are at the last point
+  ${reducedFieldCopy($integrator.dependencyMap, 
+"""
+_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = \\
+    1.0/16.0*(15.0*_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex}]
+            +  5.0*_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + ${skipSize} * _${vector.id}_ncomponents]
+            -  5.0*_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} - ${skipSize} * _${vector.id}_ncomponents]
+            +      _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} - 2 * ${skipSize} * _${vector.id}_ncomponents]);
+"""), autoIndent=True}@slurp
+} else {
+  // We are somewhere in the middle
+  ${reducedFieldCopy($integrator.dependencyMap, 
+"""
+_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = \\
+    9.0/16.0*(_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex}]
+            + _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + ${skipSize} * _${vector.id}_ncomponents])
+  - 1.0/16.0*(_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} - ${skipSize} * _${vector.id}_ncomponents]
+            + _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + 2 * ${skipSize} * _${vector.id}_ncomponents]);
+"""), autoIndent=True}@slurp
+}
+  @#
+ at end def
diff --git a/xpdeint/Segments/Integrators/RK89Stepper.py b/xpdeint/Segments/Integrators/RK89Stepper.py
new file mode 100644
index 0000000..3f54e56
--- /dev/null
+++ b/xpdeint/Segments/Integrators/RK89Stepper.py
@@ -0,0 +1,1238 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Segments.Integrators._Stepper import _Stepper
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.941313
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Segments/Integrators/RK89Stepper.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class RK89Stepper(_Stepper):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(RK89Stepper, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def name(self, **KWS):
+
+
+
+        ## Generated from @def name: RK89 at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''RK89''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def localInitialise(self, **KWS):
+
+
+        """
+        Initialise all of the Cash-Karp coefficients, etc.
+        """
+
+        ## CHEETAH: generated from @def localInitialise at line 40, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(RK89Stepper, self).localInitialise()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''
+// Runge Kutta method constants 
+real _a_raw[16];
+real _a[16];
+real _b[16][16];
+real _c[16];
+real _cs[16];
+real _d[16];
+
+for (unsigned long _i0 = 0; _i0 < 16; _i0++) {
+  _a_raw[_i0] = _c[_i0] = _d[_i0] = 0.0;
+  for (unsigned long _i1 = 0; _i1 < 16; _i1++)
+   _b[_i0][_i1] = 0.0;
+}
+
+_a_raw[1]  = 0.02173913043478260869565217391304347;
+_a_raw[2]  = 0.09629581047800066670113001679819925;
+_a_raw[3]  = 0.14444371571700100005169502519729888;
+_a_raw[4]  = 0.52205882352941176470588235294117647;
+_a_raw[5]  = 0.22842443612863469578031459099794265;
+_a_raw[6]  = 0.54360353589933733219171338103002937;
+_a_raw[7]  = 0.64335664335664335664335664335664335;
+_a_raw[8]  = 0.48251748251748251748251748251748251;
+_a_raw[9]  = 0.06818181818181818181818181818181818;
+_a_raw[10] = 0.25060827250608272506082725060827250;
+_a_raw[11] = 0.66736715965600568968278165443304378;
+_a_raw[12] = 0.85507246376811594202898550724637681;
+_a_raw[13] = 0.89795918367346938775510204081632653;
+_a_raw[14] = 1.0;
+_a_raw[15] = 1.0;
+
+_a[0] = 0.0;
+for (unsigned long _i0 = 1; _i0 < 16; _i0++)
+  _a[_i0] = _a_raw[_i0] - _a_raw[_i0 - 1];
+
+_b[1][0]   = 1.0/46.0;
+_b[2][0]   =-0.11698050118114486205818241524969622;
+_b[2][1]   = 0.21327631165914552875931243204789548;
+_b[3][0]   = 0.03611092892925025001292375629932472;
+_b[3][2]   = 0.10833278678775075003877126889797416;
+_b[4][0]   = 1.57329743908138605107331820072051125;
+_b[4][2]   =-5.98400943754042002888532938159655553;
+_b[4][3]   = 4.93277082198844574251789353381722074;
+_b[5][0]   = 0.05052046351120380909008334360006234;
+_b[5][3]   = 0.17686653884807108146683657390397612;
+_b[5][4]   = 0.00103743376935980522339467349390418;
+_b[6][0]   = 0.10543148021953768958529340893598138;
+_b[6][3]   =-0.16042415162569842979496486916719383;
+_b[6][4]   = 0.11643956912829316045688724281285250;
+_b[6][5]   = 0.48215663817720491194449759844838932;
+_b[7][0]   = 0.07148407148407148407148407148407148;
+_b[7][5]   = 0.32971116090443908023196389566296464;
+_b[7][6]   = 0.24216141096813279233990867620960722;
+_b[8][0]   = 0.07162368881118881118881118881118881;
+_b[8][5]   = 0.32859867301674234161492268975519694;
+_b[8][6]   = 0.11622213117906185418927311444060725;
+_b[8][7]   =-0.03392701048951048951048951048951048;
+_b[9][0]   = 0.04861540768024729180628870095388582;
+_b[9][5]   = 0.03998502200331629058445317782406268;
+_b[9][6]   = 0.10715724786209388876739304914053506;
+_b[9][7]   =-0.02177735985419485163815426357369818;
+_b[9][8]   =-0.10579849950964443770179884616296721;
+_b[10][0]  =-0.02540141041535143673515871979014924;
+_b[10][5]  = 1.0/30.0;
+_b[10][6]  =-0.16404854760069182073503553020238782;
+_b[10][7]  = 0.03410548898794737788891414566528526;
+_b[10][8]  = 0.15836825014108792658008718465091487;
+_b[10][9]  = 0.21425115805975734472868683695127609;
+_b[11][0]  = 0.00584833331460742801095934302256470;
+_b[11][5]  =-0.53954170547283522916525526480339109;
+_b[11][6]  = 0.20128430845560909506500331018201158;
+_b[11][7]  = 0.04347222773254789483240207937678906;
+_b[11][8]  =-0.00402998571475307250775349983910179;
+_b[11][9]  = 0.16541535721570612771420482097898952;
+_b[11][10] = 0.79491862412512344573322086551518180;
+_b[12][0]  =-0.39964965968794892497157706711861448;
+_b[12][5]  =-3.79096577568393158554742638116249372;
+_b[12][6]  =-0.40349325653530103387515807815498044;
+_b[12][7]  =-2.82463879530435263378049668286220715;
+_b[12][8]  = 1.04226892772185985533374283289821416;
+_b[12][9]  = 1.12510956420436603974237036536924078;
+_b[12][10] = 3.32746188718986816186934832571938138;
+_b[12][11] = 2.77897957186355606325818219255783627;
+_b[13][0]  = 0.39545306350085237157098218205756922;
+_b[13][5]  = 5.82534730759650564865380791881446903;
+_b[13][6]  =-0.36527452339161313311889856846974452;
+_b[13][7]  = 1.18860324058346533283780076203192232;
+_b[13][8]  = 0.57970467638357921347110271762687972;
+_b[13][9]  =-0.86824862589087693262676988867897834;
+_b[13][10] =-5.20227677296454721392873650976792184;
+_b[13][11] =-0.79895541420753382543211121058675915;
+_b[13][12] = 0.14360623206363792632792463778889008;
+_b[14][0]  = 8.49173149061346398013352206978380938;
+_b[14][5]  = 86.32213734729036800877634194386790750;
+_b[14][6]  = 1.02560575501091662034511526187393241;
+_b[14][7]  = 85.77427969817339941806831550695235092;
+_b[14][8]  =-13.98699305104110611795532466113248067;
+_b[14][9]  =-20.71537405501426352265946477613161883;
+_b[14][10] =-72.16597156619946800281180102605140463;
+_b[14][11] =-76.71211139107806345587696023064419687;
+_b[14][12] = 4.22319427707298828839851258893735507;
+_b[14][13] =-1.25649850482823521641825667745565428;
+_b[15][0]  =-0.42892119881959353241190195318730008;
+_b[15][5]  =-9.16865700950084689999297912545025359;
+_b[15][6]  = 1.08317616770620939241547721530003920;
+_b[15][7]  =-1.23501525358323653198215832293981810;
+_b[15][8]  =-1.21438272617593906232943856422371019;
+_b[15][9]  = 1.37226168507232166621351243731869914;
+_b[15][10] = 9.15723239697162418155377135344394113;
+_b[15][11] = 1.30616301842220047563298585480401671;
+_b[15][12] =-0.25285618808937955976690569433069974;
+_b[15][13] = 0.38099910799663987066763679926508552;
+
+_c[0]  = 0.01490902081978461022483617102382552;
+_c[7]  =-0.20408044692054151258349120934134791;
+_c[8]  = 0.22901438600570447264772469337066476;
+_c[9]  = 0.12800558251147375669208211573729202;
+_c[10] = 0.22380626846054143649770066956485937;
+_c[11] = 0.39553165293700054420552389156421651;
+_c[12] = 0.05416646758806981196568364538360743;
+_c[13] = 0.12691439652445903685643385312168037;
+_c[14] =-0.00052539244262118876455834655383035;
+_c[15] = 1.0/31.0;
+
+_cs[0]  = 0.00653047880643482012034413441159249;
+_cs[7]  =-2.31471038197461347517552506241529830;
+_cs[8]  = 0.43528227238866280799530900822377013;
+_cs[9]  = 0.14907947287101933118545845390618763;
+_cs[10] = 0.17905535442235532311850533252768020;
+_cs[11] = 2.53400872222767706921176214508820825;
+_cs[12] =-0.55430437423209112896721332268159015;
+_cs[13] = 0.56924788787870083224213506297615260;
+_cs[14] =-0.03644749690427461198884026816573513;
+_cs[15] = 1.0/31.0;
+
+_d[0] = 1.0-_b[15][5]/_b[14][5];
+_d[1] = _b[15][0]-_b[14][0]*_b[15][5]/_b[14][5];
+_d[2] = _b[15][5]/_b[14][5];
+_d[3] = _b[15][6]-_b[14][6]*_b[15][5]/_b[14][5];
+_d[4] = _b[15][7]-_b[14][7]*_b[15][5]/_b[14][5];
+_d[5] = _b[15][8]-_b[14][8]*_b[15][5]/_b[14][5];
+_d[6] = _b[15][9]-_b[14][9]*_b[15][5]/_b[14][5];
+_d[7] = _b[15][10]-_b[14][10]*_b[15][5]/_b[14][5];
+_d[8] = _b[15][11]-_b[14][11]*_b[15][5]/_b[14][5];
+_d[9] = _b[15][12]-_b[14][12]*_b[15][5]/_b[14][5];
+_d[10] = _b[15][13]-_b[14][13]*_b[15][5]/_b[14][5];
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def singleIntegrationStep(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def singleIntegrationStep($function) at line 199, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        arguments = {'_step': '_step'}
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 202, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 202, col 1.
+        write(u'''
+// Step 1
+
+''')
+        _v = VFFSL(SL,"copyVectors",False)(VFFSL(SL,"integrationVectors",True), '_akafield') # u"${copyVectors($integrationVectors, '_akafield')}" on line 206, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${copyVectors($integrationVectors, '_akafield')}")) # from line 206, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction=function)}" on line 208, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction=function)}")) # from line 208, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +1, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}" on line 211, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}")) # from line 211, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 212, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 212, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 214, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 215, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 215, col 9.
+            write(u''' = _akafield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 215, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 215, col 34.
+            write(u''';
+''')
+        write(u'''
+// a_k=G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 219, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 219, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +1, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}" on line 222, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}")) # from line 222, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 223, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 223, col 1.
+        write(u'''
+// Step 2
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 227, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 227, col 1.
+        write(u''' += _a[1] * _step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akbfield_${vector.id}[$index] = _${vector.id}[$index] + _b[1][0]*_akafield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akbfield_${vector.id}[$index] = _${vector.id}[$index] + _b[1][0]*_akafield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 229, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 233, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 234, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 234, col 9.
+            write(u''' = _akbfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 234, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 234, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 2, _arrayIndex = 1, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 2, _arrayIndex = 1, parentFunction=function)}" on line 237, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 2, _arrayIndex = 1, parentFunction=function)}")) # from line 237, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -2, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -2, parentFunction=function)}" on line 240, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -2, parentFunction=function)}")) # from line 240, col 1.
+        write(u'''
+
+// a_k=G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 243, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 243, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +2, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +2, parentFunction=function)}" on line 246, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +2, parentFunction=function)}")) # from line 246, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 247, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 247, col 1.
+        write(u'''
+// Step 3
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 251, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 251, col 1.
+        write(u''' += _a[2] * _step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akcfield_${vector.id}[$index] = _${vector.id}[$index] + _b[2][0]*_akafield_${vector.id}[$index] + _b[2][1]*_akbfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akcfield_${vector.id}[$index] = _${vector.id}[$index] + _b[2][0]*_akafield_${vector.id}[$index] + _b[2][1]*_akbfield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 253, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 257, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 258, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 258, col 9.
+            write(u''' = _akcfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 258, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 258, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 3, _arrayIndex = 1, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 3, _arrayIndex = 1, parentFunction=function)}" on line 261, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 3, _arrayIndex = 1, parentFunction=function)}")) # from line 261, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -3, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -3, parentFunction=function)}" on line 264, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -3, parentFunction=function)}")) # from line 264, col 1.
+        write(u'''
+
+// a_k=G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 267, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 267, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +3, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +3, parentFunction=function)}" on line 270, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +3, parentFunction=function)}")) # from line 270, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 271, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 271, col 1.
+        write(u'''
+// Step 4
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 275, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 275, col 1.
+        write(u''' += _a[3] * _step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akdfield_${vector.id}[$index] = _${vector.id}[$index] + _b[3][0]*_akafield_${vector.id}[$index] + _b[3][1]*_akbfield_${vector.id}[$index]
+    + _b[3][2]*_akcfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akdfield_${vector.id}[$index] = _${vector.id}[$index] + _b[3][0]*_akafield_${vector.id}[$index] + _b[3][1]*_akbfield_${vector.id}[$index]\n    + _b[3][2]*_akcfield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 277, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 282, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 283, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 283, col 9.
+            write(u''' = _akdfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 283, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 283, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 4, _arrayIndex = 1, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 4, _arrayIndex = 1, parentFunction=function)}" on line 286, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 4, _arrayIndex = 1, parentFunction=function)}")) # from line 286, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -4, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -4, parentFunction=function)}" on line 289, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -4, parentFunction=function)}")) # from line 289, col 1.
+        write(u'''
+
+// a_k=G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 292, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 292, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +4, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +4, parentFunction=function)}" on line 295, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +4, parentFunction=function)}")) # from line 295, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 296, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 296, col 1.
+        write(u'''
+// Step 5
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 300, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 300, col 1.
+        write(u''' += _a[4] * _step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akefield_${vector.id}[$index] = _${vector.id}[$index] + _b[4][0]*_akafield_${vector.id}[$index] + _b[4][1]*_akbfield_${vector.id}[$index]
+    + _b[4][2]*_akcfield_${vector.id}[$index] + _b[4][3]*_akdfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akefield_${vector.id}[$index] = _${vector.id}[$index] + _b[4][0]*_akafield_${vector.id}[$index] + _b[4][1]*_akbfield_${vector.id}[$index]\n    + _b[4][2]*_akcfield_${vector.id}[$index] + _b[4][3]*_akdfield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 302, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 307, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 308, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 308, col 9.
+            write(u''' = _akefield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 308, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 308, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 5, _arrayIndex = 1, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 5, _arrayIndex = 1, parentFunction=function)}" on line 311, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 5, _arrayIndex = 1, parentFunction=function)}")) # from line 311, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -5, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -5, parentFunction=function)}" on line 314, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -5, parentFunction=function)}")) # from line 314, col 1.
+        write(u'''
+
+// a_k=G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 317, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 317, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +5, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +5, parentFunction=function)}" on line 320, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +5, parentFunction=function)}")) # from line 320, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 321, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 321, col 1.
+        write(u'''
+// Step 6
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 325, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 325, col 1.
+        write(u''' += _a[5] * _step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akifield_${vector.id}[$index] = _${vector.id}[$index] + _b[5][0]*_akafield_${vector.id}[$index] + _b[5][3]*_akdfield_${vector.id}[$index]
+    + _b[5][4]*_akefield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akifield_${vector.id}[$index] = _${vector.id}[$index] + _b[5][0]*_akafield_${vector.id}[$index] + _b[5][3]*_akdfield_${vector.id}[$index]\n    + _b[5][4]*_akefield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 327, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 332, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 333, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 333, col 9.
+            write(u''' = _akifield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 333, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 333, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 6, _arrayIndex = 1, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 6, _arrayIndex = 1, parentFunction=function)}" on line 336, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 6, _arrayIndex = 1, parentFunction=function)}")) # from line 336, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -6, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -6, parentFunction=function)}" on line 339, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -6, parentFunction=function)}")) # from line 339, col 1.
+        write(u'''
+
+// a_k=G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 342, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 342, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +6, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +6, parentFunction=function)}" on line 345, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +6, parentFunction=function)}")) # from line 345, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 346, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 346, col 1.
+        write(u'''
+// Step 7
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 350, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 350, col 1.
+        write(u''' += _a[6] * _step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akjfield_${vector.id}[$index] = _${vector.id}[$index] + _b[6][0]*_akafield_${vector.id}[$index] + _b[6][3]*_akdfield_${vector.id}[$index]
+    + _b[6][4]*_akefield_${vector.id}[$index] + _b[6][5]*_akifield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akjfield_${vector.id}[$index] = _${vector.id}[$index] + _b[6][0]*_akafield_${vector.id}[$index] + _b[6][3]*_akdfield_${vector.id}[$index]\n    + _b[6][4]*_akefield_${vector.id}[$index] + _b[6][5]*_akifield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 352, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 357, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 358, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 358, col 9.
+            write(u''' = _akjfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 358, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 358, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 7, _arrayIndex = 1, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 7, _arrayIndex = 1, parentFunction=function)}" on line 361, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 7, _arrayIndex = 1, parentFunction=function)}")) # from line 361, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -7, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -7, parentFunction=function)}" on line 364, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -7, parentFunction=function)}")) # from line 364, col 1.
+        write(u'''
+
+// a_k=G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 367, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 367, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +7, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +7, parentFunction=function)}" on line 370, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +7, parentFunction=function)}")) # from line 370, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 371, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 371, col 1.
+        write(u'''
+// Step 8
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 375, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 375, col 1.
+        write(u''' += _a[7] * _step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akbfield_${vector.id}[$index] = _${vector.id}[$index] + _b[7][0]*_akafield_${vector.id}[$index] + _b[7][5]*_akifield_${vector.id}[$index]
+    + _b[7][6]*_akjfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akbfield_${vector.id}[$index] = _${vector.id}[$index] + _b[7][0]*_akafield_${vector.id}[$index] + _b[7][5]*_akifield_${vector.id}[$index]\n    + _b[7][6]*_akjfield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 377, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 382, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 383, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 383, col 9.
+            write(u''' = _akbfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 383, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 383, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 8, _arrayIndex = 1, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 8, _arrayIndex = 1, parentFunction=function)}" on line 386, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 8, _arrayIndex = 1, parentFunction=function)}")) # from line 386, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -8, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -8, parentFunction=function)}" on line 389, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -8, parentFunction=function)}")) # from line 389, col 1.
+        write(u'''
+
+// a_k=G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 392, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 392, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +8, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +8, parentFunction=function)}" on line 395, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +8, parentFunction=function)}")) # from line 395, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 396, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 396, col 1.
+        write(u'''
+// Step 9
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 400, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 400, col 1.
+        write(u''' += _a[8] * _step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akcfield_${vector.id}[$index] = _${vector.id}[$index] + _b[8][0]*_akafield_${vector.id}[$index] + _b[8][5]*_akifield_${vector.id}[$index]
+    + _b[8][6]*_akjfield_${vector.id}[$index]+ _b[8][7]*_akbfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akcfield_${vector.id}[$index] = _${vector.id}[$index] + _b[8][0]*_akafield_${vector.id}[$index] + _b[8][5]*_akifield_${vector.id}[$index]\n    + _b[8][6]*_akjfield_${vector.id}[$index]+ _b[8][7]*_akbfield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 402, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 407, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 408, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 408, col 9.
+            write(u''' = _akcfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 408, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 408, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 9, _arrayIndex = 1, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 9, _arrayIndex = 1, parentFunction=function)}" on line 411, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 9, _arrayIndex = 1, parentFunction=function)}")) # from line 411, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -9, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -9, parentFunction=function)}" on line 414, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -9, parentFunction=function)}")) # from line 414, col 1.
+        write(u'''
+
+// a_k=G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 417, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 417, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +9, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +9, parentFunction=function)}" on line 420, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +9, parentFunction=function)}")) # from line 420, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 421, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 421, col 1.
+        write(u'''
+// Step 10
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 425, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 425, col 1.
+        write(u''' += _a[9] * _step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akdfield_${vector.id}[$index] = _${vector.id}[$index] + _b[9][0]*_akafield_${vector.id}[$index] + _b[9][5]*_akifield_${vector.id}[$index]
+    + _b[9][6]*_akjfield_${vector.id}[$index]+ _b[9][7]*_akbfield_${vector.id}[$index]+ _b[9][8]*_akcfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akdfield_${vector.id}[$index] = _${vector.id}[$index] + _b[9][0]*_akafield_${vector.id}[$index] + _b[9][5]*_akifield_${vector.id}[$index]\n    + _b[9][6]*_akjfield_${vector.id}[$index]+ _b[9][7]*_akbfield_${vector.id}[$index]+ _b[9][8]*_akcfield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 427, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 432, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 433, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 433, col 9.
+            write(u''' = _akdfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 433, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 433, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 10, _arrayIndex = 1, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 10, _arrayIndex = 1, parentFunction=function)}" on line 436, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 10, _arrayIndex = 1, parentFunction=function)}")) # from line 436, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -10, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -10, parentFunction=function)}" on line 439, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -10, parentFunction=function)}")) # from line 439, col 1.
+        write(u'''
+
+// a_k=G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 442, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 442, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +10, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +10, parentFunction=function)}" on line 445, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +10, parentFunction=function)}")) # from line 445, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 446, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 446, col 1.
+        write(u'''
+// Step 11
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 450, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 450, col 1.
+        write(u''' += _a[10] * _step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akefield_${vector.id}[$index] = _${vector.id}[$index] + _b[10][0]*_akafield_${vector.id}[$index] + _b[10][5]*_akifield_${vector.id}[$index]
+    + _b[10][6]*_akjfield_${vector.id}[$index]+ _b[10][7]*_akbfield_${vector.id}[$index] + _b[10][8]*_akcfield_${vector.id}[$index]
+    + _b[10][9]*_akdfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akefield_${vector.id}[$index] = _${vector.id}[$index] + _b[10][0]*_akafield_${vector.id}[$index] + _b[10][5]*_akifield_${vector.id}[$index]\n    + _b[10][6]*_akjfield_${vector.id}[$index]+ _b[10][7]*_akbfield_${vector.id}[$index] + _b[10][8]*_akcfield_${vector.id}[$index]\n    + _b[10][9]*_akdfield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 452, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 458, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 459, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 459, col 9.
+            write(u''' = _akefield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 459, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 459, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 11, _arrayIndex = 1, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 11, _arrayIndex = 1, parentFunction=function)}" on line 462, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 11, _arrayIndex = 1, parentFunction=function)}")) # from line 462, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -11, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -11, parentFunction=function)}" on line 465, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -11, parentFunction=function)}")) # from line 465, col 1.
+        write(u'''
+
+// a_k=G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 468, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 468, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +11, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +11, parentFunction=function)}" on line 471, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +11, parentFunction=function)}")) # from line 471, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 472, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 472, col 1.
+        write(u'''
+// Step 12
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 476, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 476, col 1.
+        write(u''' += _a[11] * _step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akffield_${vector.id}[$index] = _${vector.id}[$index] + _b[11][0]*_akafield_${vector.id}[$index] + _b[11][5]*_akifield_${vector.id}[$index]
+    + _b[11][6]*_akjfield_${vector.id}[$index] + _b[11][7]*_akbfield_${vector.id}[$index] + _b[11][8]*_akcfield_${vector.id}[$index]
+    + _b[11][9]*_akdfield_${vector.id}[$index] + _b[11][10]*_akefield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akffield_${vector.id}[$index] = _${vector.id}[$index] + _b[11][0]*_akafield_${vector.id}[$index] + _b[11][5]*_akifield_${vector.id}[$index]\n    + _b[11][6]*_akjfield_${vector.id}[$index] + _b[11][7]*_akbfield_${vector.id}[$index] + _b[11][8]*_akcfield_${vector.id}[$index]\n    + _b[11][9]*_akdfield_${vector.id}[$index] + _b[11][10]*_akefield_${vector.id}[$index];\n" [...]
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 484, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 485, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 485, col 9.
+            write(u''' = _akffield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 485, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 485, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 12, _arrayIndex = 1, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 12, _arrayIndex = 1, parentFunction=function)}" on line 488, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 12, _arrayIndex = 1, parentFunction=function)}")) # from line 488, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -12, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -12, parentFunction=function)}" on line 491, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -12, parentFunction=function)}")) # from line 491, col 1.
+        write(u'''
+
+// a_k=G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 494, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 494, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +12, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +12, parentFunction=function)}" on line 497, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +12, parentFunction=function)}")) # from line 497, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 498, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 498, col 1.
+        write(u'''
+// Step 13
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 502, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 502, col 1.
+        write(u''' += _a[12] * _step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akgfield_${vector.id}[$index] = _${vector.id}[$index] + _b[12][0]*_akafield_${vector.id}[$index] + _b[12][5]*_akifield_${vector.id}[$index]
+    + _b[12][6]*_akjfield_${vector.id}[$index]+ _b[12][7]*_akbfield_${vector.id}[$index] + _b[12][8]*_akcfield_${vector.id}[$index]
+    + _b[12][9]*_akdfield_${vector.id}[$index] + _b[12][10]*_akefield_${vector.id}[$index] + _b[12][11]*_akffield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akgfield_${vector.id}[$index] = _${vector.id}[$index] + _b[12][0]*_akafield_${vector.id}[$index] + _b[12][5]*_akifield_${vector.id}[$index]\n    + _b[12][6]*_akjfield_${vector.id}[$index]+ _b[12][7]*_akbfield_${vector.id}[$index] + _b[12][8]*_akcfield_${vector.id}[$index]\n    + _b[12][9]*_akdfield_${vector.id}[$index] + _b[12][10]*_akefield_${vector.id}[$index] + _b [...]
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 510, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 511, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 511, col 9.
+            write(u''' = _akgfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 511, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 511, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 13, _arrayIndex = 1, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 13, _arrayIndex = 1, parentFunction=function)}" on line 514, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 13, _arrayIndex = 1, parentFunction=function)}")) # from line 514, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -13, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -13, parentFunction=function)}" on line 517, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -13, parentFunction=function)}")) # from line 517, col 1.
+        write(u'''
+
+// a_k=G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 520, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 520, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +13, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +13, parentFunction=function)}" on line 523, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +13, parentFunction=function)}")) # from line 523, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 524, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 524, col 1.
+        write(u'''
+// Step 14
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 528, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 528, col 1.
+        write(u''' += _a[13] * _step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akhfield_${vector.id}[$index] = _${vector.id}[$index] + _b[13][0]*_akafield_${vector.id}[$index] + _b[13][5]*_akifield_${vector.id}[$index]
+    + _b[13][6]*_akjfield_${vector.id}[$index]+ _b[13][7]*_akbfield_${vector.id}[$index] + _b[13][8]*_akcfield_${vector.id}[$index]
+    + _b[13][9]*_akdfield_${vector.id}[$index] + _b[13][10]*_akefield_${vector.id}[$index] + _b[13][11]*_akffield_${vector.id}[$index]
+    + _b[13][12]*_akgfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akhfield_${vector.id}[$index] = _${vector.id}[$index] + _b[13][0]*_akafield_${vector.id}[$index] + _b[13][5]*_akifield_${vector.id}[$index]\n    + _b[13][6]*_akjfield_${vector.id}[$index]+ _b[13][7]*_akbfield_${vector.id}[$index] + _b[13][8]*_akcfield_${vector.id}[$index]\n    + _b[13][9]*_akdfield_${vector.id}[$index] + _b[13][10]*_akefield_${vector.id}[$index] + _b [...]
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 537, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 538, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 538, col 9.
+            write(u''' = _akhfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 538, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 538, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 14, _arrayIndex = 1, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 14, _arrayIndex = 1, parentFunction=function)}" on line 541, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 14, _arrayIndex = 1, parentFunction=function)}")) # from line 541, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -14, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -14, parentFunction=function)}" on line 544, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -14, parentFunction=function)}")) # from line 544, col 1.
+        write(u'''
+
+// a_k=G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 547, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 547, col 1.
+        write(u'''
+
+// a_i=D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +14, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +14, parentFunction=function)}" on line 550, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +14, parentFunction=function)}")) # from line 550, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 551, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 551, col 1.
+        write(u'''
+// Step 15 and 16 combined to reduce memory use 
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akifield_${vector.id}[$index] = _${vector.id}[$index] + _b[14][0]*_akafield_${vector.id}[$index] + _b[14][5]*_akifield_${vector.id}[$index]
+    + _b[14][6]*_akjfield_${vector.id}[$index]+ _b[14][7]*_akbfield_${vector.id}[$index] + _b[14][8]*_akcfield_${vector.id}[$index]
+    + _b[14][9]*_akdfield_${vector.id}[$index] + _b[14][10]*_akefield_${vector.id}[$index] + _b[14][11]*_akffield_${vector.id}[$index]
+    + _b[14][12]*_akgfield_${vector.id}[$index] + _b[14][13]*_akhfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akifield_${vector.id}[$index] = _${vector.id}[$index] + _b[14][0]*_akafield_${vector.id}[$index] + _b[14][5]*_akifield_${vector.id}[$index]\n    + _b[14][6]*_akjfield_${vector.id}[$index]+ _b[14][7]*_akbfield_${vector.id}[$index] + _b[14][8]*_akcfield_${vector.id}[$index]\n    + _b[14][9]*_akdfield_${vector.id}[$index] + _b[14][10]*_akefield_${vector.id}[$index] + _b [...]
+        write(u'''
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akjfield_${vector.id}[$index] = _d[0]*_${vector.id}[$index]
+      + _d[1]*_akafield_${vector.id}[$index]
+      + _d[2]*_akifield_${vector.id}[$index]
+      + _d[3]*_akjfield_${vector.id}[$index]
+      + _d[4]*_akbfield_${vector.id}[$index]
+      + _d[5]*_akcfield_${vector.id}[$index]
+      + _d[6]*_akdfield_${vector.id}[$index]
+      + _d[7]*_akefield_${vector.id}[$index]
+      + _d[8]*_akffield_${vector.id}[$index]
+      + _d[9]*_akgfield_${vector.id}[$index]
+      + _d[10]*_akhfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akjfield_${vector.id}[$index] = _d[0]*_${vector.id}[$index]\n      + _d[1]*_akafield_${vector.id}[$index]\n      + _d[2]*_akifield_${vector.id}[$index]\n      + _d[3]*_akjfield_${vector.id}[$index]\n      + _d[4]*_akbfield_${vector.id}[$index]\n      + _d[5]*_akcfield_${vector.id}[$index]\n      + _d[6]*_akdfield_${vector.id}[$index]\n      + _d[7]*_akefield_${vector [...]
+        write(u'''
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 576, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 576, col 1.
+        write(u''' += _a[14] * _step;
+
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 578, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 579, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 579, col 9.
+            write(u''' = _akifield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 579, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 579, col 34.
+            write(u''';
+''')
+        write(u'''
+// a_k=G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 583, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 583, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 584, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 584, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 586, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 586, col 1.
+        write(u''' += _a[15] * _step;
+
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 588, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 589, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 589, col 9.
+            write(u''' = _akjfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 589, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 589, col 34.
+            write(u''';
+''')
+        write(u'''
+// a_k=G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 593, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 593, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 594, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 594, col 1.
+        write(u'''
+// Take full step
+
+// ai = a
+''')
+        _v = VFFSL(SL,"copyVectors",False)(VFFSL(SL,"integrationVectors",True), '_initial') # u"${copyVectors($integrationVectors, '_initial')}" on line 599, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${copyVectors($integrationVectors, '_initial')}")) # from line 599, col 1.
+        write(u'''
+// a = a + etc
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_${vector.id}[$index] += _c[0]*_akafield_${vector.id}[$index] + _c[7]*_akbfield_${vector.id}[$index] + _c[8]*_akcfield_${vector.id}[$index]
+    + _c[9]*_akdfield_${vector.id}[$index] + _c[10]*_akefield_${vector.id}[$index] + _c[11]*_akffield_${vector.id}[$index]
+    + _c[12]*_akgfield_${vector.id}[$index] + _c[13]*_akhfield_${vector.id}[$index] + _c[14]*_akifield_${vector.id}[$index]
+    + _c[15]*_akjfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_${vector.id}[$index] += _c[0]*_akafield_${vector.id}[$index] + _c[7]*_akbfield_${vector.id}[$index] + _c[8]*_akcfield_${vector.id}[$index]\n    + _c[9]*_akdfield_${vector.id}[$index] + _c[10]*_akefield_${vector.id}[$index] + _c[11]*_akffield_${vector.id}[$index]\n    + _c[12]*_akgfield_${vector.id}[$index] + _c[13]*_akhfield_${vector.id}[$index] + _c[14]*_akifield_${ [...]
+        write(u'''
+// a* = a + etc
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akafield_${vector.id}[$index] = _initial_${vector.id}[$index] + _cs[0]*_akafield_${vector.id}[$index] + _cs[7]*_akbfield_${vector.id}[$index]
+    + _cs[8]*_akcfield_${vector.id}[$index] + _cs[9]*_akdfield_${vector.id}[$index] + _cs[10]*_akefield_${vector.id}[$index]
+    + _cs[11]*_akffield_${vector.id}[$index] + _cs[12]*_akgfield_${vector.id}[$index] + _cs[13]*_akhfield_${vector.id}[$index]
+    + _cs[14]*_akifield_${vector.id}[$index] + _cs[15]*_akjfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akafield_${vector.id}[$index] = _initial_${vector.id}[$index] + _cs[0]*_akafield_${vector.id}[$index] + _cs[7]*_akbfield_${vector.id}[$index]\n    + _cs[8]*_akcfield_${vector.id}[$index] + _cs[9]*_akdfield_${vector.id}[$index] + _cs[10]*_akefield_${vector.id}[$index]\n    + _cs[11]*_akffield_${vector.id}[$index] + _cs[12]*_akgfield_${vector.id}[$index] + _cs[13]*_akh [...]
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 617, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 618, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 618, col 9.
+            write(u''' = _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 618, col 25
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 618, col 25.
+            write(u''';
+''')
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # RK89Stepper.tmpl
+        # 
+        # Created by Graham Dennis on 2008-02-11.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+''')
+        # 
+        #   Single integration step (ARK89)
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    ipPropagationStepFractions =   [ '1.000000000000000', '0.978260869565217', '0.903704189521999', '0.855556284282999',    '0.477941176470588', '0.771575563871365', '0.456396464100663', '0.356643356643357',    '0.517482517482518', '0.931818181818182', '0.749391727493917', '0.332632840343994',    '0.144927536231884', '0.102040816326531' ]
+
+    nonconstantIPFields = 2
+
+    extraIntegrationArrayNames =   [ 'akafield', 'akbfield', 'akcfield', 'akdfield', 'akefield', 'akffield', 'akgfield',    'akhfield', 'akifield', 'akjfield', 'initial']
+
+    errorFieldName = 'akafield'
+
+    resetFieldName = 'initial'
+
+    integrationOrder = 9.0
+
+    _mainCheetahMethod_for_RK89Stepper= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(RK89Stepper, '_initCheetahAttributes'):
+    templateAPIClass = getattr(RK89Stepper, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(RK89Stepper)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=RK89Stepper()).run()
+
+
diff --git a/xpdeint/Segments/Integrators/RK89Stepper.tmpl b/xpdeint/Segments/Integrators/RK89Stepper.tmpl
new file mode 100644
index 0000000..9bcebfc
--- /dev/null
+++ b/xpdeint/Segments/Integrators/RK89Stepper.tmpl
@@ -0,0 +1,622 @@
+@*
+RK89Stepper.tmpl
+
+Created by Graham Dennis on 2008-02-11.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Segments.Integrators._Stepper
+
+ at def name: RK89
+ at attr $ipPropagationStepFractions = \
+  [ '1.000000000000000', '0.978260869565217', '0.903704189521999', '0.855556284282999',
+    '0.477941176470588', '0.771575563871365', '0.456396464100663', '0.356643356643357',
+    '0.517482517482518', '0.931818181818182', '0.749391727493917', '0.332632840343994',
+    '0.144927536231884', '0.102040816326531' ]
+ at attr $nonconstantIPFields = 2
+ at attr $extraIntegrationArrayNames = \
+  [ 'akafield', 'akbfield', 'akcfield', 'akdfield', 'akefield', 'akffield', 'akgfield',
+    'akhfield', 'akifield', 'akjfield', 'initial']
+
+ at attr $errorFieldName = 'akafield'
+ at attr $resetFieldName = 'initial'
+
+ at attr $integrationOrder = 9.0
+
+ at def localInitialise
+@*doc:
+Initialise all of the Cash-Karp coefficients, etc.
+*@
+  @#
+  @super
+  @#
+
+// Runge Kutta method constants 
+real _a_raw[16];
+real _a[16];
+real _b[16][16];
+real _c[16];
+real _cs[16];
+real _d[16];
+
+for (unsigned long _i0 = 0; _i0 < 16; _i0++) {
+  _a_raw[_i0] = _c[_i0] = _d[_i0] = 0.0;
+  for (unsigned long _i1 = 0; _i1 < 16; _i1++)
+   _b[_i0][_i1] = 0.0;
+}
+
+_a_raw[1]  = 0.02173913043478260869565217391304347;
+_a_raw[2]  = 0.09629581047800066670113001679819925;
+_a_raw[3]  = 0.14444371571700100005169502519729888;
+_a_raw[4]  = 0.52205882352941176470588235294117647;
+_a_raw[5]  = 0.22842443612863469578031459099794265;
+_a_raw[6]  = 0.54360353589933733219171338103002937;
+_a_raw[7]  = 0.64335664335664335664335664335664335;
+_a_raw[8]  = 0.48251748251748251748251748251748251;
+_a_raw[9]  = 0.06818181818181818181818181818181818;
+_a_raw[10] = 0.25060827250608272506082725060827250;
+_a_raw[11] = 0.66736715965600568968278165443304378;
+_a_raw[12] = 0.85507246376811594202898550724637681;
+_a_raw[13] = 0.89795918367346938775510204081632653;
+_a_raw[14] = 1.0;
+_a_raw[15] = 1.0;
+
+_a[0] = 0.0;
+for (unsigned long _i0 = 1; _i0 < 16; _i0++)
+  _a[_i0] = _a_raw[_i0] - _a_raw[_i0 - 1];
+
+_b[1][0]   = 1.0/46.0;
+_b[2][0]   =-0.11698050118114486205818241524969622;
+_b[2][1]   = 0.21327631165914552875931243204789548;
+_b[3][0]   = 0.03611092892925025001292375629932472;
+_b[3][2]   = 0.10833278678775075003877126889797416;
+_b[4][0]   = 1.57329743908138605107331820072051125;
+_b[4][2]   =-5.98400943754042002888532938159655553;
+_b[4][3]   = 4.93277082198844574251789353381722074;
+_b[5][0]   = 0.05052046351120380909008334360006234;
+_b[5][3]   = 0.17686653884807108146683657390397612;
+_b[5][4]   = 0.00103743376935980522339467349390418;
+_b[6][0]   = 0.10543148021953768958529340893598138;
+_b[6][3]   =-0.16042415162569842979496486916719383;
+_b[6][4]   = 0.11643956912829316045688724281285250;
+_b[6][5]   = 0.48215663817720491194449759844838932;
+_b[7][0]   = 0.07148407148407148407148407148407148;
+_b[7][5]   = 0.32971116090443908023196389566296464;
+_b[7][6]   = 0.24216141096813279233990867620960722;
+_b[8][0]   = 0.07162368881118881118881118881118881;
+_b[8][5]   = 0.32859867301674234161492268975519694;
+_b[8][6]   = 0.11622213117906185418927311444060725;
+_b[8][7]   =-0.03392701048951048951048951048951048;
+_b[9][0]   = 0.04861540768024729180628870095388582;
+_b[9][5]   = 0.03998502200331629058445317782406268;
+_b[9][6]   = 0.10715724786209388876739304914053506;
+_b[9][7]   =-0.02177735985419485163815426357369818;
+_b[9][8]   =-0.10579849950964443770179884616296721;
+_b[10][0]  =-0.02540141041535143673515871979014924;
+_b[10][5]  = 1.0/30.0;
+_b[10][6]  =-0.16404854760069182073503553020238782;
+_b[10][7]  = 0.03410548898794737788891414566528526;
+_b[10][8]  = 0.15836825014108792658008718465091487;
+_b[10][9]  = 0.21425115805975734472868683695127609;
+_b[11][0]  = 0.00584833331460742801095934302256470;
+_b[11][5]  =-0.53954170547283522916525526480339109;
+_b[11][6]  = 0.20128430845560909506500331018201158;
+_b[11][7]  = 0.04347222773254789483240207937678906;
+_b[11][8]  =-0.00402998571475307250775349983910179;
+_b[11][9]  = 0.16541535721570612771420482097898952;
+_b[11][10] = 0.79491862412512344573322086551518180;
+_b[12][0]  =-0.39964965968794892497157706711861448;
+_b[12][5]  =-3.79096577568393158554742638116249372;
+_b[12][6]  =-0.40349325653530103387515807815498044;
+_b[12][7]  =-2.82463879530435263378049668286220715;
+_b[12][8]  = 1.04226892772185985533374283289821416;
+_b[12][9]  = 1.12510956420436603974237036536924078;
+_b[12][10] = 3.32746188718986816186934832571938138;
+_b[12][11] = 2.77897957186355606325818219255783627;
+_b[13][0]  = 0.39545306350085237157098218205756922;
+_b[13][5]  = 5.82534730759650564865380791881446903;
+_b[13][6]  =-0.36527452339161313311889856846974452;
+_b[13][7]  = 1.18860324058346533283780076203192232;
+_b[13][8]  = 0.57970467638357921347110271762687972;
+_b[13][9]  =-0.86824862589087693262676988867897834;
+_b[13][10] =-5.20227677296454721392873650976792184;
+_b[13][11] =-0.79895541420753382543211121058675915;
+_b[13][12] = 0.14360623206363792632792463778889008;
+_b[14][0]  = 8.49173149061346398013352206978380938;
+_b[14][5]  = 86.32213734729036800877634194386790750;
+_b[14][6]  = 1.02560575501091662034511526187393241;
+_b[14][7]  = 85.77427969817339941806831550695235092;
+_b[14][8]  =-13.98699305104110611795532466113248067;
+_b[14][9]  =-20.71537405501426352265946477613161883;
+_b[14][10] =-72.16597156619946800281180102605140463;
+_b[14][11] =-76.71211139107806345587696023064419687;
+_b[14][12] = 4.22319427707298828839851258893735507;
+_b[14][13] =-1.25649850482823521641825667745565428;
+_b[15][0]  =-0.42892119881959353241190195318730008;
+_b[15][5]  =-9.16865700950084689999297912545025359;
+_b[15][6]  = 1.08317616770620939241547721530003920;
+_b[15][7]  =-1.23501525358323653198215832293981810;
+_b[15][8]  =-1.21438272617593906232943856422371019;
+_b[15][9]  = 1.37226168507232166621351243731869914;
+_b[15][10] = 9.15723239697162418155377135344394113;
+_b[15][11] = 1.30616301842220047563298585480401671;
+_b[15][12] =-0.25285618808937955976690569433069974;
+_b[15][13] = 0.38099910799663987066763679926508552;
+
+_c[0]  = 0.01490902081978461022483617102382552;
+_c[7]  =-0.20408044692054151258349120934134791;
+_c[8]  = 0.22901438600570447264772469337066476;
+_c[9]  = 0.12800558251147375669208211573729202;
+_c[10] = 0.22380626846054143649770066956485937;
+_c[11] = 0.39553165293700054420552389156421651;
+_c[12] = 0.05416646758806981196568364538360743;
+_c[13] = 0.12691439652445903685643385312168037;
+_c[14] =-0.00052539244262118876455834655383035;
+_c[15] = 1.0/31.0;
+
+_cs[0]  = 0.00653047880643482012034413441159249;
+_cs[7]  =-2.31471038197461347517552506241529830;
+_cs[8]  = 0.43528227238866280799530900822377013;
+_cs[9]  = 0.14907947287101933118545845390618763;
+_cs[10] = 0.17905535442235532311850533252768020;
+_cs[11] = 2.53400872222767706921176214508820825;
+_cs[12] =-0.55430437423209112896721332268159015;
+_cs[13] = 0.56924788787870083224213506297615260;
+_cs[14] =-0.03644749690427461198884026816573513;
+_cs[15] = 1.0/31.0;
+
+_d[0] = 1.0-_b[15][5]/_b[14][5];
+_d[1] = _b[15][0]-_b[14][0]*_b[15][5]/_b[14][5];
+_d[2] = _b[15][5]/_b[14][5];
+_d[3] = _b[15][6]-_b[14][6]*_b[15][5]/_b[14][5];
+_d[4] = _b[15][7]-_b[14][7]*_b[15][5]/_b[14][5];
+_d[5] = _b[15][8]-_b[14][8]*_b[15][5]/_b[14][5];
+_d[6] = _b[15][9]-_b[14][9]*_b[15][5]/_b[14][5];
+_d[7] = _b[15][10]-_b[14][10]*_b[15][5]/_b[14][5];
+_d[8] = _b[15][11]-_b[14][11]*_b[15][5]/_b[14][5];
+_d[9] = _b[15][12]-_b[14][12]*_b[15][5]/_b[14][5];
+_d[10] = _b[15][13]-_b[14][13]*_b[15][5]/_b[14][5];
+  @#
+ at end def
+
+@*
+  Single integration step (ARK89)
+*@
+ at def singleIntegrationStep($function)
+  @#
+  @set $arguments = {'_step': '_step'}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 1
+
+${copyVectors($integrationVectors, '_akafield')}@slurp
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akafield_${vector.id};
+  @end for
+
+// a_k=G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 2
+
+${propagationDimension} += _a[1] * _step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akbfield_${vector.id}[$index] = _${vector.id}[$index] + _b[1][0]*_akafield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akbfield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 2, _arrayIndex = 1, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -2, parentFunction=function)}
+
+// a_k=G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +2, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 3
+
+${propagationDimension} += _a[2] * _step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akcfield_${vector.id}[$index] = _${vector.id}[$index] + _b[2][0]*_akafield_${vector.id}[$index] + _b[2][1]*_akbfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akcfield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 3, _arrayIndex = 1, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -3, parentFunction=function)}
+
+// a_k=G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +3, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 4
+
+${propagationDimension} += _a[3] * _step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akdfield_${vector.id}[$index] = _${vector.id}[$index] + _b[3][0]*_akafield_${vector.id}[$index] + _b[3][1]*_akbfield_${vector.id}[$index]
+    + _b[3][2]*_akcfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akdfield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 4, _arrayIndex = 1, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -4, parentFunction=function)}
+
+// a_k=G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +4, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 5
+
+${propagationDimension} += _a[4] * _step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akefield_${vector.id}[$index] = _${vector.id}[$index] + _b[4][0]*_akafield_${vector.id}[$index] + _b[4][1]*_akbfield_${vector.id}[$index]
+    + _b[4][2]*_akcfield_${vector.id}[$index] + _b[4][3]*_akdfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akefield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 5, _arrayIndex = 1, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -5, parentFunction=function)}
+
+// a_k=G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +5, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 6
+
+${propagationDimension} += _a[5] * _step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akifield_${vector.id}[$index] = _${vector.id}[$index] + _b[5][0]*_akafield_${vector.id}[$index] + _b[5][3]*_akdfield_${vector.id}[$index]
+    + _b[5][4]*_akefield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akifield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 6, _arrayIndex = 1, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -6, parentFunction=function)}
+
+// a_k=G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +6, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 7
+
+${propagationDimension} += _a[6] * _step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akjfield_${vector.id}[$index] = _${vector.id}[$index] + _b[6][0]*_akafield_${vector.id}[$index] + _b[6][3]*_akdfield_${vector.id}[$index]
+    + _b[6][4]*_akefield_${vector.id}[$index] + _b[6][5]*_akifield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akjfield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 7, _arrayIndex = 1, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -7, parentFunction=function)}
+
+// a_k=G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +7, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 8
+
+${propagationDimension} += _a[7] * _step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akbfield_${vector.id}[$index] = _${vector.id}[$index] + _b[7][0]*_akafield_${vector.id}[$index] + _b[7][5]*_akifield_${vector.id}[$index]
+    + _b[7][6]*_akjfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akbfield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 8, _arrayIndex = 1, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -8, parentFunction=function)}
+
+// a_k=G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +8, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 9
+
+${propagationDimension} += _a[8] * _step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akcfield_${vector.id}[$index] = _${vector.id}[$index] + _b[8][0]*_akafield_${vector.id}[$index] + _b[8][5]*_akifield_${vector.id}[$index]
+    + _b[8][6]*_akjfield_${vector.id}[$index]+ _b[8][7]*_akbfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akcfield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 9, _arrayIndex = 1, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -9, parentFunction=function)}
+
+// a_k=G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +9, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 10
+
+${propagationDimension} += _a[9] * _step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akdfield_${vector.id}[$index] = _${vector.id}[$index] + _b[9][0]*_akafield_${vector.id}[$index] + _b[9][5]*_akifield_${vector.id}[$index]
+    + _b[9][6]*_akjfield_${vector.id}[$index]+ _b[9][7]*_akbfield_${vector.id}[$index]+ _b[9][8]*_akcfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akdfield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 10, _arrayIndex = 1, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -10, parentFunction=function)}
+
+// a_k=G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +10, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 11
+
+${propagationDimension} += _a[10] * _step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akefield_${vector.id}[$index] = _${vector.id}[$index] + _b[10][0]*_akafield_${vector.id}[$index] + _b[10][5]*_akifield_${vector.id}[$index]
+    + _b[10][6]*_akjfield_${vector.id}[$index]+ _b[10][7]*_akbfield_${vector.id}[$index] + _b[10][8]*_akcfield_${vector.id}[$index]
+    + _b[10][9]*_akdfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akefield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 11, _arrayIndex = 1, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -11, parentFunction=function)}
+
+// a_k=G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +11, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 12
+
+${propagationDimension} += _a[11] * _step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akffield_${vector.id}[$index] = _${vector.id}[$index] + _b[11][0]*_akafield_${vector.id}[$index] + _b[11][5]*_akifield_${vector.id}[$index]
+    + _b[11][6]*_akjfield_${vector.id}[$index] + _b[11][7]*_akbfield_${vector.id}[$index] + _b[11][8]*_akcfield_${vector.id}[$index]
+    + _b[11][9]*_akdfield_${vector.id}[$index] + _b[11][10]*_akefield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akffield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 12, _arrayIndex = 1, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -12, parentFunction=function)}
+
+// a_k=G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +12, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 13
+
+${propagationDimension} += _a[12] * _step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akgfield_${vector.id}[$index] = _${vector.id}[$index] + _b[12][0]*_akafield_${vector.id}[$index] + _b[12][5]*_akifield_${vector.id}[$index]
+    + _b[12][6]*_akjfield_${vector.id}[$index]+ _b[12][7]*_akbfield_${vector.id}[$index] + _b[12][8]*_akcfield_${vector.id}[$index]
+    + _b[12][9]*_akdfield_${vector.id}[$index] + _b[12][10]*_akefield_${vector.id}[$index] + _b[12][11]*_akffield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akgfield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 13, _arrayIndex = 1, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -13, parentFunction=function)}
+
+// a_k=G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +13, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 14
+
+${propagationDimension} += _a[13] * _step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akhfield_${vector.id}[$index] = _${vector.id}[$index] + _b[13][0]*_akafield_${vector.id}[$index] + _b[13][5]*_akifield_${vector.id}[$index]
+    + _b[13][6]*_akjfield_${vector.id}[$index]+ _b[13][7]*_akbfield_${vector.id}[$index] + _b[13][8]*_akcfield_${vector.id}[$index]
+    + _b[13][9]*_akdfield_${vector.id}[$index] + _b[13][10]*_akefield_${vector.id}[$index] + _b[13][11]*_akffield_${vector.id}[$index]
+    + _b[13][12]*_akgfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akhfield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 14, _arrayIndex = 1, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -14, parentFunction=function)}
+
+// a_k=G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i=D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +14, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 15 and 16 combined to reduce memory use 
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akifield_${vector.id}[$index] = _${vector.id}[$index] + _b[14][0]*_akafield_${vector.id}[$index] + _b[14][5]*_akifield_${vector.id}[$index]
+    + _b[14][6]*_akjfield_${vector.id}[$index]+ _b[14][7]*_akbfield_${vector.id}[$index] + _b[14][8]*_akcfield_${vector.id}[$index]
+    + _b[14][9]*_akdfield_${vector.id}[$index] + _b[14][10]*_akefield_${vector.id}[$index] + _b[14][11]*_akffield_${vector.id}[$index]
+    + _b[14][12]*_akgfield_${vector.id}[$index] + _b[14][13]*_akhfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akjfield_${vector.id}[$index] = _d[0]*_${vector.id}[$index]
+      + _d[1]*_akafield_${vector.id}[$index]
+      + _d[2]*_akifield_${vector.id}[$index]
+      + _d[3]*_akjfield_${vector.id}[$index]
+      + _d[4]*_akbfield_${vector.id}[$index]
+      + _d[5]*_akcfield_${vector.id}[$index]
+      + _d[6]*_akdfield_${vector.id}[$index]
+      + _d[7]*_akefield_${vector.id}[$index]
+      + _d[8]*_akffield_${vector.id}[$index]
+      + _d[9]*_akgfield_${vector.id}[$index]
+      + _d[10]*_akhfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+${propagationDimension} += _a[14] * _step;
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akifield_${vector.id};
+  @end for
+
+// a_k=G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+${propagationDimension} += _a[15] * _step;
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akjfield_${vector.id};
+  @end for
+
+// a_k=G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Take full step
+
+// ai = a
+${copyVectors($integrationVectors, '_initial')}@slurp
+
+// a = a + etc
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_${vector.id}[$index] += _c[0]*_akafield_${vector.id}[$index] + _c[7]*_akbfield_${vector.id}[$index] + _c[8]*_akcfield_${vector.id}[$index]
+    + _c[9]*_akdfield_${vector.id}[$index] + _c[10]*_akefield_${vector.id}[$index] + _c[11]*_akffield_${vector.id}[$index]
+    + _c[12]*_akgfield_${vector.id}[$index] + _c[13]*_akhfield_${vector.id}[$index] + _c[14]*_akifield_${vector.id}[$index]
+    + _c[15]*_akjfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+// a* = a + etc
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akafield_${vector.id}[$index] = _initial_${vector.id}[$index] + _cs[0]*_akafield_${vector.id}[$index] + _cs[7]*_akbfield_${vector.id}[$index]
+    + _cs[8]*_akcfield_${vector.id}[$index] + _cs[9]*_akdfield_${vector.id}[$index] + _cs[10]*_akefield_${vector.id}[$index]
+    + _cs[11]*_akffield_${vector.id}[$index] + _cs[12]*_akgfield_${vector.id}[$index] + _cs[13]*_akhfield_${vector.id}[$index]
+    + _cs[14]*_akifield_${vector.id}[$index] + _cs[15]*_akjfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _${vector.id};
+  @end for
+
+  @#
+ at end def
diff --git a/xpdeint/Segments/Integrators/RK9Stepper.py b/xpdeint/Segments/Integrators/RK9Stepper.py
new file mode 100644
index 0000000..23b02b0
--- /dev/null
+++ b/xpdeint/Segments/Integrators/RK9Stepper.py
@@ -0,0 +1,1222 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Segments.Integrators._Stepper import _Stepper
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.082027
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Segments/Integrators/RK9Stepper.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class RK9Stepper(_Stepper):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(RK9Stepper, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def name(self, **KWS):
+
+
+
+        ## Generated from @def name: RK9 at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''RK9''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def localInitialise(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def localInitialise at line 38, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(RK9Stepper, self).localInitialise()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''
+// Runge Kutta method constants
+real _a_raw[16];
+real _a[16];
+real _b[16][16];
+real _c[16];
+real _d[16];
+
+for(unsigned long _i0=0; _i0 < 16; _i0++)
+{
+  _a_raw[_i0] = _c[_i0] = _d[_i0] = 0.0;
+  for(unsigned long _i1=0; _i1 < 16; _i1++)
+   _b[_i0][_i1] = 0.0;
+}
+
+_a_raw[1]  = 0.02173913043478260869565217391304347;
+_a_raw[2]  = 0.09629581047800066670113001679819925;
+_a_raw[3]  = 0.14444371571700100005169502519729888;
+_a_raw[4]  = 0.52205882352941176470588235294117647;
+_a_raw[5]  = 0.22842443612863469578031459099794265;
+_a_raw[6]  = 0.54360353589933733219171338103002937;
+_a_raw[7]  = 0.64335664335664335664335664335664335;
+_a_raw[8]  = 0.48251748251748251748251748251748251;
+_a_raw[9]  = 0.06818181818181818181818181818181818;
+_a_raw[10] = 0.25060827250608272506082725060827250;
+_a_raw[11] = 0.66736715965600568968278165443304378;
+_a_raw[12] = 0.85507246376811594202898550724637681;
+_a_raw[13] = 0.89795918367346938775510204081632653;
+_a_raw[14] = 1.0;
+_a_raw[15] = 1.0;
+
+_a[0]=0.0;
+for(unsigned long _i0=1; _i0 < 16; _i0++)
+  _a[_i0] = _a_raw[_i0] - _a_raw[_i0-1];
+
+_b[1][0]   = 1.0/46.0;
+_b[2][0]   =-0.11698050118114486205818241524969622;
+_b[2][1]   = 0.21327631165914552875931243204789548;
+_b[3][0]   = 0.03611092892925025001292375629932472;
+_b[3][2]   = 0.10833278678775075003877126889797416;
+_b[4][0]   = 1.57329743908138605107331820072051125;
+_b[4][2]   =-5.98400943754042002888532938159655553;
+_b[4][3]   = 4.93277082198844574251789353381722074;
+_b[5][0]   = 0.05052046351120380909008334360006234;
+_b[5][3]   = 0.17686653884807108146683657390397612;
+_b[5][4]   = 0.00103743376935980522339467349390418;
+_b[6][0]   = 0.10543148021953768958529340893598138;
+_b[6][3]   =-0.16042415162569842979496486916719383;
+_b[6][4]   = 0.11643956912829316045688724281285250;
+_b[6][5]   = 0.48215663817720491194449759844838932;
+_b[7][0]   = 0.07148407148407148407148407148407148;
+_b[7][5]   = 0.32971116090443908023196389566296464;
+_b[7][6]   = 0.24216141096813279233990867620960722;
+_b[8][0]   = 0.07162368881118881118881118881118881;
+_b[8][5]   = 0.32859867301674234161492268975519694;
+_b[8][6]   = 0.11622213117906185418927311444060725;
+_b[8][7]   =-0.03392701048951048951048951048951048;
+_b[9][0]   = 0.04861540768024729180628870095388582;
+_b[9][5]   = 0.03998502200331629058445317782406268;
+_b[9][6]   = 0.10715724786209388876739304914053506;
+_b[9][7]   =-0.02177735985419485163815426357369818;
+_b[9][8]   =-0.10579849950964443770179884616296721;
+_b[10][0]  =-0.02540141041535143673515871979014924;
+_b[10][5]  = 1.0/30.0;
+_b[10][6]  =-0.16404854760069182073503553020238782;
+_b[10][7]  = 0.03410548898794737788891414566528526;
+_b[10][8]  = 0.15836825014108792658008718465091487;
+_b[10][9]  = 0.21425115805975734472868683695127609;
+_b[11][0]  = 0.00584833331460742801095934302256470;
+_b[11][5]  =-0.53954170547283522916525526480339109;
+_b[11][6]  = 0.20128430845560909506500331018201158;
+_b[11][7]  = 0.04347222773254789483240207937678906;
+_b[11][8]  =-0.00402998571475307250775349983910179;
+_b[11][9]  = 0.16541535721570612771420482097898952;
+_b[11][10] = 0.79491862412512344573322086551518180;
+_b[12][0]  =-0.39964965968794892497157706711861448;
+_b[12][5]  =-3.79096577568393158554742638116249372;
+_b[12][6]  =-0.40349325653530103387515807815498044;
+_b[12][7]  =-2.82463879530435263378049668286220715;
+_b[12][8]  = 1.04226892772185985533374283289821416;
+_b[12][9]  = 1.12510956420436603974237036536924078;
+_b[12][10] = 3.32746188718986816186934832571938138;
+_b[12][11] = 2.77897957186355606325818219255783627;
+_b[13][0]  = 0.39545306350085237157098218205756922;
+_b[13][5]  = 5.82534730759650564865380791881446903;
+_b[13][6]  =-0.36527452339161313311889856846974452;
+_b[13][7]  = 1.18860324058346533283780076203192232;
+_b[13][8]  = 0.57970467638357921347110271762687972;
+_b[13][9]  =-0.86824862589087693262676988867897834;
+_b[13][10] =-5.20227677296454721392873650976792184;
+_b[13][11] =-0.79895541420753382543211121058675915;
+_b[13][12] = 0.14360623206363792632792463778889008;
+_b[14][0]  = 8.49173149061346398013352206978380938;
+_b[14][5]  = 86.32213734729036800877634194386790750;
+_b[14][6]  = 1.02560575501091662034511526187393241;
+_b[14][7]  = 85.77427969817339941806831550695235092;
+_b[14][8]  =-13.98699305104110611795532466113248067;
+_b[14][9]  =-20.71537405501426352265946477613161883;
+_b[14][10] =-72.16597156619946800281180102605140463;
+_b[14][11] =-76.71211139107806345587696023064419687;
+_b[14][12] = 4.22319427707298828839851258893735507;
+_b[14][13] =-1.25649850482823521641825667745565428;
+_b[15][0]  =-0.42892119881959353241190195318730008;
+_b[15][5]  =-9.16865700950084689999297912545025359;
+_b[15][6]  = 1.08317616770620939241547721530003920;
+_b[15][7]  =-1.23501525358323653198215832293981810;
+_b[15][8]  =-1.21438272617593906232943856422371019;
+_b[15][9]  = 1.37226168507232166621351243731869914;
+_b[15][10] = 9.15723239697162418155377135344394113;
+_b[15][11] = 1.30616301842220047563298585480401671;
+_b[15][12] =-0.25285618808937955976690569433069974;
+_b[15][13] = 0.38099910799663987066763679926508552;
+
+_c[0]  = 0.01490902081978461022483617102382552;
+_c[7]  =-0.20408044692054151258349120934134791;
+_c[8]  = 0.22901438600570447264772469337066476;
+_c[9]  = 0.12800558251147375669208211573729202;
+_c[10] = 0.22380626846054143649770066956485937;
+_c[11] = 0.39553165293700054420552389156421651;
+_c[12] = 0.05416646758806981196568364538360743;
+_c[13] = 0.12691439652445903685643385312168037;
+_c[14] =-0.00052539244262118876455834655383035;
+_c[15] = 1.0/31.0;
+
+_d[0] = 1.0-_b[15][5]/_b[14][5];
+_d[1] = _b[15][0]-_b[14][0]*_b[15][5]/_b[14][5];
+_d[2] = _b[15][5]/_b[14][5];
+_d[3] = _b[15][6]-_b[14][6]*_b[15][5]/_b[14][5];
+_d[4] = _b[15][7]-_b[14][7]*_b[15][5]/_b[14][5];
+_d[5] = _b[15][8]-_b[14][8]*_b[15][5]/_b[14][5];
+_d[6] = _b[15][9]-_b[14][9]*_b[15][5]/_b[14][5];
+_d[7] = _b[15][10]-_b[14][10]*_b[15][5]/_b[14][5];
+_d[8] = _b[15][11]-_b[14][11]*_b[15][5]/_b[14][5];
+_d[9] = _b[15][12]-_b[14][12]*_b[15][5]/_b[14][5];
+_d[10] = _b[15][13]-_b[14][13]*_b[15][5]/_b[14][5];
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def singleIntegrationStep(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def singleIntegrationStep($function) at line 183, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        arguments = {'_step': '_step'}
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 186, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 186, col 1.
+        write(u'''
+// Step 1
+
+''')
+        _v = VFFSL(SL,"copyVectors",False)(VFFSL(SL,"integrationVectors",True), '_akafield') # u"${copyVectors($integrationVectors, '_akafield')}" on line 190, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${copyVectors($integrationVectors, '_akafield')}")) # from line 190, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 192, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 193, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 193, col 9.
+            write(u''' = _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 193, col 25
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 193, col 25.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction=function)}" on line 196, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction=function)}")) # from line 196, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +1, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}" on line 199, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}")) # from line 199, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 200, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 200, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 202, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 203, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 203, col 9.
+            write(u''' = _akafield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 203, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 203, col 34.
+            write(u''';
+''')
+        write(u'''
+// a_k = G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 207, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 207, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +1, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}" on line 210, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}")) # from line 210, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 211, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 211, col 1.
+        write(u'''
+// Step 2
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 215, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 215, col 1.
+        write(u''' += _a[1]*_step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akbfield_${vector.id}[$index] = _${vector.id}[$index] + _b[1][0]*_akafield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akbfield_${vector.id}[$index] = _${vector.id}[$index] + _b[1][0]*_akafield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 217, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 221, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 222, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 222, col 9.
+            write(u''' = _akbfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 222, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 222, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 2, _arrayIndex = 0, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 2, _arrayIndex = 0, parentFunction=function)}" on line 225, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 2, _arrayIndex = 0, parentFunction=function)}")) # from line 225, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -2, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -2, parentFunction=function)}" on line 228, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -2, parentFunction=function)}")) # from line 228, col 1.
+        write(u'''
+
+// a_k = G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 231, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 231, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +2, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +2, parentFunction=function)}" on line 234, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +2, parentFunction=function)}")) # from line 234, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 235, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 235, col 1.
+        write(u'''
+// Step 3
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 239, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 239, col 1.
+        write(u''' += _a[2]*_step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akcfield_${vector.id}[$index] = _${vector.id}[$index] + _b[2][0]*_akafield_${vector.id}[$index] + _b[2][1]*_akbfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akcfield_${vector.id}[$index] = _${vector.id}[$index] + _b[2][0]*_akafield_${vector.id}[$index] + _b[2][1]*_akbfield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 241, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 245, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 246, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 246, col 9.
+            write(u''' = _akcfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 246, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 246, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 3, _arrayIndex = 0, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 3, _arrayIndex = 0, parentFunction=function)}" on line 249, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 3, _arrayIndex = 0, parentFunction=function)}")) # from line 249, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -3, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -3, parentFunction=function)}" on line 252, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -3, parentFunction=function)}")) # from line 252, col 1.
+        write(u'''
+
+// a_k = G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 255, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 255, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +3, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +3, parentFunction=function)}" on line 258, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +3, parentFunction=function)}")) # from line 258, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 259, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 259, col 1.
+        write(u'''
+// Step 4
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 263, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 263, col 1.
+        write(u''' += _a[3]*_step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akdfield_${vector.id}[$index] = _${vector.id}[$index] + _b[3][0]*_akafield_${vector.id}[$index]
+    + _b[3][1]*_akbfield_${vector.id}[$index] + _b[3][2]*_akcfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akdfield_${vector.id}[$index] = _${vector.id}[$index] + _b[3][0]*_akafield_${vector.id}[$index]\n    + _b[3][1]*_akbfield_${vector.id}[$index] + _b[3][2]*_akcfield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 265, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 270, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 271, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 271, col 9.
+            write(u''' = _akdfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 271, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 271, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 4, _arrayIndex = 0, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 4, _arrayIndex = 0, parentFunction=function)}" on line 274, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 4, _arrayIndex = 0, parentFunction=function)}")) # from line 274, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -4, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -4, parentFunction=function)}" on line 277, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -4, parentFunction=function)}")) # from line 277, col 1.
+        write(u'''
+
+// a_k = G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 280, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 280, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +4, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +4, parentFunction=function)}" on line 283, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +4, parentFunction=function)}")) # from line 283, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 284, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 284, col 1.
+        write(u'''
+// Step 5
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 288, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 288, col 1.
+        write(u''' += _a[4]*_step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akefield_${vector.id}[$index] = _${vector.id}[$index] + _b[4][0]*_akafield_${vector.id}[$index]
+    + _b[4][1]*_akbfield_${vector.id}[$index] + _b[4][2]*_akcfield_${vector.id}[$index]
+    + _b[4][3]*_akdfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akefield_${vector.id}[$index] = _${vector.id}[$index] + _b[4][0]*_akafield_${vector.id}[$index]\n    + _b[4][1]*_akbfield_${vector.id}[$index] + _b[4][2]*_akcfield_${vector.id}[$index]\n    + _b[4][3]*_akdfield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 290, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 296, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 297, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 297, col 9.
+            write(u''' = _akefield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 297, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 297, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 5, _arrayIndex = 0, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 5, _arrayIndex = 0, parentFunction=function)}" on line 300, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 5, _arrayIndex = 0, parentFunction=function)}")) # from line 300, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -5, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -5, parentFunction=function)}" on line 303, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -5, parentFunction=function)}")) # from line 303, col 1.
+        write(u'''
+
+// a_k = G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 306, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 306, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +5, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +5, parentFunction=function)}" on line 309, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +5, parentFunction=function)}")) # from line 309, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 310, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 310, col 1.
+        write(u'''
+// Step 6
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 314, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 314, col 1.
+        write(u''' += _a[5]*_step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akifield_${vector.id}[$index] = _${vector.id}[$index] + _b[5][0]*_akafield_${vector.id}[$index]
+    + _b[5][3]*_akdfield_${vector.id}[$index] + _b[5][4]*_akefield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akifield_${vector.id}[$index] = _${vector.id}[$index] + _b[5][0]*_akafield_${vector.id}[$index]\n    + _b[5][3]*_akdfield_${vector.id}[$index] + _b[5][4]*_akefield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 316, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 321, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 322, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 322, col 9.
+            write(u''' = _akifield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 322, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 322, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 6, _arrayIndex = 0, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 6, _arrayIndex = 0, parentFunction=function)}" on line 325, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 6, _arrayIndex = 0, parentFunction=function)}")) # from line 325, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -6, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -6, parentFunction=function)}" on line 328, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -6, parentFunction=function)}")) # from line 328, col 1.
+        write(u'''
+
+// a_k = G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 331, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 331, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +6, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +6, parentFunction=function)}" on line 334, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +6, parentFunction=function)}")) # from line 334, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 335, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 335, col 1.
+        write(u'''
+// Step 7
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 339, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 339, col 1.
+        write(u''' += _a[6]*_step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akjfield_${vector.id}[$index] = _${vector.id}[$index] + _b[6][0]*_akafield_${vector.id}[$index]
+    + _b[6][3]*_akdfield_${vector.id}[$index] + _b[6][4]*_akefield_${vector.id}[$index]
+    + _b[6][5]*_akifield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akjfield_${vector.id}[$index] = _${vector.id}[$index] + _b[6][0]*_akafield_${vector.id}[$index]\n    + _b[6][3]*_akdfield_${vector.id}[$index] + _b[6][4]*_akefield_${vector.id}[$index]\n    + _b[6][5]*_akifield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 341, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 347, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 348, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 348, col 9.
+            write(u''' = _akjfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 348, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 348, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 7, _arrayIndex = 0, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 7, _arrayIndex = 0, parentFunction=function)}" on line 351, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 7, _arrayIndex = 0, parentFunction=function)}")) # from line 351, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -7, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -7, parentFunction=function)}" on line 354, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -7, parentFunction=function)}")) # from line 354, col 1.
+        write(u'''
+
+// a_k = G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 357, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 357, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +7, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +7, parentFunction=function)}" on line 360, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +7, parentFunction=function)}")) # from line 360, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 361, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 361, col 1.
+        write(u'''
+// Step 8
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 365, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 365, col 1.
+        write(u''' += _a[7]*_step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akbfield_${vector.id}[$index] = _${vector.id}[$index] + _b[7][0]*_akafield_${vector.id}[$index]
+    + _b[7][5]*_akifield_${vector.id}[$index] + _b[7][6]*_akjfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akbfield_${vector.id}[$index] = _${vector.id}[$index] + _b[7][0]*_akafield_${vector.id}[$index]\n    + _b[7][5]*_akifield_${vector.id}[$index] + _b[7][6]*_akjfield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 367, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 372, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 373, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 373, col 9.
+            write(u''' = _akbfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 373, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 373, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 8, _arrayIndex = 0, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 8, _arrayIndex = 0, parentFunction=function)}" on line 376, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 8, _arrayIndex = 0, parentFunction=function)}")) # from line 376, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -8, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -8, parentFunction=function)}" on line 379, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -8, parentFunction=function)}")) # from line 379, col 1.
+        write(u'''
+
+// a_k = G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 382, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 382, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +8, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +8, parentFunction=function)}" on line 385, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +8, parentFunction=function)}")) # from line 385, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 386, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 386, col 1.
+        write(u'''
+// Step 9
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 390, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 390, col 1.
+        write(u''' += _a[8]*_step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akcfield_${vector.id}[$index] = _${vector.id}[$index] + _b[8][0]*_akafield_${vector.id}[$index]
+    + _b[8][5]*_akifield_${vector.id}[$index] + _b[8][6]*_akjfield_${vector.id}[$index]
+    + _b[8][7]*_akbfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akcfield_${vector.id}[$index] = _${vector.id}[$index] + _b[8][0]*_akafield_${vector.id}[$index]\n    + _b[8][5]*_akifield_${vector.id}[$index] + _b[8][6]*_akjfield_${vector.id}[$index]\n    + _b[8][7]*_akbfield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 392, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 398, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 399, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 399, col 9.
+            write(u''' = _akcfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 399, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 399, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 9, _arrayIndex = 0, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 9, _arrayIndex = 0, parentFunction=function)}" on line 402, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 9, _arrayIndex = 0, parentFunction=function)}")) # from line 402, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -9, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -9, parentFunction=function)}" on line 405, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -9, parentFunction=function)}")) # from line 405, col 1.
+        write(u'''
+
+// a_k = G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 408, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 408, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +9, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +9, parentFunction=function)}" on line 411, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +9, parentFunction=function)}")) # from line 411, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 412, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 412, col 1.
+        write(u'''
+// Step 10
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 416, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 416, col 1.
+        write(u''' += _a[9]*_step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akdfield_${vector.id}[$index] = _${vector.id}[$index] + _b[9][0]*_akafield_${vector.id}[$index]
+    + _b[9][5]*_akifield_${vector.id}[$index] + _b[9][6]*_akjfield_${vector.id}[$index]
+    + _b[9][7]*_akbfield_${vector.id}[$index] + _b[9][8]*_akcfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akdfield_${vector.id}[$index] = _${vector.id}[$index] + _b[9][0]*_akafield_${vector.id}[$index]\n    + _b[9][5]*_akifield_${vector.id}[$index] + _b[9][6]*_akjfield_${vector.id}[$index]\n    + _b[9][7]*_akbfield_${vector.id}[$index] + _b[9][8]*_akcfield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line 418, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 424, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 425, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 425, col 9.
+            write(u''' = _akdfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 425, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 425, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 10, _arrayIndex = 0, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 10, _arrayIndex = 0, parentFunction=function)}" on line 428, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 10, _arrayIndex = 0, parentFunction=function)}")) # from line 428, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -10, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -10, parentFunction=function)}" on line 431, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -10, parentFunction=function)}")) # from line 431, col 1.
+        write(u'''
+
+// a_k = G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 434, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 434, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +10, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +10, parentFunction=function)}" on line 437, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +10, parentFunction=function)}")) # from line 437, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 438, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 438, col 1.
+        write(u'''
+// Step 11
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 442, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 442, col 1.
+        write(u''' += _a[10]*_step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akefield_${vector.id}[$index] = _${vector.id}[$index] + _b[10][0]*_akafield_${vector.id}[$index]
+    + _b[10][5]*_akifield_${vector.id}[$index] + _b[10][6]*_akjfield_${vector.id}[$index]
+    + _b[10][7]*_akbfield_${vector.id}[$index] + _b[10][8]*_akcfield_${vector.id}[$index]
+    + _b[10][9]*_akdfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akefield_${vector.id}[$index] = _${vector.id}[$index] + _b[10][0]*_akafield_${vector.id}[$index]\n    + _b[10][5]*_akifield_${vector.id}[$index] + _b[10][6]*_akjfield_${vector.id}[$index]\n    + _b[10][7]*_akbfield_${vector.id}[$index] + _b[10][8]*_akcfield_${vector.id}[$index]\n    + _b[10][9]*_akdfield_${vector.id}[$index];\n""", basis = $homeBasis)}')) # from line [...]
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 451, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 452, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 452, col 9.
+            write(u''' = _akefield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 452, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 452, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 11, _arrayIndex = 0, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 11, _arrayIndex = 0, parentFunction=function)}" on line 455, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 11, _arrayIndex = 0, parentFunction=function)}")) # from line 455, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -11, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -11, parentFunction=function)}" on line 458, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -11, parentFunction=function)}")) # from line 458, col 1.
+        write(u'''
+
+// a_k = G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 461, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 461, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +11, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +11, parentFunction=function)}" on line 464, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +11, parentFunction=function)}")) # from line 464, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 465, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 465, col 1.
+        write(u'''
+// Step 12
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 469, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 469, col 1.
+        write(u''' += _a[11]*_step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akffield_${vector.id}[$index] = _${vector.id}[$index] + _b[11][0]*_akafield_${vector.id}[$index]
+    + _b[11][5]*_akifield_${vector.id}[$index] + _b[11][6]*_akjfield_${vector.id}[$index]
+    + _b[11][7]*_akbfield_${vector.id}[$index] + _b[11][8]*_akcfield_${vector.id}[$index]
+    + _b[11][9]*_akdfield_${vector.id}[$index] + _b[11][10]*_akefield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akffield_${vector.id}[$index] = _${vector.id}[$index] + _b[11][0]*_akafield_${vector.id}[$index]\n    + _b[11][5]*_akifield_${vector.id}[$index] + _b[11][6]*_akjfield_${vector.id}[$index]\n    + _b[11][7]*_akbfield_${vector.id}[$index] + _b[11][8]*_akcfield_${vector.id}[$index]\n    + _b[11][9]*_akdfield_${vector.id}[$index] + _b[11][10]*_akefield_${vector.id}[$index [...]
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 478, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 479, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 479, col 9.
+            write(u''' = _akffield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 479, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 479, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 12, _arrayIndex = 0, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 12, _arrayIndex = 0, parentFunction=function)}" on line 482, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 12, _arrayIndex = 0, parentFunction=function)}")) # from line 482, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -12, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -12, parentFunction=function)}" on line 485, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -12, parentFunction=function)}")) # from line 485, col 1.
+        write(u'''
+
+// a_k = G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 488, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 488, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +12, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +12, parentFunction=function)}" on line 491, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +12, parentFunction=function)}")) # from line 491, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 492, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 492, col 1.
+        write(u'''
+// Step 13
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 496, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 496, col 1.
+        write(u''' += _a[12]*_step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akgfield_${vector.id}[$index] = _${vector.id}[$index] + _b[12][0]*_akafield_${vector.id}[$index]
+    + _b[12][5]*_akifield_${vector.id}[$index] + _b[12][6]*_akjfield_${vector.id}[$index]
+    + _b[12][7]*_akbfield_${vector.id}[$index] + _b[12][8]*_akcfield_${vector.id}[$index]
+    + _b[12][9]*_akdfield_${vector.id}[$index] + _b[12][10]*_akefield_${vector.id}[$index]
+    + _b[12][11]*_akffield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akgfield_${vector.id}[$index] = _${vector.id}[$index] + _b[12][0]*_akafield_${vector.id}[$index]\n    + _b[12][5]*_akifield_${vector.id}[$index] + _b[12][6]*_akjfield_${vector.id}[$index]\n    + _b[12][7]*_akbfield_${vector.id}[$index] + _b[12][8]*_akcfield_${vector.id}[$index]\n    + _b[12][9]*_akdfield_${vector.id}[$index] + _b[12][10]*_akefield_${vector.id}[$index [...]
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 506, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 507, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 507, col 9.
+            write(u''' = _akgfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 507, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 507, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 13, _arrayIndex = 0, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 13, _arrayIndex = 0, parentFunction=function)}" on line 510, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 13, _arrayIndex = 0, parentFunction=function)}")) # from line 510, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -13, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -13, parentFunction=function)}" on line 513, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -13, parentFunction=function)}")) # from line 513, col 1.
+        write(u'''
+
+// a_k = G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 516, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 516, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +13, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +13, parentFunction=function)}" on line 519, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +13, parentFunction=function)}")) # from line 519, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 520, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 520, col 1.
+        write(u'''
+// Step 14
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 524, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 524, col 1.
+        write(u''' += _a[13]*_step;
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akhfield_${vector.id}[$index] = _${vector.id}[$index] + _b[13][0]*_akafield_${vector.id}[$index]
+    + _b[13][5]*_akifield_${vector.id}[$index] + _b[13][6]*_akjfield_${vector.id}[$index]
+    + _b[13][7]*_akbfield_${vector.id}[$index] + _b[13][8]*_akcfield_${vector.id}[$index]
+    + _b[13][9]*_akdfield_${vector.id}[$index] + _b[13][10]*_akefield_${vector.id}[$index]
+    + _b[13][11]*_akffield_${vector.id}[$index] + _b[13][12]*_akgfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akhfield_${vector.id}[$index] = _${vector.id}[$index] + _b[13][0]*_akafield_${vector.id}[$index]\n    + _b[13][5]*_akifield_${vector.id}[$index] + _b[13][6]*_akjfield_${vector.id}[$index]\n    + _b[13][7]*_akbfield_${vector.id}[$index] + _b[13][8]*_akcfield_${vector.id}[$index]\n    + _b[13][9]*_akdfield_${vector.id}[$index] + _b[13][10]*_akefield_${vector.id}[$index [...]
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 534, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 535, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 535, col 9.
+            write(u''' = _akhfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 535, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 535, col 34.
+            write(u''';
+''')
+        write(u'''
+''')
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 14, _arrayIndex = 0, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 14, _arrayIndex = 0, parentFunction=function)}" on line 538, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 14, _arrayIndex = 0, parentFunction=function)}")) # from line 538, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = -14, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = -14, parentFunction=function)}" on line 541, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = -14, parentFunction=function)}")) # from line 541, col 1.
+        write(u'''
+
+// a_k = G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 544, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 544, col 1.
+        write(u'''
+
+// a_i = D(a_2*dt)[y1]
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +14, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +14, parentFunction=function)}" on line 547, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +14, parentFunction=function)}")) # from line 547, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 548, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 548, col 1.
+        write(u'''
+// Step 15 and 16 combined to reduce memory use
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""_akifield_${vector.id}[$index] = _${vector.id}[$index] + _b[14][0]*_akafield_${vector.id}[$index]
+    + _b[14][5]*_akifield_${vector.id}[$index] + _b[14][6]*_akjfield_${vector.id}[$index]
+    + _b[14][7]*_akbfield_${vector.id}[$index] + _b[14][8]*_akcfield_${vector.id}[$index]
+    + _b[14][9]*_akdfield_${vector.id}[$index] + _b[14][10]*_akefield_${vector.id}[$index]
+    + _b[14][11]*_akffield_${vector.id}[$index] + _b[14][12]*_akgfield_${vector.id}[$index]
+    + _b[14][13]*_akhfield_${vector.id}[$index];
+    
+  _akjfield_${vector.id}[$index] = _d[0]*_${vector.id}[$index]
+      + _d[1]*_akafield_${vector.id}[$index]
+      + _d[2]*_akifield_${vector.id}[$index] 
+      + _d[3]*_akjfield_${vector.id}[$index] 
+      + _d[4]*_akbfield_${vector.id}[$index]
+      + _d[5]*_akcfield_${vector.id}[$index]
+      + _d[6]*_akdfield_${vector.id}[$index]
+      + _d[7]*_akefield_${vector.id}[$index]
+      + _d[8]*_akffield_${vector.id}[$index]
+      + _d[9]*_akgfield_${vector.id}[$index]
+      + _d[10]*_akhfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""_akifield_${vector.id}[$index] = _${vector.id}[$index] + _b[14][0]*_akafield_${vector.id}[$index]\n    + _b[14][5]*_akifield_${vector.id}[$index] + _b[14][6]*_akjfield_${vector.id}[$index]\n    + _b[14][7]*_akbfield_${vector.id}[$index] + _b[14][8]*_akcfield_${vector.id}[$index]\n    + _b[14][9]*_akdfield_${vector.id}[$index] + _b[14][10]*_akefield_${vector.id}[$index [...]
+        write(u'''
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 573, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 573, col 1.
+        write(u''' += _a[14]*_step;
+
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 575, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 576, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 576, col 9.
+            write(u''' = _akifield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 576, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 576, col 34.
+            write(u''';
+''')
+        write(u'''
+// a_k = G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 580, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 580, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 581, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 581, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 583, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 583, col 1.
+        write(u''' += _a[15]*_step;
+
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 585, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 586, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 586, col 9.
+            write(u''' = _akjfield_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 586, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 586, col 34.
+            write(u''';
+''')
+        write(u'''
+// a_k = G[a_k, t]
+''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function)}" on line 590, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function)}")) # from line 590, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 591, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 591, col 1.
+        write(u'''
+// Take full step
+
+''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""
+_${vector.id}[$index] += _c[0]*_akafield_${vector.id}[$index] + _c[7]*_akbfield_${vector.id}[$index] + _c[8]*_akcfield_${vector.id}[$index]
+    + _c[9]*_akdfield_${vector.id}[$index] + _c[10]*_akefield_${vector.id}[$index] + _c[11]*_akffield_${vector.id}[$index]
+    + _c[12]*_akgfield_${vector.id}[$index] + _c[13]*_akhfield_${vector.id}[$index] + _c[14]*_akifield_${vector.id}[$index]
+    + _c[15]*_akjfield_${vector.id}[$index];
+""", basis = VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""\n_${vector.id}[$index] += _c[0]*_akafield_${vector.id}[$index] + _c[7]*_akbfield_${vector.id}[$index] + _c[8]*_akcfield_${vector.id}[$index]\n    + _c[9]*_akdfield_${vector.id}[$index] + _c[10]*_akefield_${vector.id}[$index] + _c[11]*_akffield_${vector.id}[$index]\n    + _c[12]*_akgfield_${vector.id}[$index] + _c[13]*_akhfield_${vector.id}[$index] + _c[14]*_akifield_ [...]
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 603, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 604, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 604, col 9.
+            write(u''' = _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 604, col 25
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 604, col 25.
+            write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # RK9Stepper.tmpl
+        # 
+        # Created by Graham Dennis on 2007-10-20.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+''')
+        # 
+        #   Single integration step (RK9)
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    ipPropagationStepFractions =   [ '1.000000000000000', '0.978260869565217', '0.903704189521999', '0.855556284282999',    '0.477941176470588', '0.771575563871365', '0.456396464100663', '0.356643356643357',    '0.517482517482518', '0.931818181818182', '0.749391727493917', '0.332632840343994',    '0.144927536231884', '0.102040816326531' ]
+
+    nonconstantIPFields = 1
+
+    extraIntegrationArrayNames =   [ 'akafield', 'akbfield', 'akcfield', 'akdfield', 'akefield',    'akffield', 'akgfield', 'akhfield', 'akifield', 'akjfield' ]
+
+    isCrossCapable = False
+
+    integrationOrder = 9.0
+
+    _mainCheetahMethod_for_RK9Stepper= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(RK9Stepper, '_initCheetahAttributes'):
+    templateAPIClass = getattr(RK9Stepper, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(RK9Stepper)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=RK9Stepper()).run()
+
+
diff --git a/xpdeint/Segments/Integrators/RK9Stepper.tmpl b/xpdeint/Segments/Integrators/RK9Stepper.tmpl
new file mode 100644
index 0000000..b45dc89
--- /dev/null
+++ b/xpdeint/Segments/Integrators/RK9Stepper.tmpl
@@ -0,0 +1,607 @@
+@*
+RK9Stepper.tmpl
+
+Created by Graham Dennis on 2007-10-20.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Segments.Integrators._Stepper
+
+ at def name: RK9
+ at attr $ipPropagationStepFractions = \
+  [ '1.000000000000000', '0.978260869565217', '0.903704189521999', '0.855556284282999',
+    '0.477941176470588', '0.771575563871365', '0.456396464100663', '0.356643356643357',
+    '0.517482517482518', '0.931818181818182', '0.749391727493917', '0.332632840343994',
+    '0.144927536231884', '0.102040816326531' ]
+ at attr $nonconstantIPFields = 1
+ at attr $extraIntegrationArrayNames = \
+  [ 'akafield', 'akbfield', 'akcfield', 'akdfield', 'akefield',
+    'akffield', 'akgfield', 'akhfield', 'akifield', 'akjfield' ]
+ at attr $isCrossCapable = False
+
+ at attr $integrationOrder = 9.0
+
+ at def localInitialise
+  @#
+  @super
+  @#
+
+// Runge Kutta method constants
+real _a_raw[16];
+real _a[16];
+real _b[16][16];
+real _c[16];
+real _d[16];
+
+for(unsigned long _i0=0; _i0 < 16; _i0++)
+{
+  _a_raw[_i0] = _c[_i0] = _d[_i0] = 0.0;
+  for(unsigned long _i1=0; _i1 < 16; _i1++)
+   _b[_i0][_i1] = 0.0;
+}
+
+_a_raw[1]  = 0.02173913043478260869565217391304347;
+_a_raw[2]  = 0.09629581047800066670113001679819925;
+_a_raw[3]  = 0.14444371571700100005169502519729888;
+_a_raw[4]  = 0.52205882352941176470588235294117647;
+_a_raw[5]  = 0.22842443612863469578031459099794265;
+_a_raw[6]  = 0.54360353589933733219171338103002937;
+_a_raw[7]  = 0.64335664335664335664335664335664335;
+_a_raw[8]  = 0.48251748251748251748251748251748251;
+_a_raw[9]  = 0.06818181818181818181818181818181818;
+_a_raw[10] = 0.25060827250608272506082725060827250;
+_a_raw[11] = 0.66736715965600568968278165443304378;
+_a_raw[12] = 0.85507246376811594202898550724637681;
+_a_raw[13] = 0.89795918367346938775510204081632653;
+_a_raw[14] = 1.0;
+_a_raw[15] = 1.0;
+
+_a[0]=0.0;
+for(unsigned long _i0=1; _i0 < 16; _i0++)
+  _a[_i0] = _a_raw[_i0] - _a_raw[_i0-1];
+
+_b[1][0]   = 1.0/46.0;
+_b[2][0]   =-0.11698050118114486205818241524969622;
+_b[2][1]   = 0.21327631165914552875931243204789548;
+_b[3][0]   = 0.03611092892925025001292375629932472;
+_b[3][2]   = 0.10833278678775075003877126889797416;
+_b[4][0]   = 1.57329743908138605107331820072051125;
+_b[4][2]   =-5.98400943754042002888532938159655553;
+_b[4][3]   = 4.93277082198844574251789353381722074;
+_b[5][0]   = 0.05052046351120380909008334360006234;
+_b[5][3]   = 0.17686653884807108146683657390397612;
+_b[5][4]   = 0.00103743376935980522339467349390418;
+_b[6][0]   = 0.10543148021953768958529340893598138;
+_b[6][3]   =-0.16042415162569842979496486916719383;
+_b[6][4]   = 0.11643956912829316045688724281285250;
+_b[6][5]   = 0.48215663817720491194449759844838932;
+_b[7][0]   = 0.07148407148407148407148407148407148;
+_b[7][5]   = 0.32971116090443908023196389566296464;
+_b[7][6]   = 0.24216141096813279233990867620960722;
+_b[8][0]   = 0.07162368881118881118881118881118881;
+_b[8][5]   = 0.32859867301674234161492268975519694;
+_b[8][6]   = 0.11622213117906185418927311444060725;
+_b[8][7]   =-0.03392701048951048951048951048951048;
+_b[9][0]   = 0.04861540768024729180628870095388582;
+_b[9][5]   = 0.03998502200331629058445317782406268;
+_b[9][6]   = 0.10715724786209388876739304914053506;
+_b[9][7]   =-0.02177735985419485163815426357369818;
+_b[9][8]   =-0.10579849950964443770179884616296721;
+_b[10][0]  =-0.02540141041535143673515871979014924;
+_b[10][5]  = 1.0/30.0;
+_b[10][6]  =-0.16404854760069182073503553020238782;
+_b[10][7]  = 0.03410548898794737788891414566528526;
+_b[10][8]  = 0.15836825014108792658008718465091487;
+_b[10][9]  = 0.21425115805975734472868683695127609;
+_b[11][0]  = 0.00584833331460742801095934302256470;
+_b[11][5]  =-0.53954170547283522916525526480339109;
+_b[11][6]  = 0.20128430845560909506500331018201158;
+_b[11][7]  = 0.04347222773254789483240207937678906;
+_b[11][8]  =-0.00402998571475307250775349983910179;
+_b[11][9]  = 0.16541535721570612771420482097898952;
+_b[11][10] = 0.79491862412512344573322086551518180;
+_b[12][0]  =-0.39964965968794892497157706711861448;
+_b[12][5]  =-3.79096577568393158554742638116249372;
+_b[12][6]  =-0.40349325653530103387515807815498044;
+_b[12][7]  =-2.82463879530435263378049668286220715;
+_b[12][8]  = 1.04226892772185985533374283289821416;
+_b[12][9]  = 1.12510956420436603974237036536924078;
+_b[12][10] = 3.32746188718986816186934832571938138;
+_b[12][11] = 2.77897957186355606325818219255783627;
+_b[13][0]  = 0.39545306350085237157098218205756922;
+_b[13][5]  = 5.82534730759650564865380791881446903;
+_b[13][6]  =-0.36527452339161313311889856846974452;
+_b[13][7]  = 1.18860324058346533283780076203192232;
+_b[13][8]  = 0.57970467638357921347110271762687972;
+_b[13][9]  =-0.86824862589087693262676988867897834;
+_b[13][10] =-5.20227677296454721392873650976792184;
+_b[13][11] =-0.79895541420753382543211121058675915;
+_b[13][12] = 0.14360623206363792632792463778889008;
+_b[14][0]  = 8.49173149061346398013352206978380938;
+_b[14][5]  = 86.32213734729036800877634194386790750;
+_b[14][6]  = 1.02560575501091662034511526187393241;
+_b[14][7]  = 85.77427969817339941806831550695235092;
+_b[14][8]  =-13.98699305104110611795532466113248067;
+_b[14][9]  =-20.71537405501426352265946477613161883;
+_b[14][10] =-72.16597156619946800281180102605140463;
+_b[14][11] =-76.71211139107806345587696023064419687;
+_b[14][12] = 4.22319427707298828839851258893735507;
+_b[14][13] =-1.25649850482823521641825667745565428;
+_b[15][0]  =-0.42892119881959353241190195318730008;
+_b[15][5]  =-9.16865700950084689999297912545025359;
+_b[15][6]  = 1.08317616770620939241547721530003920;
+_b[15][7]  =-1.23501525358323653198215832293981810;
+_b[15][8]  =-1.21438272617593906232943856422371019;
+_b[15][9]  = 1.37226168507232166621351243731869914;
+_b[15][10] = 9.15723239697162418155377135344394113;
+_b[15][11] = 1.30616301842220047563298585480401671;
+_b[15][12] =-0.25285618808937955976690569433069974;
+_b[15][13] = 0.38099910799663987066763679926508552;
+
+_c[0]  = 0.01490902081978461022483617102382552;
+_c[7]  =-0.20408044692054151258349120934134791;
+_c[8]  = 0.22901438600570447264772469337066476;
+_c[9]  = 0.12800558251147375669208211573729202;
+_c[10] = 0.22380626846054143649770066956485937;
+_c[11] = 0.39553165293700054420552389156421651;
+_c[12] = 0.05416646758806981196568364538360743;
+_c[13] = 0.12691439652445903685643385312168037;
+_c[14] =-0.00052539244262118876455834655383035;
+_c[15] = 1.0/31.0;
+
+_d[0] = 1.0-_b[15][5]/_b[14][5];
+_d[1] = _b[15][0]-_b[14][0]*_b[15][5]/_b[14][5];
+_d[2] = _b[15][5]/_b[14][5];
+_d[3] = _b[15][6]-_b[14][6]*_b[15][5]/_b[14][5];
+_d[4] = _b[15][7]-_b[14][7]*_b[15][5]/_b[14][5];
+_d[5] = _b[15][8]-_b[14][8]*_b[15][5]/_b[14][5];
+_d[6] = _b[15][9]-_b[14][9]*_b[15][5]/_b[14][5];
+_d[7] = _b[15][10]-_b[14][10]*_b[15][5]/_b[14][5];
+_d[8] = _b[15][11]-_b[14][11]*_b[15][5]/_b[14][5];
+_d[9] = _b[15][12]-_b[14][12]*_b[15][5]/_b[14][5];
+_d[10] = _b[15][13]-_b[14][13]*_b[15][5]/_b[14][5];
+  @#
+ at end def
+
+@*
+  Single integration step (RK9)
+*@
+ at def singleIntegrationStep($function)
+  @#
+  @set $arguments = {'_step': '_step'}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 1
+
+${copyVectors($integrationVectors, '_akafield')}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akafield_${vector.id};
+  @end for
+
+// a_k = G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 2
+
+${propagationDimension} += _a[1]*_step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akbfield_${vector.id}[$index] = _${vector.id}[$index] + _b[1][0]*_akafield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akbfield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 2, _arrayIndex = 0, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -2, parentFunction=function)}
+
+// a_k = G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +2, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 3
+
+${propagationDimension} += _a[2]*_step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akcfield_${vector.id}[$index] = _${vector.id}[$index] + _b[2][0]*_akafield_${vector.id}[$index] + _b[2][1]*_akbfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akcfield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 3, _arrayIndex = 0, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -3, parentFunction=function)}
+
+// a_k = G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +3, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 4
+
+${propagationDimension} += _a[3]*_step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akdfield_${vector.id}[$index] = _${vector.id}[$index] + _b[3][0]*_akafield_${vector.id}[$index]
+    + _b[3][1]*_akbfield_${vector.id}[$index] + _b[3][2]*_akcfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akdfield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 4, _arrayIndex = 0, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -4, parentFunction=function)}
+
+// a_k = G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +4, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 5
+
+${propagationDimension} += _a[4]*_step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akefield_${vector.id}[$index] = _${vector.id}[$index] + _b[4][0]*_akafield_${vector.id}[$index]
+    + _b[4][1]*_akbfield_${vector.id}[$index] + _b[4][2]*_akcfield_${vector.id}[$index]
+    + _b[4][3]*_akdfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akefield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 5, _arrayIndex = 0, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -5, parentFunction=function)}
+
+// a_k = G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +5, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 6
+
+${propagationDimension} += _a[5]*_step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akifield_${vector.id}[$index] = _${vector.id}[$index] + _b[5][0]*_akafield_${vector.id}[$index]
+    + _b[5][3]*_akdfield_${vector.id}[$index] + _b[5][4]*_akefield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akifield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 6, _arrayIndex = 0, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -6, parentFunction=function)}
+
+// a_k = G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +6, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 7
+
+${propagationDimension} += _a[6]*_step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akjfield_${vector.id}[$index] = _${vector.id}[$index] + _b[6][0]*_akafield_${vector.id}[$index]
+    + _b[6][3]*_akdfield_${vector.id}[$index] + _b[6][4]*_akefield_${vector.id}[$index]
+    + _b[6][5]*_akifield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akjfield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 7, _arrayIndex = 0, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -7, parentFunction=function)}
+
+// a_k = G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +7, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 8
+
+${propagationDimension} += _a[7]*_step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akbfield_${vector.id}[$index] = _${vector.id}[$index] + _b[7][0]*_akafield_${vector.id}[$index]
+    + _b[7][5]*_akifield_${vector.id}[$index] + _b[7][6]*_akjfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akbfield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 8, _arrayIndex = 0, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -8, parentFunction=function)}
+
+// a_k = G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +8, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 9
+
+${propagationDimension} += _a[8]*_step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akcfield_${vector.id}[$index] = _${vector.id}[$index] + _b[8][0]*_akafield_${vector.id}[$index]
+    + _b[8][5]*_akifield_${vector.id}[$index] + _b[8][6]*_akjfield_${vector.id}[$index]
+    + _b[8][7]*_akbfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akcfield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 9, _arrayIndex = 0, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -9, parentFunction=function)}
+
+// a_k = G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +9, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 10
+
+${propagationDimension} += _a[9]*_step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akdfield_${vector.id}[$index] = _${vector.id}[$index] + _b[9][0]*_akafield_${vector.id}[$index]
+    + _b[9][5]*_akifield_${vector.id}[$index] + _b[9][6]*_akjfield_${vector.id}[$index]
+    + _b[9][7]*_akbfield_${vector.id}[$index] + _b[9][8]*_akcfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akdfield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 10, _arrayIndex = 0, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -10, parentFunction=function)}
+
+// a_k = G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +10, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 11
+
+${propagationDimension} += _a[10]*_step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akefield_${vector.id}[$index] = _${vector.id}[$index] + _b[10][0]*_akafield_${vector.id}[$index]
+    + _b[10][5]*_akifield_${vector.id}[$index] + _b[10][6]*_akjfield_${vector.id}[$index]
+    + _b[10][7]*_akbfield_${vector.id}[$index] + _b[10][8]*_akcfield_${vector.id}[$index]
+    + _b[10][9]*_akdfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akefield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 11, _arrayIndex = 0, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -11, parentFunction=function)}
+
+// a_k = G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +11, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 12
+
+${propagationDimension} += _a[11]*_step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akffield_${vector.id}[$index] = _${vector.id}[$index] + _b[11][0]*_akafield_${vector.id}[$index]
+    + _b[11][5]*_akifield_${vector.id}[$index] + _b[11][6]*_akjfield_${vector.id}[$index]
+    + _b[11][7]*_akbfield_${vector.id}[$index] + _b[11][8]*_akcfield_${vector.id}[$index]
+    + _b[11][9]*_akdfield_${vector.id}[$index] + _b[11][10]*_akefield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akffield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 12, _arrayIndex = 0, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -12, parentFunction=function)}
+
+// a_k = G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +12, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 13
+
+${propagationDimension} += _a[12]*_step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akgfield_${vector.id}[$index] = _${vector.id}[$index] + _b[12][0]*_akafield_${vector.id}[$index]
+    + _b[12][5]*_akifield_${vector.id}[$index] + _b[12][6]*_akjfield_${vector.id}[$index]
+    + _b[12][7]*_akbfield_${vector.id}[$index] + _b[12][8]*_akcfield_${vector.id}[$index]
+    + _b[12][9]*_akdfield_${vector.id}[$index] + _b[12][10]*_akefield_${vector.id}[$index]
+    + _b[12][11]*_akffield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akgfield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 13, _arrayIndex = 0, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -13, parentFunction=function)}
+
+// a_k = G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +13, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 14
+
+${propagationDimension} += _a[13]*_step;
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akhfield_${vector.id}[$index] = _${vector.id}[$index] + _b[13][0]*_akafield_${vector.id}[$index]
+    + _b[13][5]*_akifield_${vector.id}[$index] + _b[13][6]*_akjfield_${vector.id}[$index]
+    + _b[13][7]*_akbfield_${vector.id}[$index] + _b[13][8]*_akcfield_${vector.id}[$index]
+    + _b[13][9]*_akdfield_${vector.id}[$index] + _b[13][10]*_akefield_${vector.id}[$index]
+    + _b[13][11]*_akffield_${vector.id}[$index] + _b[13][12]*_akgfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akhfield_${vector.id};
+  @end for
+
+${callFunction('nonconstantIPFields', arguments, _exponent = 14, _arrayIndex = 0, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = -14, parentFunction=function)}
+
+// a_k = G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+
+// a_i = D(a_2*dt)[y1]
+${callFunction('ipEvolve', arguments, _exponent = +14, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Step 15 and 16 combined to reduce memory use
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""_akifield_${vector.id}[$index] = _${vector.id}[$index] + _b[14][0]*_akafield_${vector.id}[$index]
+    + _b[14][5]*_akifield_${vector.id}[$index] + _b[14][6]*_akjfield_${vector.id}[$index]
+    + _b[14][7]*_akbfield_${vector.id}[$index] + _b[14][8]*_akcfield_${vector.id}[$index]
+    + _b[14][9]*_akdfield_${vector.id}[$index] + _b[14][10]*_akefield_${vector.id}[$index]
+    + _b[14][11]*_akffield_${vector.id}[$index] + _b[14][12]*_akgfield_${vector.id}[$index]
+    + _b[14][13]*_akhfield_${vector.id}[$index];
+    
+  _akjfield_${vector.id}[$index] = _d[0]*_${vector.id}[$index]
+      + _d[1]*_akafield_${vector.id}[$index]
+      + _d[2]*_akifield_${vector.id}[$index] 
+      + _d[3]*_akjfield_${vector.id}[$index] 
+      + _d[4]*_akbfield_${vector.id}[$index]
+      + _d[5]*_akcfield_${vector.id}[$index]
+      + _d[6]*_akdfield_${vector.id}[$index]
+      + _d[7]*_akefield_${vector.id}[$index]
+      + _d[8]*_akffield_${vector.id}[$index]
+      + _d[9]*_akgfield_${vector.id}[$index]
+      + _d[10]*_akhfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+${propagationDimension} += _a[14]*_step;
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akifield_${vector.id};
+  @end for
+
+// a_k = G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+${propagationDimension} += _a[15]*_step;
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _akjfield_${vector.id};
+  @end for
+
+// a_k = G[a_k, t]
+${callFunction('deltaA', arguments, parentFunction=function)}
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+// Take full step
+
+${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""
+_${vector.id}[$index] += _c[0]*_akafield_${vector.id}[$index] + _c[7]*_akbfield_${vector.id}[$index] + _c[8]*_akcfield_${vector.id}[$index]
+    + _c[9]*_akdfield_${vector.id}[$index] + _c[10]*_akefield_${vector.id}[$index] + _c[11]*_akffield_${vector.id}[$index]
+    + _c[12]*_akgfield_${vector.id}[$index] + _c[13]*_akhfield_${vector.id}[$index] + _c[14]*_akifield_${vector.id}[$index]
+    + _c[15]*_akjfield_${vector.id}[$index];
+""", basis = $homeBasis)}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _${vector.id};
+  @end for
+  @#
+ at end def
diff --git a/xpdeint/Segments/Integrators/SICStepper.py b/xpdeint/Segments/Integrators/SICStepper.py
new file mode 100644
index 0000000..d55a8ce
--- /dev/null
+++ b/xpdeint/Segments/Integrators/SICStepper.py
@@ -0,0 +1,301 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Segments.Integrators._Stepper import _Stepper
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.927649
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Segments/Integrators/SICStepper.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class SICStepper(_Stepper):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(SICStepper, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def name(self, **KWS):
+
+
+
+        ## Generated from @def name: SIC at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''SIC''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def singleIntegrationStep(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def singleIntegrationStep($function) at line 34, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        arguments = {'_step': '_step', VFFSL(SL,"propagationDimension",True): VFFSL(SL,"propagationDimension",True)}
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction=function)}" on line 37, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction=function)}")) # from line 37, col 1.
+        write(u'''
+
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +1, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}" on line 39, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}")) # from line 39, col 1.
+        write(u'''
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 41, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 41, col 1.
+        write(u''' += 0.5*_step;
+
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 43, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 43, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"copyVectors",False)(VFFSL(SL,"integrationVectors",True), '_oldcopy') # u"${copyVectors($integrationVectors, '_oldcopy')}" on line 45, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${copyVectors($integrationVectors, '_oldcopy')}")) # from line 45, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 47, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 48, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 48, col 9.
+            write(u''' = _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 48, col 25
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 48, col 25.
+            write(u''';
+''')
+        write(u'''
+for (int _iteration = 0; _iteration < ''')
+        _v = VFFSL(SL,"iterations",True) # u'${iterations}' on line 51, col 39
+        if _v is not None: write(_filter(_v, rawExpr=u'${iterations}')) # from line 51, col 39.
+        write(u'''; _iteration++) {
+  if (_iteration < ''')
+        _v = VFFSL(SL,"iterations",True) # u'${iterations}' on line 52, col 20
+        if _v is not None: write(_filter(_v, rawExpr=u'${iterations}')) # from line 52, col 20.
+        write(u''' - 1) {
+''')
+        if VFFSL(SL,"integrator.leftOperatorContainer",True): # generated from line 53, col 3
+            write(u'''    ''')
+            _v = VFFSL(SL,"callFunction",False)('leftDeltaA', arguments, _step = '0.5*_step', parentFunction=function) # u"${callFunction('leftDeltaA', arguments, _step = '0.5*_step', parentFunction=function), autoIndent=True}" on line 54, col 5
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${callFunction('leftDeltaA', arguments, _step = '0.5*_step', parentFunction=function), autoIndent=True}")) # from line 54, col 5.
+        if VFFSL(SL,"integrator.rightOperatorContainer",True): # generated from line 56, col 3
+            write(u'''    ''')
+            _v = VFFSL(SL,"callFunction",False)('rightDeltaA', arguments, _step = '0.5*_step', parentFunction=function) # u"${callFunction('rightDeltaA', arguments, _step = '0.5*_step', parentFunction=function), autoIndent=True}" on line 57, col 5
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${callFunction('rightDeltaA', arguments, _step = '0.5*_step', parentFunction=function), autoIndent=True}")) # from line 57, col 5.
+        write(u'''  } else {
+    ''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function), autoIndent=True}" on line 60, col 5
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function), autoIndent=True}")) # from line 60, col 5.
+        write(u'''    
+    ''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis), autoIndent=True}' on line 62, col 5
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis), autoIndent=True}')) # from line 62, col 5.
+        write(u'''    
+    ''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""// a = oldcopy + a
+_${vector.id}[$index] += _oldcopy_${vector.id}[$index];
+""", basis=VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""// a = oldcopy + a\n_${vector.id}[$index] += _oldcopy_${vector.id}[$index];\n""", basis=$homeBasis), autoIndent=True}')) # from line 64, col 5.
+        write(u'''  }
+  
+}
+
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +1, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}" on line 72, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}")) # from line 72, col 1.
+        write(u'''
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 74, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 74, col 1.
+        write(u''' += 0.5*_step;
+
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # SICStepper.tmpl
+        # 
+        # Created by Graham Dennis on 2008-08-06.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+''')
+        # 
+        #   Single integration step (SIC)
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    ipPropagationStepFractions = ['0.5']
+
+    nonconstantIPFields = 1
+
+    extraIntegrationArrayNames = ['oldcopy']
+
+    isCrossCapable = False
+
+    iterations = 3
+
+    _mainCheetahMethod_for_SICStepper= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(SICStepper, '_initCheetahAttributes'):
+    templateAPIClass = getattr(SICStepper, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(SICStepper)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=SICStepper()).run()
+
+
diff --git a/xpdeint/Segments/Integrators/SICStepper.tmpl b/xpdeint/Segments/Integrators/SICStepper.tmpl
new file mode 100644
index 0000000..22c550e
--- /dev/null
+++ b/xpdeint/Segments/Integrators/SICStepper.tmpl
@@ -0,0 +1,77 @@
+@*
+SICStepper.tmpl
+
+Created by Graham Dennis on 2008-08-06.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Segments.Integrators._Stepper
+
+ at def name: SIC
+ at attr $ipPropagationStepFractions = ['0.5']
+ at attr $nonconstantIPFields = 1
+ at attr $extraIntegrationArrayNames = ['oldcopy']
+ at attr $isCrossCapable = False
+ at attr $iterations = 3
+
+@*
+  Single integration step (SIC)
+*@
+ at def singleIntegrationStep($function)
+  @#
+  @set $arguments = {'_step': '_step', $propagationDimension: $propagationDimension}
+${callFunction('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction=function)}
+
+${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}
+
+${propagationDimension} += 0.5*_step;
+
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+${copyVectors($integrationVectors, '_oldcopy')}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _${vector.id};
+  @end for
+
+for (int _iteration = 0; _iteration < ${iterations}; _iteration++) {
+  if (_iteration < ${iterations} - 1) {
+  @if $integrator.leftOperatorContainer
+    ${callFunction('leftDeltaA', arguments, _step = '0.5*_step', parentFunction=function), autoIndent=True}@slurp
+  @end if
+  @if $integrator.rightOperatorContainer
+    ${callFunction('rightDeltaA', arguments, _step = '0.5*_step', parentFunction=function), autoIndent=True}@slurp
+  @end if
+  } else {
+    ${callFunction('deltaA', arguments, parentFunction=function), autoIndent=True}@slurp
+    
+    ${transformVectorsToBasis($integrationVectors, $homeBasis), autoIndent=True}@slurp
+    
+    ${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""// a = oldcopy + a
+_${vector.id}[$index] += _oldcopy_${vector.id}[$index];
+""", basis=$homeBasis), autoIndent=True}@slurp
+  }
+  
+}
+
+${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}
+
+${propagationDimension} += 0.5*_step;
+
+  @#
+ at end def
diff --git a/xpdeint/Segments/Integrators/SIStepper.py b/xpdeint/Segments/Integrators/SIStepper.py
new file mode 100644
index 0000000..9f1a0ae
--- /dev/null
+++ b/xpdeint/Segments/Integrators/SIStepper.py
@@ -0,0 +1,340 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Segments.Integrators._Stepper import _Stepper
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322832.911266
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:32 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Segments/Integrators/SIStepper.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class SIStepper(_Stepper):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(SIStepper, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def name(self, **KWS):
+
+
+
+        ## Generated from @def name: SI at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''SI''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def singleIntegrationStep(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def singleIntegrationStep($function) at line 34, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        arguments = {'_step': '_step', VFFSL(SL,"propagationDimension",True): VFFSL(SL,"propagationDimension",True)}
+        _v = VFFSL(SL,"callFunction",False)('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction=function) # u"${callFunction('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction=function)}" on line 37, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction=function)}")) # from line 37, col 1.
+        write(u'''
+
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +1, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}" on line 39, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}")) # from line 39, col 1.
+        write(u'''
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 41, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 41, col 1.
+        write(u''' += 0.5*_step;
+
+''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis)}' on line 43, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis)}')) # from line 43, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"copyVectors",False)(VFFSL(SL,"integrationVectors",True), '_oldCopy') # u"${copyVectors($integrationVectors, '_oldCopy')}" on line 45, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${copyVectors($integrationVectors, '_oldCopy')}")) # from line 45, col 1.
+        write(u'''
+''')
+        for vector in VFFSL(SL,"integrationVectors",True): # generated from line 47, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 48, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 48, col 9.
+            write(u''' = _''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 48, col 25
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 48, col 25.
+            write(u''';
+''')
+        write(u'''
+''')
+        if VFFSL(SL,"cross",True): # generated from line 51, col 3
+            write(u'''// Interpolate dependencies to the half-step
+''')
+            _v = VFFSL(SL,"interpolateDependencies",True) # u'${interpolateDependencies}' on line 53, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${interpolateDependencies}')) # from line 53, col 1.
+        write(u'''
+for (int _iteration = 0; _iteration < ''')
+        _v = VFFSL(SL,"iterations",True) # u'${iterations}' on line 56, col 39
+        if _v is not None: write(_filter(_v, rawExpr=u'${iterations}')) # from line 56, col 39.
+        write(u'''; _iteration++) {
+  if (_iteration < ''')
+        _v = VFFSL(SL,"iterations",True) # u'${iterations}' on line 57, col 20
+        if _v is not None: write(_filter(_v, rawExpr=u'${iterations}')) # from line 57, col 20.
+        write(u''' - 1) {
+    ''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, _step = '0.5*_step', parentFunction=function) # u"${callFunction('deltaA', arguments, _step = '0.5*_step', parentFunction=function), autoIndent=True}" on line 58, col 5
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${callFunction('deltaA', arguments, _step = '0.5*_step', parentFunction=function), autoIndent=True}")) # from line 58, col 5.
+        write(u'''  } else {
+    ''')
+        _v = VFFSL(SL,"callFunction",False)('deltaA', arguments, parentFunction=function) # u"${callFunction('deltaA', arguments, parentFunction=function), autoIndent=True}" on line 60, col 5
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${callFunction('deltaA', arguments, parentFunction=function), autoIndent=True}")) # from line 60, col 5.
+        write(u'''  }
+  
+  ''')
+        _v = VFFSL(SL,"transformVectorsToBasis",False)(VFFSL(SL,"integrationVectors",True), VFFSL(SL,"homeBasis",True)) # u'${transformVectorsToBasis($integrationVectors, $homeBasis), autoIndent=True}' on line 63, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${transformVectorsToBasis($integrationVectors, $homeBasis), autoIndent=True}')) # from line 63, col 3.
+        write(u'''  
+  ''')
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)(VFFSL(SL,"integrationVectors",True),
+"""// a = oldCopy + a
+_${vector.id}[$index] += _oldCopy_${vector.id}[$index];
+""", basis=VFFSL(SL,"homeBasis",True))
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${loopOverVectorsWithInnerContentTemplate($integrationVectors,\n"""// a = oldCopy + a\n_${vector.id}[$index] += _oldCopy_${vector.id}[$index];\n""", basis=$homeBasis), autoIndent=True}')) # from line 65, col 3.
+        write(u'''}
+
+''')
+        _v = VFFSL(SL,"callFunction",False)('ipEvolve', arguments, _exponent = +1, parentFunction=function) # u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}" on line 71, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}")) # from line 71, col 1.
+        write(u'''
+
+''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 73, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 73, col 1.
+        write(u''' += 0.5*_step;
+
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def interpolateDependencies(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def interpolateDependencies at line 78, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  Insert code to interpolate the dependency vectors onto the half-step point.
+        #  
+        _v = VFFSL(SL,"reducedFieldCopy",False)(VFFSL(SL,"integrator.dependencyMap",True), 
+"""
+_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = \\
+    0.5*(_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex}]
+       + _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + ${skipSize} * _${vector.id}_ncomponents]);
+""")
+        if _v is not None: write(_filter(_v, rawExpr=u'${reducedFieldCopy($integrator.dependencyMap, \n"""\n_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = \\\\\n    0.5*(_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex}]\n       + _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + ${skipSize} * _${vector.id}_ncomponents]);\n""")}')) # from line 82, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # SIStepper.tmpl
+        # 
+        # Created by Joe Hope on 2008-03-24.
+        # 
+        # Copyright (c) 2008-2012, Joe Hope and Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+''')
+        # 
+        #   Single integration step (SI)
+        write(u'''
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    ipPropagationStepFractions = ['0.5']
+
+    nonconstantIPFields = 1
+
+    extraIntegrationArrayNames = ['oldCopy']
+
+    isCrossCapable = True
+
+    iterations = 3
+
+    _mainCheetahMethod_for_SIStepper= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(SIStepper, '_initCheetahAttributes'):
+    templateAPIClass = getattr(SIStepper, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(SIStepper)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=SIStepper()).run()
+
+
diff --git a/xpdeint/Segments/Integrators/SIStepper.tmpl b/xpdeint/Segments/Integrators/SIStepper.tmpl
new file mode 100644
index 0000000..281ac30
--- /dev/null
+++ b/xpdeint/Segments/Integrators/SIStepper.tmpl
@@ -0,0 +1,89 @@
+@*
+SIStepper.tmpl
+
+Created by Joe Hope on 2008-03-24.
+
+Copyright (c) 2008-2012, Joe Hope and Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Segments.Integrators._Stepper
+
+ at def name: SI
+ at attr $ipPropagationStepFractions = ['0.5']
+ at attr $nonconstantIPFields = 1
+ at attr $extraIntegrationArrayNames = ['oldCopy']
+ at attr $isCrossCapable = True
+ at attr $iterations = 3
+
+@*
+  Single integration step (SI)
+*@
+ at def singleIntegrationStep($function)
+  @#
+  @set $arguments = {'_step': '_step', $propagationDimension: $propagationDimension}
+${callFunction('nonconstantIPFields', arguments, _exponent = 1, _arrayIndex = 0, parentFunction=function)}
+
+${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}
+
+${propagationDimension} += 0.5*_step;
+
+${transformVectorsToBasis($integrationVectors, $homeBasis)}@slurp
+
+${copyVectors($integrationVectors, '_oldCopy')}@slurp
+
+  @for $vector in $integrationVectors
+_active_${vector.id} = _${vector.id};
+  @end for
+
+  @if $cross
+// Interpolate dependencies to the half-step
+${interpolateDependencies}@slurp
+  @end if
+
+for (int _iteration = 0; _iteration < ${iterations}; _iteration++) {
+  if (_iteration < ${iterations} - 1) {
+    ${callFunction('deltaA', arguments, _step = '0.5*_step', parentFunction=function), autoIndent=True}@slurp
+  } else {
+    ${callFunction('deltaA', arguments, parentFunction=function), autoIndent=True}@slurp
+  }
+  
+  ${transformVectorsToBasis($integrationVectors, $homeBasis), autoIndent=True}@slurp
+  
+  ${loopOverVectorsWithInnerContentTemplate($integrationVectors,
+"""// a = oldCopy + a
+_${vector.id}[$index] += _oldCopy_${vector.id}[$index];
+""", basis=$homeBasis), autoIndent=True}@slurp
+}
+
+${callFunction('ipEvolve', arguments, _exponent = +1, parentFunction=function)}
+
+${propagationDimension} += 0.5*_step;
+
+  @#
+ at end def
+
+ at def interpolateDependencies
+  @#
+  @# Insert code to interpolate the dependency vectors onto the half-step point.
+  @# 
+${reducedFieldCopy($integrator.dependencyMap, 
+"""
+_active_${reducedVector.id}[_${reducedVector.id}_index_pointer + ${componentIndex}] = \\
+    0.5*(_active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex}]
+       + _active_${vector.id}[_${vector.id}_index_pointer + ${componentIndex} + ${skipSize} * _${vector.id}_ncomponents]);
+""")}@slurp
+  @#
+ at end def
diff --git a/xpdeint/Segments/Integrators/_FixedStep.py b/xpdeint/Segments/Integrators/_FixedStep.py
new file mode 100644
index 0000000..ae1a30c
--- /dev/null
+++ b/xpdeint/Segments/Integrators/_FixedStep.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_FixedStep.py
+
+Created by Graham Dennis on 2008-03-01.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Segments.Integrators.Integrator import Integrator
+
+from xpdeint.Utilities import lazy_property
+
+class _FixedStep (Integrator):
+  # Is this integrator capable of doing cross-propagation integration?
+  isCrossCapable = False
+  
+  def __init__(self, *args, **KWs):
+    Integrator.__init__(self, *args, **KWs)
+    
+    # Set default variables
+    self._cross = False
+    
+    # Is this integrator being used as a cross-propagation integrator?
+    self.cross = KWs.get('cross', False)
+    
+  
+  def _getCross(self):
+    return self._cross
+  
+  def _setCross(self, value):
+    if value and not self.stepper.isCrossCapable:
+      raise AssertionError("This stepper (%s) does not support cross-propagation." % str(type(self.stepper)))
+    else:
+      self._cross = value
+  
+  cross = property(_getCross, _setCross)
+  del _getCross, _setCross
+  
+  @lazy_property
+  def bannedFeatures(self):
+    """Return the features which are not permitted to be inserted by this instance."""
+    
+    # If we are cross-propagating, then ErrorCheck cannot simply subdivide the step.
+    # And we don't want to sample anything for moment groups
+    
+    # GD: The reason that we disable auto-vectorisation is subtle, and I don't completely
+    # understand it myself. But after much fiddling, it seems that the last step in the 
+    # integrator where the results from the integration step are copied back into the main
+    # array does not sync with the last memory write in the step (as the last step with the
+    # auto-vectorisation feature would have been to a real*, so come time for the copy to
+    # a complex variable, the CPU/compiler sees fit to reorder the stores causing all hell
+    # to break loose). This isn't a particularly good explanation, but my understanding of
+    # this isn't particularly strong.
+    # 
+    # My evidence is that everything works fine if I turn off auto-vectorisation, and it also
+    # works fine if I have it on but have a printf before (but not after) the copy operation
+    # (inside the loop) to force a read from the memory that is going to be written to and so force
+    # the correct ordering between the two writes. It may be possible to turn on the
+    # auto-vectorisation feature if a memory barrier is added before the final copy step, but I
+    # don't know how to implement a cross-platform memory barrier, and I'm not about to find out.
+    
+    if self.cross:
+      return ['ErrorCheck', 'Output', 'AutoVectorise']
+    else:
+      return None
+  
+  @lazy_property
+  def step(self):
+    return ''.join([str(self.interval), '/(real)', str(self.stepCount)])
+  
+  
+
diff --git a/xpdeint/Segments/Integrators/_FixedStepWithCross.py b/xpdeint/Segments/Integrators/_FixedStepWithCross.py
new file mode 100644
index 0000000..cea324c
--- /dev/null
+++ b/xpdeint/Segments/Integrators/_FixedStepWithCross.py
@@ -0,0 +1,172 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_FixedStepWithCross.py
+
+Created by Graham Dennis on 2008-08-06.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Segments.Integrators.FixedStep import FixedStep
+
+from xpdeint.Operators.CrossPropagationOperator import CrossPropagationOperator
+from xpdeint.Operators.OperatorContainer import OperatorContainer
+from xpdeint.Operators.SICDeltaAOperator import SICDeltaAOperator
+
+from xpdeint.ParserException import ParserException
+from xpdeint.Function import Function
+from xpdeint.Geometry import FieldElement
+
+class _FixedStepWithCross (FixedStep):
+  def __init__(self, *args, **KWs):
+    FixedStep.__init__(self, *args, **KWs)
+    
+    self.operatorContainerToOverride = None
+    self.leftOperatorContainer = None
+    self.rightOperatorContainer = None
+    self.leftRightLoopingField = None
+    
+    functionNamePrefix = '_' + self.id
+    
+    self.functions['leftDeltaA'] = Function(name = functionNamePrefix + '_calculate_left_delta_a',
+                                            args = [('real', '_step')], 
+                                            implementation = self.leftDeltaAFunctionBody,
+                                            predicate = lambda: bool(self.leftOperatorContainer))
+    self.functions['rightDeltaA'] = Function(name = functionNamePrefix + '_calculate_right_delta_a',
+                                             args = [('real', '_step')], 
+                                             implementation = self.rightDeltaAFunctionBody,
+                                             predicate = lambda: bool(self.rightOperatorContainer))
+    
+  
+  def leftDeltaAFunctionBody(self, function):
+    return self.leftRightDeltaAFunctionBody(function, self.leftOperatorContainer)
+  
+  def rightDeltaAFunctionBody(self, function):
+    return self.leftRightDeltaAFunctionBody(function, self.rightOperatorContainer)
+  
+  def leftRightOperatorContainerFromCrossPropagationOperator(self, crossOp):
+    # We can just extract the Delta-a operator from the cross-propagation integrator
+    # and then modify the inner code somewhat, and we're done.
+    # We may need to reorder the looping dimensions in order to get the cross-propagation dimension
+    # looped across last.... Is this safe, combined with integer-valued dimension stuff?
+    # How about we just assert that its current loopingField is the same as the operator field.
+    # Nope. It's in preflight() that the DeltaA operator reorders its dimensions... but we can make
+    # it not do that if loopingField has already been set. (and raise an exception)
+    direction = crossOp.propagationDirection
+    if direction == '+':
+      directionName = 'left'
+    else:
+      directionName = 'right'
+    
+    oldCrossDeltaAOperator = crossOp.crossPropagationIntegratorDeltaAOperator
+    normalDeltaAOperator = self.operatorContainerToOverride.deltaAOperator
+    
+    operatorContainer = OperatorContainer(field = self.operatorContainerToOverride.field,
+                                          parent = self,
+                                          name = directionName + '_container',
+                                          **self.argumentsToTemplateConstructors)
+    
+    leftRightDeltaAOperator = SICDeltaAOperator(parent = operatorContainer,
+                                                **self.argumentsToTemplateConstructors)
+    leftRightDeltaAOperator.crossPropagationDimension           = crossOp.propagationDimension
+    leftRightDeltaAOperator.crossPropagationDirection           = direction
+    leftRightDeltaAOperator.integrationVectorsEntity            = normalDeltaAOperator.integrationVectorsEntity
+    leftRightDeltaAOperator.codeBlocks['operatorDefinition']    = normalDeltaAOperator.codeBlocks['operatorDefinition']
+    
+    leftRightDeltaAOperator.codeBlocks['boundaryCondition']     = crossOp.codeBlocks['boundaryCondition']
+    
+    leftRightDeltaAOperator.crossIntegrationVectorsEntity       = crossOp.integrationVectorsEntity
+    leftRightDeltaAOperator.codeBlocks['crossPropagation']      = oldCrossDeltaAOperator.codeBlocks['operatorDefinition']
+    
+    leftRightDeltaAOperator.iterations = crossOp.crossPropagationIntegrator.stepper.iterations
+    
+    # Now we need to work out if we need to create a new field to be the looping field
+    crossPropagationDimensionName = crossOp.propagationDimension
+    if not self.leftRightLoopingField:
+      if leftRightDeltaAOperator.field.dimensions[-1].name != crossPropagationDimensionName:
+        # We need to create a new field with reordered dimensions
+        loopingFieldName = ''.join(['_', normalDeltaAOperator.id, '_leftright_looping_field'])
+        
+        loopingField = FieldElement(name = loopingFieldName,
+                                    **self.argumentsToTemplateConstructors)
+        
+        loopingField.dimensions = [dim.copy(parent=loopingField) for dim in newFieldDimensions]
+        crossDim = loopingField.dimensionWithName(crossPropagationDimensionName)
+        loopingField.dimensions.remove(crossDim)
+        loopingField.dimensions.append(crossDim)
+        self.leftRightLoopingField = loopingField
+      else:
+        # We set this to prevent the delta-a operator itself trying to change its looping field.
+        self.leftRightLoopingField = leftRightDeltaAOperator.field
+    leftRightDeltaAOperator.loopingField = self.leftRightLoopingField
+    
+    self._children.append(operatorContainer)
+    return operatorContainer
+  
+  def bindNamedVectors(self):
+    super(_FixedStepWithCross, self).bindNamedVectors()
+    
+    # This needs to go in bindNamedVectors not preflight because the CrossPropagationOperator
+    # fiddles with the mapping of vector names to vectors for its child elements, and it will be annoying
+    # to undo, so we best clear out all of these objects before that happens.
+    
+    # Now we need to drill down into our operator container objects, locate the cross-propagators (there should be some)
+    # and then destroy them and copy their code into our left- and right-propagating delta-a objects. But destroying a
+    # cross-propagator is quite involved as it requires destroying the actual integration objects too. Let's hope that
+    # our 'remove' method works correctly.
+    
+    propagationDimension = None
+    
+    for oc in self.intraStepOperatorContainers:
+      crossOperators = [op for op in oc.preDeltaAOperators if isinstance(op, CrossPropagationOperator)]
+      for crossOp in crossOperators:
+        if not propagationDimension:
+          propagationDimension = crossOp.propagationDimension
+        if self.operatorContainerToOverride and not oc == self.operatorContainerToOverride:
+          raise ParserException(self.xmlElement, "This integrator can only have at most two cross-propagators. "
+                                                 "They must be in opposite directions, and be in the same <operators> block.")
+        self.operatorContainerToOverride = oc
+        if crossOp.propagationDirection == '+':
+          # Propagating from left
+          if self.leftOperatorContainer:
+            raise ParserException(self.xmlElement, "This integrator has two cross-propagators with left boundary conditions. "
+                                                   "The SIC integrator can only have two cross-propagators, one in each direction of a single dimension.")
+          self.leftOperatorContainer = self.leftRightOperatorContainerFromCrossPropagationOperator(crossOp)
+        else:
+          # Propagating from right
+          if self.rightOperatorContainer:
+            raise ParserException(self.xmlElement, "This integrator has two cross-propagators with right boundary conditions. "
+                                                   "The SIC integrator can only have two cross-propagators, one in each direction of a single dimension.")
+          self.rightOperatorContainer = self.leftRightOperatorContainerFromCrossPropagationOperator(crossOp)
+        
+        # Kill the CrossPropagationOperator and its children
+        oc.preDeltaAOperators.remove(crossOp)
+        crossOp.remove()
+    
+  def preflight(self):
+    super(_FixedStepWithCross, self).preflight()
+    
+    if not self.leftOperatorContainer and not self.rightOperatorContainer:
+      raise ParserException(self.xmlElement, "It doesn't make sense to use the 'SIC' integrator without any cross-propagation operators. Use 'SI' instead.")
+    
+    for oc in [self.leftOperatorContainer, self.rightOperatorContainer]:
+      if not oc:
+        continue
+      self.operatorContainerToOverride.deltaAOperator.dependencies.update(oc.deltaAOperator.crossIntegrationVectors)
+
+
diff --git a/xpdeint/Segments/Integrators/_Integrator.py b/xpdeint/Segments/Integrators/_Integrator.py
new file mode 100644
index 0000000..cf967e9
--- /dev/null
+++ b/xpdeint/Segments/Integrators/_Integrator.py
@@ -0,0 +1,188 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_Integrator.py
+
+This contains all the pure-python code for Integrator.tmpl
+
+Created by Graham Dennis on 2007-10-18.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Segments._Segment import _Segment
+
+from xpdeint.Operators.NonConstantIPOperator import NonConstantIPOperator
+from xpdeint.ParserException import ParserException
+from xpdeint.Utilities import lazy_property, leastCommonMultiple
+from xpdeint.Function import Function
+from itertools import chain
+
+class _Integrator (_Segment):
+  
+  canBeInitialisedEarly = True
+  
+  def __init__(self, stepperClass, *args, **KWs):
+    _Segment.__init__(self, *args, **KWs)
+    
+    # Set default variables
+    self.samplesEntity = None
+    self.samples = []
+    self._integrationVectors = set()
+    self.homeBasis = None
+    self.cutoff = 1e-3
+    self.stepStartOperatorContainers = []
+    self.intraStepOperatorContainers = []
+    self.stepEndOperatorContainers = []
+    self.localVectors = set()
+    assert stepperClass
+    self.stepper = stepperClass(parent = self, **self.argumentsToTemplateConstructors)
+    self._children.append(self.stepper)
+    
+    functionNamePrefix = '_' + self.id
+    
+    self.functions['deltaA'] = Function(name = functionNamePrefix + '_calculate_delta_a',
+                                        args = [('real', '_step')], 
+                                        implementation = self.deltaAFunctionBody,
+                                        returnType = 'inline void')
+    
+    self.functions['ipEvolve'] = Function(name = functionNamePrefix + '_ip_evolve',
+                                          args = [('int', '_exponent')],
+                                          implementation = self.ipEvolveFunctionBody,
+                                          returnType = 'inline void')
+    
+    self.functions['nonconstantIPFields'] = Function(name = functionNamePrefix + '_calculate_nonconstant_ip_fields',
+                                                     args = [('real', '_step'), ('int', '_exponent'), ('int', '_arrayIndex')],
+                                                     implementation = self.nonconstantIPFieldsFunctionBody,
+                                                     returnType = 'inline void')
+    
+  
+  @property
+  def children(self):
+    children = super(_Integrator, self).children
+    children.extend(chain(self.stepStartOperatorContainers, self.intraStepOperatorContainers, self.stepEndOperatorContainers, \
+                          self.localVectors))
+    return children
+  
+  @property
+  def integrationVectors(self):
+    if self._integrationVectors:
+      return self._integrationVectors.copy()
+    
+    deltaAOperators = [oc.deltaAOperator for oc in self.intraStepOperatorContainers if oc.deltaAOperator]
+    for op in deltaAOperators:
+      self._integrationVectors.update(op.integrationVectors)
+    
+    return self._integrationVectors.copy()
+  
+  @lazy_property
+  def dynamicNoiseVectors(self):
+    """Returns the dynamic noise vectors required by the integrator."""
+    
+    return [vector for vector in self.evaluationOrderForVectors(
+            self.dynamicVectorsNeedingPrecalculationForOperatorContainers(self.intraStepOperatorContainers), 
+            static = False, predicate = lambda x: x.isComputed or x.isNoise) if vector.isNoise]
+
+  @lazy_property
+  def extraIntegrationArrayNames(self):
+    return self.stepper.extraIntegrationArrayNames
+  
+  @lazy_property
+  def ipPropagationStepFractions(self):
+    return self.stepper.ipPropagationStepFractions
+  
+  @lazy_property
+  def nonconstantIPFields(self):
+    return self.stepper.nonconstantIPFields
+  
+  @lazy_property
+  def stepCount(self):
+    return leastCommonMultiple([sample for sample in self.samples])
+  
+  @property
+  def integrationOrder(self):
+    return self.stepper.integrationOrder
+  
+  @property
+  def operatorContainers(self):
+    return list(chain(self.stepStartOperatorContainers, self.intraStepOperatorContainers, self.stepEndOperatorContainers))
+  
+  @property
+  def integrationFields(self):
+    return set([v.field for v in self.integrationVectors])
+  
+  # List of the operator containers in descending order of the number of dimensions in their fields.
+  #
+  # This is needed because when delta A operators are evaluated, they replace the components
+  # with their propagation-dimension increments. i.e. They do phi = dphi_dt * dt
+  #
+  # As a result, we need to be very particular about the order in which the delta A operators are evaluated.
+  # We can't have a delta A operator for a vector before another delta A operator that might depend on that
+  # vector.
+  #
+  # The solution used is to order the delta A operators in descending order of the
+  # number of dimensions in its field, because while it would be sensible for a field with 3 dimensions to depend
+  # on another field with 0 or 1 dimensions, it doesn't make sense for a 0 or 1 dimensional field to depend directly
+  # on a 3 dimensional field. It may depend on the 3 dimensional field through moments of the field, however they will
+  # be calculated in other operators that would have already been evaluated.
+  def intraStepOperatorContainersInFieldDescendingOrder(self):
+    operatorContainers = self.intraStepOperatorContainers[:]
+    operatorContainers.sort(lambda x, y: cmp(len(x.field.dimensions), len(y.field.dimensions)), reverse=True)
+    return operatorContainers
+  
+  def ipEvolveFunctionBody(self, function):
+    return '\n'.join([oc.evaluateIPOperators(parentFunction = function) for oc in self.operatorContainers])
+  
+  def nonconstantIPFieldsFunctionBody(self, function):
+    result = []
+    for oc in self.operatorContainers:
+      nonconstantIPOperators = [op for op in oc.ipOperators if isinstance(op, NonConstantIPOperator)]
+      if nonconstantIPOperators:
+        result.append(oc.callOperatorFunctionWithArguments('calculateOperatorField', nonconstantIPOperators, parentFunction=function))
+    
+    return '\n'.join(result)
+  
+  def bindNamedVectors(self):
+    super(_Integrator, self).bindNamedVectors()
+    
+    momentGroups = self.getVar('momentGroups')
+    
+    if not self.samplesEntity:
+      self.samples = [0] * len(momentGroups)
+    else:
+      samplesList = self.samplesEntity.value
+      samplesElement = self.samplesEntity.xmlElement
+      
+      if not len(samplesList) == len(momentGroups):
+        raise ParserException(samplesElement, "The number of entries (%i) does not match the "
+                                              "number of moment groups (%i)." % \
+                                              (len(samplesList), len(momentGroups)))
+      
+      self.samples = [int(sampleCountString) for sampleCountString in samplesList]
+      
+      for momentGroup, sampleCount in zip(momentGroups, self.samples):
+        if sampleCount and not (self.stepCount % sampleCount) == 0:
+          raise ParserException(samplesElement, "Sample count does not evenly divide the number of steps")
+        
+        momentGroup.addSamplePoints(sampleCount * self.totalCycles)
+    
+    
+  def preflight(self):
+    super(_Integrator, self).preflight()
+    
+    self.registerVectorsRequiredInBasis(self.integrationVectors, self.homeBasis)
+  
diff --git a/xpdeint/Segments/Integrators/_Stepper.py b/xpdeint/Segments/Integrators/_Stepper.py
new file mode 100644
index 0000000..09702ac
--- /dev/null
+++ b/xpdeint/Segments/Integrators/_Stepper.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_Stepper.py
+
+Created by Graham Dennis on 2008-11-12.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.ScriptElement import ScriptElement
+from xpdeint.Utilities import lazy_property
+
+class _Stepper (ScriptElement):
+  @lazy_property
+  def integrationVectors(self):
+    return self.parent.integrationVectors
+  
+  @property
+  def homeBasis(self):
+    return self.parent.homeBasis
+  
+  @lazy_property
+  def integrator(self):
+    return self.parent
+  
+  @property
+  def cross(self):
+    return self.parent.cross
+  
+  def callFunction(self, functionName, *args, **KWs):
+    return self.parent.functions[functionName].call(*args, **KWs)
+  
+  def localInitialise(self):
+    return None
+  
+  def localFinalise(self):
+    return None
+  
+  def reducedFieldCopy(self, *args, **KWs):
+    return self.integrator.reducedFieldCopy(*args, **KWs)
+  
+  def updateDependenciesForNextStep(self, *args, **KWs):
+    return self.integrator.updateDependenciesForNextStep(*args, **KWs)
+  
diff --git a/xpdeint/Segments/Integrators/__init__.py b/xpdeint/Segments/Integrators/__init__.py
new file mode 100644
index 0000000..830d52c
--- /dev/null
+++ b/xpdeint/Segments/Integrators/__init__.py
@@ -0,0 +1,11 @@
+#
+import FixedStep
+import FixedStepWithCross
+import AdaptiveStep
+
+import RK4Stepper
+import RK9Stepper
+import RK45Stepper
+import RK89Stepper
+import SIStepper
+import SICStepper
\ No newline at end of file
diff --git a/xpdeint/Segments/SequenceSegment.py b/xpdeint/Segments/SequenceSegment.py
new file mode 100644
index 0000000..7e1edf6
--- /dev/null
+++ b/xpdeint/Segments/SequenceSegment.py
@@ -0,0 +1,422 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Segments._Segment import _Segment
+from xpdeint.CallOnceGuards import callOncePerInstanceGuard
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.035691
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Segments/SequenceSegment.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class SequenceSegment(_Segment):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(SequenceSegment, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: segment $segmentNumber (Sequence) at line 28, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''segment ''')
+        _v = VFFSL(SL,"segmentNumber",True) # u'$segmentNumber' on line 28, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'$segmentNumber')) # from line 28, col 27.
+        write(u''' (Sequence)''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def segmentFunctionBody(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def segmentFunctionBody($function) at line 30, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        extraIndent = 0
+        if VFFSL(SL,"localCycles",True) > 1: # generated from line 33, col 3
+            write(u'''// Initialise child segments
+''')
+            _v = VFFSL(SL,"allocate",True) # u'${allocate}' on line 35, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${allocate}')) # from line 35, col 1.
+            _v = VFFSL(SL,"initialise",True) # u'${initialise}' on line 36, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${initialise}')) # from line 36, col 1.
+            write(u'''for (unsigned long _cycle = 0; _cycle < ''')
+            _v = VFFSL(SL,"localCycles",True) # u'${localCycles}' on line 37, col 41
+            if _v is not None: write(_filter(_v, rawExpr=u'${localCycles}')) # from line 37, col 41.
+            write(u'''; _cycle++) {
+''')
+            extraIndent = 2
+        # 
+        _v = VFFSL(SL,"callChildSegments",False)(function) # u'${callChildSegments(function), extraIndent=extraIndent}' on line 41, col 1
+        if _v is not None: write(_filter(_v, extraIndent=extraIndent, rawExpr=u'${callChildSegments(function), extraIndent=extraIndent}')) # from line 41, col 1.
+        # 
+        if VFFSL(SL,"localCycles",True) > 1: # generated from line 43, col 3
+            write(u'''}
+''')
+            extraIndent = 0
+            write(u'''// Finalise child segments
+''')
+            _v = VFFSL(SL,"finalise",True) # u'${finalise}' on line 47, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${finalise}')) # from line 47, col 1.
+            _v = VFFSL(SL,"free",True) # u'${free}' on line 48, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${free}')) # from line 48, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def callChildSegments(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def callChildSegments($function) at line 53, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        for segment in VFFSL(SL,"childSegments",True): # generated from line 55, col 3
+            _v = VFN(VFN(VFFSL(SL,"segment",True),"functions",True)['segment'],"call",False)(parentFunction=function) # u"${segment.functions['segment'].call(parentFunction=function)}" on line 56, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u"${segment.functions['segment'].call(parentFunction=function)}")) # from line 56, col 1.
+            write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOncePerInstanceGuard
+    def allocate(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def allocate at line 62, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(SequenceSegment, self).allocate()
+        if _v is not None: write(_filter(_v))
+        # 
+        for segment in VFFSL(SL,"childSegments",True): # generated from line 66, col 3
+            _v = VFFSL(SL,"segment.allocate",True) # u'$segment.allocate' on line 67, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'$segment.allocate')) # from line 67, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOncePerInstanceGuard
+    def free(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def free at line 73, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(SequenceSegment, self).free()
+        if _v is not None: write(_filter(_v))
+        # 
+        for segment in VFFSL(SL,"childSegments",True): # generated from line 77, col 3
+            _v = VFFSL(SL,"segment.free",True) # u'$segment.free' on line 78, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'$segment.free')) # from line 78, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOncePerInstanceGuard
+    def initialise(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def initialise at line 84, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(SequenceSegment, self).initialise()
+        if _v is not None: write(_filter(_v))
+        # 
+        for segment in VFFSL(SL,"childSegments",True): # generated from line 88, col 3
+            _v = VFFSL(SL,"segment.initialise",True) # u'$segment.initialise' on line 89, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'$segment.initialise')) # from line 89, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOncePerInstanceGuard
+    def finalise(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def finalise at line 95, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(SequenceSegment, self).finalise()
+        if _v is not None: write(_filter(_v))
+        # 
+        for segment in VFFSL(SL,"childSegments",True): # generated from line 99, col 3
+            _v = VFFSL(SL,"segment.finalise",True) # u'$segment.finalise' on line 100, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'$segment.finalise')) # from line 100, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # SequenceSegment.tmpl
+        # 
+        # Created by Graham Dennis on 2008-03-18.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+''')
+        # 
+        #   Description of template
+        write(u'''
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_SequenceSegment= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(SequenceSegment, '_initCheetahAttributes'):
+    templateAPIClass = getattr(SequenceSegment, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(SequenceSegment)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=SequenceSegment()).run()
+
+
diff --git a/xpdeint/Segments/SequenceSegment.tmpl b/xpdeint/Segments/SequenceSegment.tmpl
new file mode 100644
index 0000000..ac0b01a
--- /dev/null
+++ b/xpdeint/Segments/SequenceSegment.tmpl
@@ -0,0 +1,104 @@
+@*
+SequenceSegment.tmpl
+
+Created by Graham Dennis on 2008-03-18.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Segments._Segment
+ at from xpdeint.CallOnceGuards import callOncePerInstanceGuard
+
+@*
+  Description of template
+*@
+ at def description: segment $segmentNumber (Sequence)
+
+ at def segmentFunctionBody($function)
+  @#
+  @set $extraIndent = 0
+  @if $localCycles > 1
+// Initialise child segments
+${allocate}@slurp
+${initialise}@slurp
+for (unsigned long _cycle = 0; _cycle < ${localCycles}; _cycle++) {
+    @set $extraIndent = 2
+  @end if
+  @#
+${callChildSegments(function), extraIndent=extraIndent}@slurp
+  @#
+  @if $localCycles > 1
+}
+    @set $extraIndent = 0
+// Finalise child segments
+${finalise}@slurp
+${free}@slurp
+  @end if
+  @#
+ at end def
+
+ at def callChildSegments($function)
+  @#
+  @for $segment in $childSegments
+${segment.functions['segment'].call(parentFunction=function)}
+  @end for
+  @#
+ at end def
+
+@@callOncePerInstanceGuard
+ at def allocate
+  @#
+  @super
+  @#
+  @for $segment in $childSegments
+$segment.allocate at slurp
+  @end for
+  @#
+ at end def
+
+@@callOncePerInstanceGuard
+ at def free
+  @#
+  @super
+  @#
+  @for $segment in $childSegments
+$segment.free at slurp
+  @end for
+  @#
+ at end def
+
+@@callOncePerInstanceGuard
+ at def initialise
+  @#
+  @super
+  @#
+  @for $segment in $childSegments
+$segment.initialise at slurp
+  @end for
+  @#
+ at end def
+
+@@callOncePerInstanceGuard
+ at def finalise
+  @#
+  @super
+  @#
+  @for $segment in $childSegments
+$segment.finalise at slurp
+  @end for
+  @#
+ at end def
+
diff --git a/xpdeint/Segments/TopLevelSequenceElement.py b/xpdeint/Segments/TopLevelSequenceElement.py
new file mode 100644
index 0000000..34293f3
--- /dev/null
+++ b/xpdeint/Segments/TopLevelSequenceElement.py
@@ -0,0 +1,319 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Segments.SequenceSegment import SequenceSegment
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.096215
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Segments/TopLevelSequenceElement.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class TopLevelSequenceElement(SequenceSegment):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(TopLevelSequenceElement, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: segment $segmentNumber (Top level sequence) at line 30, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''segment ''')
+        _v = VFFSL(SL,"segmentNumber",True) # u'$segmentNumber' on line 30, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'$segmentNumber')) # from line 30, col 27.
+        write(u''' (Top level sequence)''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def functionImplementations(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def functionImplementations at line 32, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  Make this empty as the content of the top-level sequence will be written by
+        #  a simulation driver
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def topLevelSequenceInnerContent(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def topLevelSequenceInnerContent at line 39, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"propagationDimension",True) # u'$propagationDimension' on line 41, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'$propagationDimension')) # from line 41, col 1.
+        write(u''' = 0.0;
+''')
+        # 
+        write(u'''
+''')
+        fieldsNotToInitialise = set()
+        for momentGroup in VFFSL(SL,"momentGroups",True): # generated from line 45, col 3
+            #  Initialise the raw vector
+            _v = VFN(VFN(VFFSL(SL,"momentGroup.rawVector",True),"functions",True)['initialise'],"call",False)() # u"${momentGroup.rawVector.functions['initialise'].call()}" on line 47, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u"${momentGroup.rawVector.functions['initialise'].call()}")) # from line 47, col 1.
+            write(u'''
+''')
+            #  Don't call the initialise method as that will cause
+            #  its aliases to be initialised, which is bad.
+            fieldsNotToInitialise.add(momentGroup.outputField)
+        # 
+        vectorsToInitialise = set()
+        for field in [f for f in VFFSL(SL,"fields",True) if f not in fieldsNotToInitialise]: # generated from line 54, col 3
+            vectorsToInitialise.update([v for v in field.managedVectors if not (v.isComputed or v.isNoise)])
+        # 
+        for vector in self.evaluationOrderForVectors(vectorsToInitialise, static = True): # generated from line 58, col 3
+            if vector.isComputed: # generated from line 59, col 5
+                #  Computed vectors were explicitly removed from the set of vectors that need
+                #  initialisation. The only way we can get one now is if one of the other vectors depends on this
+                #  vector. In this case, we must provide the information the other vector is requiring. To do this,
+                #  we must evaluate the vector, not initialise it.
+                _v = VFN(VFN(VFFSL(SL,"vector",True),"functions",True)['evaluate'],"call",False)() # u"${vector.functions['evaluate'].call()}" on line 64, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u"${vector.functions['evaluate'].call()}")) # from line 64, col 1.
+                write(u'''
+''')
+            else: # generated from line 65, col 5
+                _v = VFFSL(SL,"vector.initialise",True) # u'${vector.initialise}' on line 66, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.initialise}')) # from line 66, col 1.
+        # 
+        for momentGroup in VFFSL(SL,"momentGroups",True): # generated from line 70, col 3
+            #  We only need to set the sample index for the propagation dimension
+            #  and only if this moment group has the propagation dimension as one
+            #  of its dimensions
+            if not VFN(VFFSL(SL,"momentGroup.outputField",True),"hasDimensionName",False)(VFFSL(SL,"propagationDimension",True)): # generated from line 74, col 5
+                continue
+            write(u'''_''')
+            _v = VFFSL(SL,"momentGroup.outputField.id",True) # u'${momentGroup.outputField.id}' on line 77, col 2
+            if _v is not None: write(_filter(_v, rawExpr=u'${momentGroup.outputField.id}')) # from line 77, col 2.
+            write(u'''_index_''')
+            _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 77, col 38
+            if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 77, col 38.
+            write(u''' = 0;
+''')
+        # 
+        for momentGroup in filter(lambda x: x.requiresInitialSample, VFFSL(SL,"momentGroups",True)): # generated from line 80, col 3
+            write(u'''_mg''')
+            _v = VFFSL(SL,"momentGroup.number",True) # u'${momentGroup.number}' on line 81, col 4
+            if _v is not None: write(_filter(_v, rawExpr=u'${momentGroup.number}')) # from line 81, col 4.
+            write(u'''_sample();
+''')
+        # 
+        _v = VFFSL(SL,"segmentFunctionBody",False)(function=None) # u'${segmentFunctionBody(function=None)}' on line 84, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${segmentFunctionBody(function=None)}')) # from line 84, col 1.
+        # 
+        write(u'''
+''')
+        for momentGroup in VFFSL(SL,"momentGroups",True): # generated from line 87, col 3
+            write(u'''_mg''')
+            _v = VFFSL(SL,"momentGroup.number",True) # u'${momentGroup.number}' on line 88, col 4
+            if _v is not None: write(_filter(_v, rawExpr=u'${momentGroup.number}')) # from line 88, col 4.
+            write(u'''_process();
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # TopLevelSequenceElement.tmpl
+        # 
+        # Created by Graham Dennis on 2007-08-27.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+''')
+        assert VFFSL(SL,"segmentNumber",True) == 0
+        write(u'''
+''')
+        # 
+        #   Description of template
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    globalNameSpaceName = "topLevelSequence"
+
+    _mainCheetahMethod_for_TopLevelSequenceElement= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(TopLevelSequenceElement, '_initCheetahAttributes'):
+    templateAPIClass = getattr(TopLevelSequenceElement, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(TopLevelSequenceElement)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=TopLevelSequenceElement()).run()
+
+
diff --git a/xpdeint/Segments/TopLevelSequenceElement.tmpl b/xpdeint/Segments/TopLevelSequenceElement.tmpl
new file mode 100644
index 0000000..8e6e885
--- /dev/null
+++ b/xpdeint/Segments/TopLevelSequenceElement.tmpl
@@ -0,0 +1,91 @@
+@*
+TopLevelSequenceElement.tmpl
+
+Created by Graham Dennis on 2007-08-27.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Segments.SequenceSegment
+
+ at assert $segmentNumber == 0
+ at attr $globalNameSpaceName = "topLevelSequence"
+
+@*
+  Description of template
+*@
+ at def description: segment $segmentNumber (Top level sequence)
+
+ at def functionImplementations
+  @#
+  @# Make this empty as the content of the top-level sequence will be written by
+  @# a simulation driver
+  @#
+ at end def
+
+ at def topLevelSequenceInnerContent
+  @#
+$propagationDimension = 0.0;
+  @#
+
+  @set $fieldsNotToInitialise = set()
+  @for $momentGroup in $momentGroups
+    @# Initialise the raw vector
+${momentGroup.rawVector.functions['initialise'].call()}
+    @# Don't call the initialise method as that will cause
+    @# its aliases to be initialised, which is bad.
+    @silent fieldsNotToInitialise.add(momentGroup.outputField)
+  @end for
+  @#
+  @set $vectorsToInitialise = set()
+  @for field in [f for f in $fields if f not in fieldsNotToInitialise]
+    @silent vectorsToInitialise.update([v for v in field.managedVectors if not (v.isComputed or v.isNoise)])
+  @end for
+  @#
+  @for vector in self.evaluationOrderForVectors(vectorsToInitialise, static = True)
+    @if vector.isComputed
+      @# Computed vectors were explicitly removed from the set of vectors that need
+      @# initialisation. The only way we can get one now is if one of the other vectors depends on this
+      @# vector. In this case, we must provide the information the other vector is requiring. To do this,
+      @# we must evaluate the vector, not initialise it.
+${vector.functions['evaluate'].call()}
+    @else
+${vector.initialise}@slurp
+    @end if
+  @end for
+  @#
+  @for $momentGroup in $momentGroups
+    @# We only need to set the sample index for the propagation dimension
+    @# and only if this moment group has the propagation dimension as one
+    @# of its dimensions
+    @if not $momentGroup.outputField.hasDimensionName($propagationDimension)
+      @continue
+    @end if
+_${momentGroup.outputField.id}_index_${propagationDimension} = 0;
+  @end for
+  @#
+  @for $momentGroup in filter(lambda x: x.requiresInitialSample, $momentGroups)
+_mg${momentGroup.number}_sample();
+  @end for
+  @#
+${segmentFunctionBody(function=None)}@slurp
+  @#
+
+  @for $momentGroup in $momentGroups
+_mg${momentGroup.number}_process();
+  @end for  
+  @#
+ at end def
diff --git a/xpdeint/Segments/_BreakpointSegment.py b/xpdeint/Segments/_BreakpointSegment.py
new file mode 100644
index 0000000..34e94cd
--- /dev/null
+++ b/xpdeint/Segments/_BreakpointSegment.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_BreakpointSegment.py
+
+Created by Graham Dennis on 2008-03-15.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Segments._Segment import _Segment
+from xpdeint.ParserException import ParserException
+
+from xpdeint.Utilities import lazy_property
+
+class _BreakpointSegment (_Segment):
+  def __init__(self, *args, **KWs):
+    _Segment.__init__(self, *args, **KWs)
+    
+    self.filename = None
+    self.field = None
+    self.outputGroups = 1
+  
+  @lazy_property
+  def outputComponents(self):
+    result = []
+    for vector in self.orderedDependencies:
+      for componentName in vector.components:
+        result.append(componentName + 'R')
+        if vector.type == 'complex':
+          result.append(componentName + 'I')
+    return result
+  
+  def bindNamedVectors(self):
+    super(_Segment, self).bindNamedVectors()
+    
+    aVector = list(self.dependencies)[0]
+    for vector in self.dependencies:
+      if not vector.field.dimensions == aVector.field.dimensions:
+        raise ParserException(self.xmlElement, "All vectors for a breakpoint element must be have the same dimensions.\n"
+                                               "The conflicting vectors are: '%s' and '%s'." % (vector.name, aVector.name))
+    self.field = aVector.field
+    # We rely on a constant order for our dependencies when writing out
+    self.orderedDependencies = list(self.dependencies)
+  
+  def preflight(self):
+    super(_Segment, self).preflight()
+    
+    if self.dependenciesEntity.xmlElement.hasAttribute('basis'):
+      spaceString = self.dependenciesEntity.xmlElement.getAttribute('basis')
+      self.breakpointBasis = \
+        self.field.basisFromString(
+          self.dependenciesEntity.xmlElement.getAttribute('basis'),
+          xmlElement = self.dependenciesEntity.xmlElement
+        )
+    else:
+      self.breakpointBasis = self.field.defaultCoordinateBasis
+    
+    # Use the output format used for output if one isn't specified
+    if not self.hasattr('outputFormat'):
+      self.outputFormat = type(self.getVar('features')['Output'].outputFormat)(
+        parent = self,
+        **self.argumentsToTemplateConstructors
+      )
+    self._children.append(self.outputFormat)
+    
+    if self.outputFormat.name == 'hdf5':
+      # HDF5 doesn't like writing out data when the order of dimensions in the file and
+      # in memory aren't the same. It's slow. So we make sure that we sample in the same
+      # order that we would write out to file. But only for HDF5 as this requires extra
+      # MPI Transpose operations at each sample.
+      driver = self._driver
+      self.breakpointBasis = driver.canonicalBasisForBasis(self.breakpointBasis, noTranspose = True)
+    
+    self.registerVectorsRequiredInBasis(self.dependencies, self.breakpointBasis)
+    
+  
+
diff --git a/xpdeint/Segments/_FilterSegment.py b/xpdeint/Segments/_FilterSegment.py
new file mode 100644
index 0000000..eca0969
--- /dev/null
+++ b/xpdeint/Segments/_FilterSegment.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_FilterSegment.py
+
+Created by Graham Dennis on 2008-03-13.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Segments._Segment import _Segment
+
+class _FilterSegment (_Segment):
+  def __init__(self, *args, **KWs):
+    _Segment.__init__(self, *args, **KWs)
+    
+    self.operatorContainers = []
+  
+  @property
+  def children(self):
+    children = super(_FilterSegment, self).children
+    children.extend(self.operatorContainers)
+    return children
+  
+
diff --git a/xpdeint/Segments/_Segment.py b/xpdeint/Segments/_Segment.py
new file mode 100644
index 0000000..1b3aa30
--- /dev/null
+++ b/xpdeint/Segments/_Segment.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_Segment.py
+
+This contains all the pure-python code for segments
+
+Created by Graham Dennis on 2007-10-18.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.ScriptElement import ScriptElement
+
+from xpdeint.Function import Function
+from xpdeint.Utilities import lazy_property
+from xpdeint.CallOnceGuards import callOncePerInstanceGuard
+
+class _Segment (ScriptElement):
+  def __init__(self, *args, **KWs):
+    if not 'parent' in KWs: KWs['parent'] = self.simulation
+    ScriptElement.__init__(self, *args, **KWs)
+    
+    self.segmentNumber = len(filter(lambda x: isinstance(x, _Segment), self.getVar('templates'))) - 1
+    self._childSegments = []
+    self.parentSegment = None
+    self.localCycles = 1
+    self.name = 'segment' + str(self.segmentNumber)
+    self._id = self.name # Override the id as the segments have unique numbering
+    
+    self.functions['segment'] = Function(name = '_segment' + str(self.segmentNumber),
+                                         args = [], 
+                                         implementation = self.segmentFunctionBody)
+    
+  
+  @property
+  def childSegments(self):
+    return self._childSegments[:]
+  
+  @lazy_property
+  def totalCycles(self):
+    currSegment = self
+    totalCycles = 1
+    while currSegment:
+      totalCycles *= currSegment.localCycles
+      currSegment = currSegment.parentSegment
+    return totalCycles
+  
+  def addSegment(self, seg):
+    self._childSegments.append(seg)
+    seg.parentSegment = self
+  
+  @callOncePerInstanceGuard
+  def allocate(self):   return super(_Segment, self).allocate()
+  @callOncePerInstanceGuard
+  def free(self):       return super(_Segment, self).free()
+  
+  @callOncePerInstanceGuard
+  def initialise(self): return super(_Segment, self).initialise()
+  @callOncePerInstanceGuard
+  def finalise(self):   return super(_Segment, self).finalise()
+
diff --git a/xpdeint/Segments/__init__.py b/xpdeint/Segments/__init__.py
new file mode 100644
index 0000000..792d600
--- /dev/null
+++ b/xpdeint/Segments/__init__.py
@@ -0,0 +1 @@
+#
diff --git a/xpdeint/Simulation.py b/xpdeint/Simulation.py
new file mode 100644
index 0000000..188a64b
--- /dev/null
+++ b/xpdeint/Simulation.py
@@ -0,0 +1,405 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.ScriptElement import ScriptElement
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.105078
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Simulation.tmpl'
+__CHEETAH_srcLastModified__ = 'Thu Jun  6 17:05:13 2013'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class Simulation(ScriptElement):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(Simulation, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def logFunctionInnerContent(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def logFunctionInnerContent at line 209, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''if (logLevel & (_ERROR_LOG_LEVEL | _WARNING_LOG_LEVEL)) \\
+    printf("%s:%i: ", __FILE__, __LINE__); \\
+printf(__VA_ARGS__); \\
+fflush(stdout); \\
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # Simulation.tmpl
+        # 
+        # Created by Graham Dennis on 2007-08-23.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        # 
+        # 
+        # 
+        #  First check we have at least Cheetah version 2.0.1
+        if __CHEETAH_versionTuple__ < (2, 0, 1, 'final', 0): # generated from line 29, col 1
+            raise AssertionError("xmds2 requires at least Cheetah version "
+                               "2.0.1. You currently have %s." % __CHEETAH_version__)
+        # 
+        # 
+        #  Base simulation template
+        write(u'''// ********************************************************
+// simulation logging
+
+#define _SAMPLE_LOG_LEVEL             (1 << 0)
+#define _SEGMENT_LOG_LEVEL            (1 << 1)
+#define _PATH_LOG_LEVEL               (1 << 2)
+#define _SIMULATION_LOG_LEVEL         (1 << 3)
+#define _WARNING_LOG_LEVEL            (1 << 4)
+#define _ERROR_LOG_LEVEL              (1 << 5)
+#define _NO_ERROR_TERMINATE_LOG_LEVEL (1 << 6)
+#define _ALL_LOG_LEVELS        _SAMPLE_LOG_LEVEL|_SEGMENT_LOG_LEVEL|_PATH_LOG_LEVEL|_SIMULATION_LOG_LEVEL|_WARNING_LOG_LEVEL|_ERROR_LOG_LEVEL|_NO_ERROR_TERMINATE_LOG_LEVEL
+#define _LOG_LEVELS_BEING_LOGGED (''')
+        _v = VFN(VFFSL(SL,"features",True)['Driver'],"logLevelsBeingLogged",True) # u"${features['Driver'].logLevelsBeingLogged}" on line 47, col 35
+        if _v is not None: write(_filter(_v, rawExpr=u"${features['Driver'].logLevelsBeingLogged}")) # from line 47, col 35.
+        write(u''')
+
+#include <stdio.h>
+
+''')
+        featureOrdering = ['Driver']
+        write(u'''#define _LOG(logLevel, ...) \\
+  do { \\
+    if (logLevel & _LOG_LEVELS_BEING_LOGGED) { \\
+''')
+        dict = {'extraIndent': 0}
+        write(u'''      ''')
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('logFunctionBegin', VFFSL(SL,"featureOrdering",True), VFFSL(SL,"dict",True)) # u"${insertCodeForFeatures('logFunctionBegin', $featureOrdering, $dict), autoIndent=True}" on line 56, col 7
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeatures('logFunctionBegin', $featureOrdering, $dict), autoIndent=True}")) # from line 56, col 7.
+        extraIndent = dict['extraIndent']
+        write(u'''      ''')
+        _v = VFFSL(SL,"logFunctionInnerContent",True) # u'${logFunctionInnerContent, autoIndent=True, extraIndent=extraIndent}' on line 58, col 7
+        if _v is not None: write(_filter(_v, autoIndent=True, extraIndent=extraIndent, rawExpr=u'${logFunctionInnerContent, autoIndent=True, extraIndent=extraIndent}')) # from line 58, col 7.
+        write(u'''      ''')
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('logFunctionEnd', VFFSL(SL,"featureOrdering",True), VFFSL(SL,"dict",True)) # u"${insertCodeForFeaturesInReverseOrder('logFunctionEnd', $featureOrdering, $dict), autoIndent=True}" on line 59, col 7
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeaturesInReverseOrder('logFunctionEnd', $featureOrdering, $dict), autoIndent=True}")) # from line 59, col 7.
+        write(u"""      if (logLevel & (_ERROR_LOG_LEVEL | _NO_ERROR_TERMINATE_LOG_LEVEL)) \\
+        exit(logLevel == _ERROR_LOG_LEVEL); \\
+    } \\
+  } while (0)
+
+// ********************************************************
+// simulation includes
+
+#include <xpdeint_platform.h>
+#include <cmath>
+#include <string>
+#include <cstring>
+#include <fstream>
+#include <sstream>
+#include <cstdlib>
+
+#if CFG_OSAPI == CFG_OSAPI_POSIX // These are POSIX headers (i.e. non-windows)
+  #include <sys/time.h>
+#endif // POSIX
+
+#ifdef __APPLE__
+  #include <Availability.h>
+  #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
+    #define OS_OBJECT_USE_OBJC 0 // Don't make dispatch and xpc objects Objective-C objects.
+    #include <IOKit/pwr_mgt/IOPMLib.h> // To disable user idle sleep on Mountain Lion
+  #endif
+#endif
+
+#include <time.h>
+#include <list>
+#include <vector>
+#include <algorithm>
+
+""")
+        for child in VFFSL(SL,"children",True): # generated from line 93, col 1
+            #  Prevent writing zero-length defines
+            result = VFN(VFFSL(SL,"child",True),"implementationsForFunctionName",False)('includes')
+            if VFFSL(SL,"result",True) and not VFN(VFFSL(SL,"result",True),"isspace",False)(): # generated from line 96, col 3
+                _v = VFFSL(SL,"result",True) # u'${result}' on line 97, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${result}')) # from line 97, col 1.
+                write(u'''
+''')
+        write(u'''
+#define real Re
+#define imag Im
+
+#include <complex>
+
+#undef real
+#undef imag
+
+''')
+        realType = {'single': 'float', 'double': 'double'}[VFFSL(SL,"precision",True)]
+        write(u'''typedef long integer;
+typedef ''')
+        _v = VFFSL(SL,"realType",True) # u'${realType}' on line 112, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${realType}')) # from line 112, col 9.
+        write(u""" real;
+typedef std::complex<real> XMDSComplexType;
+
+#include <xpdeint.h>
+
+#define complex XMDSComplexType
+
+const complex i(0.0, 1.0);
+
+using namespace std;
+
+#if CFG_COMPILER == CFG_COMPILER_ICC
+  //
+  // Disable ICC's warning: label was declared but never referenced
+  //
+  #pragma warning ( disable : 177 )
+#endif
+
+inline void *xmds_malloc(size_t size);
+
+// ********************************************************
+// DEFINES
+// ********************************************************
+""")
+        #  only loop over the elements that implement the defines function
+        for child in VFFSL(SL,"children",True): # generated from line 136, col 1
+            #  Prevent writing zero-length defines
+            result = VFN(VFFSL(SL,"child",True),"implementationsForFunctionName",False)('defines')
+            if result and not result.isspace(): # generated from line 139, col 3
+                write(u'''
+// ********************************************************
+//   ''')
+                _v = VFFSL(SL,"child.description",True) # u'$child.description' on line 142, col 6
+                if _v is not None: write(_filter(_v, rawExpr=u'$child.description')) # from line 142, col 6.
+                write(u''' defines
+''')
+                _v = VFFSL(SL,"result",True) # u'$result' on line 143, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'$result')) # from line 143, col 1.
+        write(u'''
+
+// ********************************************************
+// GLOBALS
+// ********************************************************
+
+''')
+        #  only loop over the elements that implement the globals function
+        for child in VFFSL(SL,"children",True): # generated from line 153, col 1
+            #  Prevent writing zero-length globals
+            result = VFN(VFFSL(SL,"child",True),"implementationsForFunctionName",False)('globals')
+            if result and not result.isspace(): # generated from line 156, col 3
+                write(u'''
+// ********************************************************
+//   ''')
+                _v = VFFSL(SL,"child.description",True) # u'$child.description' on line 159, col 6
+                if _v is not None: write(_filter(_v, rawExpr=u'$child.description')) # from line 159, col 6.
+                write(u''' globals
+''')
+                _v = VFFSL(SL,"result",True) # u'$result' on line 160, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'$result')) # from line 160, col 1.
+        write(u'''
+
+// ********************************************************
+// FUNCTION PROTOTYPES
+// ********************************************************
+''')
+        #  only loop over the elements that implement the prototypes function
+        for child in VFFSL(SL,"children",True): # generated from line 169, col 1
+            #  Prevent writing zero-length globals
+            result = VFN(VFFSL(SL,"child",True),"implementationsForFunctionName",False)('functionPrototypes')
+            if result and not result.isspace(): # generated from line 172, col 3
+                write(u'''
+// ********************************************************
+//   ''')
+                _v = VFFSL(SL,"child.description",True) # u'$child.description' on line 175, col 6
+                if _v is not None: write(_filter(_v, rawExpr=u'$child.description')) # from line 175, col 6.
+                write(u''' function prototypes
+''')
+                _v = VFFSL(SL,"result",True) # u'$result' on line 176, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'$result')) # from line 176, col 1.
+        write(u'''
+// ********************************************************
+// MAIN ROUTINE
+// ********************************************************
+''')
+        _v = VFFSL(SL,"features.Driver.mainRoutine",True) # u'$features.Driver.mainRoutine' on line 183, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'$features.Driver.mainRoutine')) # from line 183, col 1.
+        write(u'''
+// ********************************************************
+// FUNCTION IMPLEMENTATIONS
+// ********************************************************
+
+inline void *xmds_malloc(size_t size)
+{
+  void *retPointer = _xmds_malloc(size);
+  if ( !retPointer )
+    _LOG(_ERROR_LOG_LEVEL, "ERROR: Couldn\'t allocate %zu bytes of memory!", size);
+  return retPointer;
+}
+
+''')
+        #  only loop over the elements that implement the prototypes function
+        for child in VFFSL(SL,"children",True): # generated from line 198, col 1
+            #  Prevent writing zero-length function implementations
+            result = VFN(VFFSL(SL,"child",True),"implementationsForFunctionName",False)('functionImplementations')
+            if result and not result.isspace(): # generated from line 201, col 3
+                write(u'''
+// ********************************************************
+//   ''')
+                _v = VFFSL(SL,"child.description",True) # u'$child.description' on line 204, col 6
+                if _v is not None: write(_filter(_v, rawExpr=u'$child.description')) # from line 204, col 6.
+                write(u''' function implementations
+''')
+                _v = VFFSL(SL,"result",True) # u'$result' on line 205, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'$result')) # from line 205, col 1.
+        write(u'''
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    name = ''
+
+    id = ''
+
+    _mainCheetahMethod_for_Simulation= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(Simulation, '_initCheetahAttributes'):
+    templateAPIClass = getattr(Simulation, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(Simulation)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=Simulation()).run()
+
+
diff --git a/xpdeint/Simulation.tmpl b/xpdeint/Simulation.tmpl
new file mode 100644
index 0000000..245f9bf
--- /dev/null
+++ b/xpdeint/Simulation.tmpl
@@ -0,0 +1,216 @@
+@*
+Simulation.tmpl
+
+Created by Graham Dennis on 2007-08-23.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+@#
+ at extends xpdeint.ScriptElement
+@#
+ at attr $name = ''
+ at attr $id = ''
+@#
+@# First check we have at least Cheetah version 2.0.1
+ at if __CHEETAH_versionTuple__ < (2, 0, 1, 'final', 0)
+  @silent raise AssertionError("xmds2 requires at least Cheetah version "
+                               "2.0.1. You currently have %s." % __CHEETAH_version__)
+ at end if
+@#
+@#
+@# Base simulation template
+// ********************************************************
+// simulation logging
+
+#define _SAMPLE_LOG_LEVEL             (1 << 0)
+#define _SEGMENT_LOG_LEVEL            (1 << 1)
+#define _PATH_LOG_LEVEL               (1 << 2)
+#define _SIMULATION_LOG_LEVEL         (1 << 3)
+#define _WARNING_LOG_LEVEL            (1 << 4)
+#define _ERROR_LOG_LEVEL              (1 << 5)
+#define _NO_ERROR_TERMINATE_LOG_LEVEL (1 << 6)
+#define _ALL_LOG_LEVELS        _SAMPLE_LOG_LEVEL|_SEGMENT_LOG_LEVEL|_PATH_LOG_LEVEL|_SIMULATION_LOG_LEVEL|_WARNING_LOG_LEVEL|_ERROR_LOG_LEVEL|_NO_ERROR_TERMINATE_LOG_LEVEL
+#define _LOG_LEVELS_BEING_LOGGED (${features['Driver'].logLevelsBeingLogged})
+
+#include <stdio.h>
+
+ at set $featureOrdering = ['Driver']
+#define _LOG(logLevel, ...) \
+  do { \
+    if (logLevel & _LOG_LEVELS_BEING_LOGGED) { \
+  @set $dict = {'extraIndent': 0}
+      ${insertCodeForFeatures('logFunctionBegin', $featureOrdering, $dict), autoIndent=True}@slurp
+  @set $extraIndent = dict['extraIndent']
+      ${logFunctionInnerContent, autoIndent=True, extraIndent=extraIndent}@slurp
+      ${insertCodeForFeaturesInReverseOrder('logFunctionEnd', $featureOrdering, $dict), autoIndent=True}@slurp
+      if (logLevel & (_ERROR_LOG_LEVEL | _NO_ERROR_TERMINATE_LOG_LEVEL)) \
+        exit(logLevel == _ERROR_LOG_LEVEL); \
+    } \
+  } while (0)
+
+// ********************************************************
+// simulation includes
+
+#include <xpdeint_platform.h>
+#include <cmath>
+#include <string>
+#include <cstring>
+#include <fstream>
+#include <sstream>
+#include <cstdlib>
+
+#if CFG_OSAPI == CFG_OSAPI_POSIX // These are POSIX headers (i.e. non-windows)
+  #include <sys/time.h>
+#endif // POSIX
+
+#ifdef __APPLE__
+  #include <Availability.h>
+  #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
+    #define OS_OBJECT_USE_OBJC 0 // Don't make dispatch and xpc objects Objective-C objects.
+    #include <IOKit/pwr_mgt/IOPMLib.h> // To disable user idle sleep on Mountain Lion
+  #endif
+#endif
+
+#include <time.h>
+#include <list>
+#include <vector>
+#include <algorithm>
+
+ at for $child in $children
+  @# Prevent writing zero-length defines
+  @set $result = $child.implementationsForFunctionName('includes')
+  @if $result and not $result.isspace()
+${result}@slurp
+
+  @end if
+ at end for
+
+#define real Re
+#define imag Im
+
+#include <complex>
+
+#undef real
+#undef imag
+
+ at set $realType = {'single': 'float', 'double': 'double'}[$precision]
+typedef long integer;
+typedef ${realType} real;
+typedef std::complex<real> XMDSComplexType;
+
+#include <xpdeint.h>
+
+#define complex XMDSComplexType
+
+const complex i(0.0, 1.0);
+
+using namespace std;
+
+#if CFG_COMPILER == CFG_COMPILER_ICC
+  //
+  // Disable ICC's warning: label was declared but never referenced
+  //
+  #pragma warning ( disable : 177 )
+#endif
+
+inline void *xmds_malloc(size_t size);
+
+// ********************************************************
+// DEFINES
+// ********************************************************
+@# only loop over the elements that implement the defines function
+ at for $child in $children
+  @# Prevent writing zero-length defines
+  @set $result = $child.implementationsForFunctionName('defines')
+  @if result and not result.isspace()
+
+// ********************************************************
+//   $child.description defines
+$result at slurp
+  @end if
+ at end for
+
+
+// ********************************************************
+// GLOBALS
+// ********************************************************
+
+@# only loop over the elements that implement the globals function
+ at for $child in $children
+  @# Prevent writing zero-length globals
+  @set $result = $child.implementationsForFunctionName('globals')
+  @if result and not result.isspace()
+
+// ********************************************************
+//   $child.description globals
+$result at slurp
+  @end if
+ at end for
+
+
+// ********************************************************
+// FUNCTION PROTOTYPES
+// ********************************************************
+@# only loop over the elements that implement the prototypes function
+ at for $child in $children
+  @# Prevent writing zero-length globals
+  @set $result = $child.implementationsForFunctionName('functionPrototypes')
+  @if result and not result.isspace()
+
+// ********************************************************
+//   $child.description function prototypes
+$result at slurp
+  @end if
+ at end for
+
+// ********************************************************
+// MAIN ROUTINE
+// ********************************************************
+$features.Driver.mainRoutine at slurp
+
+// ********************************************************
+// FUNCTION IMPLEMENTATIONS
+// ********************************************************
+
+inline void *xmds_malloc(size_t size)
+{
+  void *retPointer = _xmds_malloc(size);
+  if ( !retPointer )
+    _LOG(_ERROR_LOG_LEVEL, "ERROR: Couldn't allocate %zu bytes of memory!", size);
+  return retPointer;
+}
+
+@# only loop over the elements that implement the prototypes function
+ at for $child in $children
+  @# Prevent writing zero-length function implementations
+  @set $result = $child.implementationsForFunctionName('functionImplementations')
+  @if result and not result.isspace()
+
+// ********************************************************
+//   $child.description function implementations
+$result at slurp
+  @end if
+ at end for
+
+ at def logFunctionInnerContent
+  @#
+if (logLevel & (_ERROR_LOG_LEVEL | _WARNING_LOG_LEVEL)) \
+    printf("%s:%i: ", __FILE__, __LINE__); \
+printf(__VA_ARGS__); \
+fflush(stdout); \
+  @#
+ at end def
diff --git a/xpdeint/SimulationDrivers/DistributedMPIDriver.py b/xpdeint/SimulationDrivers/DistributedMPIDriver.py
new file mode 100644
index 0000000..e80b473
--- /dev/null
+++ b/xpdeint/SimulationDrivers/DistributedMPIDriver.py
@@ -0,0 +1,1079 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.SimulationDrivers._DistributedMPIDriver import _DistributedMPIDriver
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.311083
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/SimulationDrivers/DistributedMPIDriver.tmpl'
+__CHEETAH_srcLastModified__ = 'Tue Jul 24 13:07:03 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class DistributedMPIDriver(_DistributedMPIDriver):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(DistributedMPIDriver, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Distributed MPI Simulation Driver at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Distributed MPI Simulation Driver''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def preAllocation(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def preAllocation($dict) at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''  ''')
+        _v = VFFSL(SL,"distributedTransform.setLocalLatticeAndOffsetVariables",True) # u'${distributedTransform.setLocalLatticeAndOffsetVariables, autoIndent=True}' on line 28, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${distributedTransform.setLocalLatticeAndOffsetVariables, autoIndent=True}')) # from line 28, col 3.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def mainRoutine(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def mainRoutine at line 32, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''int main(int argc, char **argv)
+{
+  MPI_Init(&argc, &argv);
+  MPI_Comm_size(MPI_COMM_WORLD, &_size);
+  MPI_Comm_rank(MPI_COMM_WORLD, &_rank);
+
+  ''')
+        _v = VFFSL(SL,"mainRoutineInnerContent",True) # u'${mainRoutineInnerContent, autoIndent=True}' on line 40, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${mainRoutineInnerContent, autoIndent=True}')) # from line 40, col 3.
+        write(u'''  
+  MPI_Finalize();
+  
+  return 0;
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def setVectorAllocSizes(self, vectors, **KWS):
+
+
+
+        ## CHEETAH: generated from @def setVectorAllocSizes($vectors) at line 49, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(DistributedMPIDriver, self).setVectorAllocSizes(vectors)
+        if _v is not None: write(_filter(_v))
+        # 
+        _v = VFN(VFFSL(SL,"distributedTransform",True),"setVectorAllocSizes",False)(vectors) # u'${distributedTransform.setVectorAllocSizes(vectors)}' on line 53, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${distributedTransform.setVectorAllocSizes(vectors)}')) # from line 53, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def loopOverFieldInBasisWithVectorsAndInnerContentEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def loopOverFieldInBasisWithVectorsAndInnerContentEnd($dict) at line 57, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        vectorOverrides = dict['vectorOverrides']
+        indexOverrides = dict['indexOverrides']
+        field = dict['field']
+        basis = dict['basis']
+        # 
+        for vector in VFFSL(SL,"vectorOverrides",True): # generated from line 64, col 3
+            if not (field.isDistributed and not vector.field.isDistributed): # generated from line 65, col 5
+                #  If we aren't integrating over an MPI dimension, then everything is as usual.
+                continue
+            #  We did integrate over the MPI dimension, so we need to run MPI_Allreduce to combine the results.
+            arrayName = ''.join([u'_active_',str(VFFSL(SL,"vector.id",True))])
+            size = VFN(VFFSL(SL,"vector",True),"sizeInBasisInReals",False)(basis)
+            # 
+            #  If we have any dimension overrides, then we don't want to add up the entire field
+            for dimRepName in indexOverrides.iterkeys(): # generated from line 74, col 5
+                if vector.field in indexOverrides[dimRepName]: # generated from line 75, col 7
+                    dimReps = [dimRep for dimRep in vector.field.inBasis(basis) if dimRep.canonicalName == dimRepName]
+                    if not dimReps: # generated from line 77, col 9
+                        continue
+                    assert len(dimReps) == 1
+                    vectorDimRep = dimReps[0]
+                    indexOverride = indexOverrides[dimRepName][vector.field]
+                    arrayName = ''.join([str(VFFSL(SL,"arrayName",True)),u' + ',str(VFFSL(SL,"indexOverride",True)),u' * ',str(VFN(VFFSL(SL,"vector.field",True),"localPointsInDimensionsAfterDimRepInBasis",False)(vectorDimRep, basis)),u' * _',str(VFFSL(SL,"vector.id",True)),u'_ncomponents'])
+                    size = size + ' / ' + vectorDimRep.localLattice
+            write(u'''MPI_Allreduce(MPI_IN_PLACE, ''')
+            _v = VFFSL(SL,"arrayName",True) # u'$arrayName' on line 87, col 29
+            if _v is not None: write(_filter(_v, rawExpr=u'$arrayName')) # from line 87, col 29.
+            write(u''', ''')
+            _v = VFFSL(SL,"size",True) # u'$size' on line 87, col 41
+            if _v is not None: write(_filter(_v, rawExpr=u'$size')) # from line 87, col 41.
+            write(u''',
+              MPI_REAL, MPI_SUM, MPI_COMM_WORLD);
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def findMax(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def findMax($dict) at line 93, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        variable = dict['variable']
+        count = dict['count']
+        type = dict.get('type', 'real').upper()
+        op = dict.get('op', 'max').upper()
+        write(u'''MPI_Allreduce(MPI_IN_PLACE, ''')
+        _v = VFFSL(SL,"variable",True) # u'$variable' on line 99, col 29
+        if _v is not None: write(_filter(_v, rawExpr=u'$variable')) # from line 99, col 29.
+        write(u''', ''')
+        _v = VFFSL(SL,"count",True) # u'$count' on line 99, col 40
+        if _v is not None: write(_filter(_v, rawExpr=u'$count')) # from line 99, col 40.
+        write(u''', MPI_''')
+        _v = VFFSL(SL,"type",True) # u'${type}' on line 99, col 52
+        if _v is not None: write(_filter(_v, rawExpr=u'${type}')) # from line 99, col 52.
+        write(u''', MPI_''')
+        _v = VFFSL(SL,"op",True) # u'${op}' on line 99, col 65
+        if _v is not None: write(_filter(_v, rawExpr=u'${op}')) # from line 99, col 65.
+        write(u''', MPI_COMM_WORLD);
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def binaryWriteOutBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def binaryWriteOutBegin($dict) at line 104, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''// Only write to file if we are rank 0, as we cannot assume
+// that the nodes have equal access to the filesystem
+if (_rank == 0) {
+''')
+        dict['extraIndent'] += 2
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def binaryWriteOutEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def binaryWriteOutEnd($dict) at line 113, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        field = dict['field']
+        basis = dict['basis']
+        dependentVariables = dict['dependentVariables']
+        # 
+        dict['extraIndent'] -= 2
+        # 
+        write(u'''}
+''')
+        if not all([field.hasDimensionName(dimName) for dimName in VFFSL(SL,"distributedDimensionNames",True)]): # generated from line 122, col 3
+            #  If we don't have all the MPI dimensions, then the data will be local.
+            return _dummyTrans and trans.response().getvalue() or ""
+        write(u"""else {
+  // We are some other rank that isn't 0, so we need to send our data to rank 0.
+  ptrdiff_t _sending_var;
+  
+""")
+        for shadowVariable in VFFSL(SL,"shadowedVariablesForField",False)(field): # generated from line 130, col 3
+            write(u'''  _sending_var = ''')
+            _v = VFFSL(SL,"shadowVariable",True) # u'$shadowVariable' on line 131, col 18
+            if _v is not None: write(_filter(_v, rawExpr=u'$shadowVariable')) # from line 131, col 18.
+            write(u''';
+  MPI_Ssend(&_sending_var, sizeof(ptrdiff_t), MPI_BYTE, 0, 0, MPI_COMM_WORLD);
+''')
+        write(u'''  
+''')
+        #  Note that a variable corresponds to an array with given component names
+        for variable in VFFSL(SL,"dependentVariables",True): # generated from line 136, col 3
+            write(u'''  _sending_var = ''')
+            _v = VFN(VFFSL(SL,"variable.vector",True),"sizeInBasisInReals",False)(basis) # u'${variable.vector.sizeInBasisInReals(basis)}' on line 137, col 18
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.vector.sizeInBasisInReals(basis)}')) # from line 137, col 18.
+            write(u''';
+  MPI_Ssend(&_sending_var, sizeof(ptrdiff_t), MPI_BYTE, 0, 0, MPI_COMM_WORLD);
+  if (_sending_var == 0)
+    goto _BINARY_WRITE_OUT_END;
+  MPI_Ssend(''')
+            _v = VFFSL(SL,"variable.arrayName",True) # u'${variable.arrayName}' on line 141, col 13
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.arrayName}')) # from line 141, col 13.
+            write(u''', ''')
+            _v = VFN(VFFSL(SL,"variable.vector",True),"sizeInBasisInReals",False)(basis) # u'${variable.vector.sizeInBasisInReals(basis)}' on line 141, col 36
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.vector.sizeInBasisInReals(basis)}')) # from line 141, col 36.
+            write(u''', MPI_REAL, 0, 0, MPI_COMM_WORLD);
+  
+''')
+        write(u'''_BINARY_WRITE_OUT_END:;
+}
+
+MPI_Barrier(MPI_COMM_WORLD);
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def binaryWriteOutWriteDataBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def binaryWriteOutWriteDataBegin($dict) at line 151, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        field = dict['field']
+        dependentVariables = dict['dependentVariables']
+        # 
+        if not all([field.hasDimensionName(dimName) for dimName in VFFSL(SL,"distributedDimensionNames",True)]): # generated from line 156, col 3
+            #  If we don't have all the MPI dimensions, then the data will be local.
+            return
+        # 
+        for shadowVariable in VFFSL(SL,"shadowedVariablesForField",False)(field): # generated from line 161, col 3
+            write(u'''ptrdiff_t _my''')
+            _v = VFFSL(SL,"shadowVariable",True) # u'${shadowVariable}' on line 162, col 14
+            if _v is not None: write(_filter(_v, rawExpr=u'${shadowVariable}')) # from line 162, col 14.
+            write(u''' = ''')
+            _v = VFFSL(SL,"shadowVariable",True) # u'${shadowVariable}' on line 162, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${shadowVariable}')) # from line 162, col 34.
+            write(u''';
+''')
+        # 
+        write(u'''
+''')
+        for variable in VFFSL(SL,"dependentVariables",True): # generated from line 166, col 3
+            _v = VFFSL(SL,"variable.vector.type",True) # u'${variable.vector.type}' on line 167, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.vector.type}')) # from line 167, col 1.
+            write(u'''* _local''')
+            _v = VFFSL(SL,"variable.arrayName",True) # u'${variable.arrayName}' on line 167, col 32
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.arrayName}')) # from line 167, col 32.
+            write(u''';
+''')
+            _v = VFFSL(SL,"variable.vector.type",True) # u'${variable.vector.type}' on line 168, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.vector.type}')) # from line 168, col 1.
+            write(u'''* _backup''')
+            _v = VFFSL(SL,"variable.arrayName",True) # u'${variable.arrayName}' on line 168, col 33
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.arrayName}')) # from line 168, col 33.
+            write(u''' = ''')
+            _v = VFFSL(SL,"variable.arrayName",True) # u'${variable.arrayName}' on line 168, col 57
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.arrayName}')) # from line 168, col 57.
+            write(u''';
+''')
+        write(u'''
+for (long _dataForRank = 0; _dataForRank < _size; _dataForRank++) {
+''')
+        for shadowVariable in VFFSL(SL,"shadowedVariablesForField",False)(field): # generated from line 172, col 3
+            write(u'''  ptrdiff_t ''')
+            _v = VFFSL(SL,"shadowVariable",True) # u'${shadowVariable}' on line 173, col 13
+            if _v is not None: write(_filter(_v, rawExpr=u'${shadowVariable}')) # from line 173, col 13.
+            write(u''';
+''')
+        write(u'''  ptrdiff_t _local_vector_size;
+  
+  if (_dataForRank == 0) {
+''')
+        for shadowVariable in VFFSL(SL,"shadowedVariablesForField",False)(field): # generated from line 178, col 3
+            write(u'''    ''')
+            _v = VFFSL(SL,"shadowVariable",True) # u'${shadowVariable}' on line 179, col 5
+            if _v is not None: write(_filter(_v, rawExpr=u'${shadowVariable}')) # from line 179, col 5.
+            write(u''' = _my''')
+            _v = VFFSL(SL,"shadowVariable",True) # u'${shadowVariable}' on line 179, col 28
+            if _v is not None: write(_filter(_v, rawExpr=u'${shadowVariable}')) # from line 179, col 28.
+            write(u''';
+''')
+        write(u'''    
+  } else {
+    MPI_Status status;
+''')
+        for shadowVariable in VFFSL(SL,"shadowedVariablesForField",False)(field): # generated from line 184, col 3
+            write(u'''    MPI_Recv(&''')
+            _v = VFFSL(SL,"shadowVariable",True) # u'${shadowVariable}' on line 185, col 15
+            if _v is not None: write(_filter(_v, rawExpr=u'${shadowVariable}')) # from line 185, col 15.
+            write(u''', sizeof(ptrdiff_t), MPI_BYTE, _dataForRank, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
+''')
+        write(u'''    
+    // Now allocate the space needed locally, and receive the entire buffer
+''')
+        for variable in VFFSL(SL,"dependentVariables",True): # generated from line 189, col 3
+            write(u'''    MPI_Recv(&_local_vector_size, sizeof(ptrdiff_t), MPI_BYTE, _dataForRank, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
+    if (_local_vector_size == 0)
+      continue;
+    
+    _local''')
+            _v = VFFSL(SL,"variable.arrayName",True) # u'${variable.arrayName}' on line 194, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.arrayName}')) # from line 194, col 11.
+            write(u''' = (''')
+            _v = VFFSL(SL,"variable.vector.type",True) # u'${variable.vector.type}' on line 194, col 36
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.vector.type}')) # from line 194, col 36.
+            write(u'''*) xmds_malloc(sizeof(real) * _local_vector_size);
+    MPI_Recv(_local''')
+            _v = VFFSL(SL,"variable.arrayName",True) # u'${variable.arrayName}' on line 195, col 20
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.arrayName}')) # from line 195, col 20.
+            write(u''', _local_vector_size,
+             MPI_REAL, _dataForRank, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
+    ''')
+            _v = VFFSL(SL,"variable.arrayName",True) # u'${variable.arrayName}' on line 197, col 5
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.arrayName}')) # from line 197, col 5.
+            write(u''' = _local''')
+            _v = VFFSL(SL,"variable.arrayName",True) # u'${variable.arrayName}' on line 197, col 35
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.arrayName}')) # from line 197, col 35.
+            write(u''';
+    
+''')
+        write(u'''  }
+''')
+        dict['extraIndent'] += 2
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def binaryWriteOutWriteDataEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def binaryWriteOutWriteDataEnd($dict) at line 205, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        field = dict['field']
+        dict['extraIndent'] -= 2
+        dependentVariables = dict['dependentVariables']
+        # 
+        if not all([field.hasDimensionName(dimName) for dimName in VFFSL(SL,"distributedDimensionNames",True)]): # generated from line 211, col 3
+            #  If we don't have all the MPI dimensions, then the data will be local.
+            return
+        # 
+        write(u'''  
+  if (_dataForRank != 0) {
+''')
+        for variable in VFFSL(SL,"dependentVariables",True): # generated from line 218, col 3
+            write(u'''    xmds_free(_local''')
+            _v = VFFSL(SL,"variable.arrayName",True) # u'${variable.arrayName}' on line 219, col 21
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.arrayName}')) # from line 219, col 21.
+            write(u''');
+''')
+        write(u'''  }
+} // End looping over ranks
+''')
+        for variable in VFFSL(SL,"dependentVariables",True): # generated from line 223, col 3
+            _v = VFFSL(SL,"variable.arrayName",True) # u'${variable.arrayName}' on line 224, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.arrayName}')) # from line 224, col 1.
+            write(u''' = _backup''')
+            _v = VFFSL(SL,"variable.arrayName",True) # u'${variable.arrayName}' on line 224, col 32
+            if _v is not None: write(_filter(_v, rawExpr=u'${variable.arrayName}')) # from line 224, col 32.
+            write(u''';
+''')
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeDataHDF5ModifyLoopContents(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def writeDataHDF5ModifyLoopContents($dict) at line 230, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        dimRepOrdering = dict['dimRepOrdering']
+        #  We only care about elements that are reordered
+        dimRepOrdering = [(fileDimIndex, memDimIndex, dimRep)                           for fileDimIndex, memDimIndex, dimRep in dimRepOrdering if fileDimIndex != memDimIndex]
+        #  If dimRepOrdering is empty, we have nothing to do
+        if not dimRepOrdering: # generated from line 237, col 3
+            return
+        # 
+        writeLoopContents = dict['writeLoopContents']
+        ## START CAPTURE REGION: _23931602 newWriteLoopContents at line 242, col 3 in the source.
+        _orig_trans_23931602 = trans
+        _wasBuffering_23931602 = self._CHEETAH__isBuffering
+        self._CHEETAH__isBuffering = True
+        trans = _captureCollector_23931602 = DummyTransaction()
+        write = _captureCollector_23931602.response().write
+        for fileDimIndex, memDimIndex, dimRep in dimRepOrdering: # generated from line 243, col 5
+            write(u'''hsize_t file_start_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 244, col 20
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 244, col 20.
+            write(u''' = file_start[''')
+            _v = VFFSL(SL,"fileDimIndex",True) # u'$fileDimIndex' on line 244, col 48
+            if _v is not None: write(_filter(_v, rawExpr=u'$fileDimIndex')) # from line 244, col 48.
+            write(u'''];
+hsize_t mem_start_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 245, col 19
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 245, col 19.
+            write(u''' = mem_start[''')
+            _v = VFFSL(SL,"memDimIndex",True) # u'$memDimIndex' on line 245, col 46
+            if _v is not None: write(_filter(_v, rawExpr=u'$memDimIndex')) # from line 245, col 46.
+            write(u'''];
+hsize_t count_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 246, col 15
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 246, col 15.
+            write(u''' = mem_count[''')
+            _v = VFFSL(SL,"memDimIndex",True) # u'$memDimIndex' on line 246, col 42
+            if _v is not None: write(_filter(_v, rawExpr=u'$memDimIndex')) # from line 246, col 42.
+            write(u'''];
+mem_count[''')
+            _v = VFFSL(SL,"memDimIndex",True) # u'$memDimIndex' on line 247, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'$memDimIndex')) # from line 247, col 11.
+            write(u'''] = 1;
+
+''')
+        # 
+        _v = VFFSL(SL,"hdf5DataCopyLoops",False)(dimRepOrdering[:], writeLoopContents) # u'${hdf5DataCopyLoops(dimRepOrdering[:], writeLoopContents)}' on line 251, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${hdf5DataCopyLoops(dimRepOrdering[:], writeLoopContents)}')) # from line 251, col 1.
+        for fileDimIndex, memDimIndex, dimRep in dimRepOrdering: # generated from line 252, col 5
+            write(u'''
+file_start[''')
+            _v = VFFSL(SL,"fileDimIndex",True) # u'$fileDimIndex' on line 254, col 12
+            if _v is not None: write(_filter(_v, rawExpr=u'$fileDimIndex')) # from line 254, col 12.
+            write(u'''] = file_start_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 254, col 40
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 254, col 40.
+            write(u''';
+mem_start[''')
+            _v = VFFSL(SL,"memDimIndex",True) # u'$memDimIndex' on line 255, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'$memDimIndex')) # from line 255, col 11.
+            write(u'''] = mem_start_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 255, col 37
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 255, col 37.
+            write(u''';
+mem_count[''')
+            _v = VFFSL(SL,"memDimIndex",True) # u'$memDimIndex' on line 256, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'$memDimIndex')) # from line 256, col 11.
+            write(u'''] = count_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 256, col 33
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 256, col 33.
+            write(u''';
+''')
+        trans = _orig_trans_23931602
+        write = trans.response().write
+        self._CHEETAH__isBuffering = _wasBuffering_23931602 
+        newWriteLoopContents = _captureCollector_23931602.response().getvalue()
+        del _orig_trans_23931602
+        del _captureCollector_23931602
+        del _wasBuffering_23931602
+        # 
+        dict['writeLoopContents'] = newWriteLoopContents
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def hdf5DataCopyLoops(self, remainingDimReps, writeLoopContents, **KWS):
+
+
+
+        ## CHEETAH: generated from @def hdf5DataCopyLoops(remainingDimReps, writeLoopContents) at line 264, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        if not remainingDimReps: # generated from line 265, col 3
+            _v = VFFSL(SL,"writeLoopContents",True) # u'${writeLoopContents}' on line 266, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${writeLoopContents}')) # from line 266, col 1.
+        else: # generated from line 267, col 3
+            fileDimIndex, memDimIndex, dimRep = remainingDimReps.pop(0)
+            write(u'''for (hsize_t _i''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 269, col 16
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 269, col 16.
+            write(u''' = 0; _i''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 269, col 38
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 269, col 38.
+            write(u''' < count_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 269, col 61
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 269, col 61.
+            write(u'''; _i''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 269, col 79
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 269, col 79.
+            write(u'''++) {
+  file_start[''')
+            _v = VFFSL(SL,"fileDimIndex",True) # u'$fileDimIndex' on line 270, col 14
+            if _v is not None: write(_filter(_v, rawExpr=u'$fileDimIndex')) # from line 270, col 14.
+            write(u'''] = file_start_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 270, col 42
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 270, col 42.
+            write(u''' + _i''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 270, col 61
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 270, col 61.
+            write(u''';
+  mem_start[''')
+            _v = VFFSL(SL,"memDimIndex",True) # u'$memDimIndex' on line 271, col 13
+            if _v is not None: write(_filter(_v, rawExpr=u'$memDimIndex')) # from line 271, col 13.
+            write(u'''] = mem_start_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 271, col 39
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 271, col 39.
+            write(u''' + _i''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 271, col 58
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 271, col 58.
+            write(u''';
+  
+  ''')
+            _v = VFFSL(SL,"hdf5DataCopyLoops",False)(remainingDimReps, writeLoopContents) # u'${hdf5DataCopyLoops(remainingDimReps, writeLoopContents), autoIndent=True}' on line 273, col 3
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${hdf5DataCopyLoops(remainingDimReps, writeLoopContents), autoIndent=True}')) # from line 273, col 3.
+            write(u'''}
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def evaluateNoiseVectorBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def evaluateNoiseVectorBegin($dict) at line 278, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        noiseVector = dict['caller']
+        # 
+        if noiseVector.field.isDistributed: # generated from line 282, col 3
+            #  If the field is distributed, then the noise
+            #  will need to vary along the MPI dimension, so all is
+            #  OK.
+            return
+        # 
+        #  This means that the noise field doesn't contain the MPI dimension.
+        #  As a result, the noise vector should be identical
+        write(u"""if (_rank == 0) {
+  // This noise is for a field that isn't distributed, so we should
+  // make sure the noise is the same on all ranks
+""")
+        dict['extraIndent'] += 2
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def evaluateNoiseVectorEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def evaluateNoiseVectorEnd($dict) at line 298, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        noiseVector = dict['caller']
+        # 
+        if noiseVector.field.isDistributed: # generated from line 302, col 3
+            #  If the field is distributed, then the noise
+            #  will need to vary along the MPI dimension, so all is
+            #  OK.
+            return
+        # 
+        write(u'''}
+// Broadcast the noises to other nodes
+MPI_Bcast(_active_''')
+        _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 311, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 311, col 19.
+        write(u''', ''')
+        _v = VFN(VFFSL(SL,"noiseVector",True),"sizeInBasisInReals",False)(noiseVector.initialBasis) # u'${noiseVector.sizeInBasisInReals(noiseVector.initialBasis)}' on line 311, col 38
+        if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.sizeInBasisInReals(noiseVector.initialBasis)}')) # from line 311, col 38.
+        write(u''', MPI_REAL, 0, MPI_COMM_WORLD);
+
+''')
+        dict['extraIndent'] -= 2
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def runtimeSeedGenerationBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def runtimeSeedGenerationBegin($dict) at line 317, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''if (_rank == 0) {
+  // Only generate random seeds on the first rank, then distribute to all.
+''')
+        dict['extraIndent'] += 2
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def runtimeSeedGenerationEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def runtimeSeedGenerationEnd($dict) at line 325, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        generator = dict['caller']
+        dict['extraIndent'] -= 2
+        write(u'''}
+// Broadcast seeds to other nodes
+MPI_Bcast(''')
+        _v = VFFSL(SL,"generator.generatorName",True) # u'${generator.generatorName}' on line 331, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'${generator.generatorName}')) # from line 331, col 11.
+        write(u'''_seeds, ''')
+        _v = VFFSL(SL,"generator.seedCount",True) # u'${generator.seedCount}' on line 331, col 45
+        if _v is not None: write(_filter(_v, rawExpr=u'${generator.seedCount}')) # from line 331, col 45.
+        write(u''', MPI_UINT32_T, 0, MPI_COMM_WORLD);
+
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def openXSILFile(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def openXSILFile($dict) at line 336, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''// Only let rank 0 do the writing to disk
+if (_rank != 0)
+  return NULL;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # DistributedMPIDriver.tmpl
+        # 
+        # Created by Graham Dennis on 2008-03-28.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_DistributedMPIDriver= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(DistributedMPIDriver, '_initCheetahAttributes'):
+    templateAPIClass = getattr(DistributedMPIDriver, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(DistributedMPIDriver)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=DistributedMPIDriver()).run()
+
+
diff --git a/xpdeint/SimulationDrivers/DistributedMPIDriver.tmpl b/xpdeint/SimulationDrivers/DistributedMPIDriver.tmpl
new file mode 100644
index 0000000..800854e
--- /dev/null
+++ b/xpdeint/SimulationDrivers/DistributedMPIDriver.tmpl
@@ -0,0 +1,343 @@
+@*
+DistributedMPIDriver.tmpl
+
+Created by Graham Dennis on 2008-03-28.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.SimulationDrivers._DistributedMPIDriver
+
+ at def description: Distributed MPI Simulation Driver
+
+ at def preAllocation($dict)
+  @#
+  ${distributedTransform.setLocalLatticeAndOffsetVariables, autoIndent=True}@slurp
+  @#
+ at end def
+
+ at def mainRoutine
+  @#
+int main(int argc, char **argv)
+{
+  MPI_Init(&argc, &argv);
+  MPI_Comm_size(MPI_COMM_WORLD, &_size);
+  MPI_Comm_rank(MPI_COMM_WORLD, &_rank);
+
+  ${mainRoutineInnerContent, autoIndent=True}@slurp
+  
+  MPI_Finalize();
+  
+  return 0;
+}
+  @#
+ at end def
+
+ at def setVectorAllocSizes($vectors)
+  @#
+  @super(vectors)
+  @#
+${distributedTransform.setVectorAllocSizes(vectors)}@slurp
+  @#
+ at end def
+
+ at def loopOverFieldInBasisWithVectorsAndInnerContentEnd($dict)
+  @#
+  @set $vectorOverrides = dict['vectorOverrides']
+  @set $indexOverrides = dict['indexOverrides']
+  @set $field = dict['field']
+  @set $basis = dict['basis']
+  @#
+  @for $vector in $vectorOverrides
+    @if not (field.isDistributed and not vector.field.isDistributed)
+      @# If we aren't integrating over an MPI dimension, then everything is as usual.
+      @continue
+    @end if
+    @# We did integrate over the MPI dimension, so we need to run MPI_Allreduce to combine the results.
+    @set $arrayName = c'_active_${vector.id}'
+    @set $size = $vector.sizeInBasisInReals(basis)
+    @#
+    @# If we have any dimension overrides, then we don't want to add up the entire field
+    @for $dimRepName in indexOverrides.iterkeys()
+      @if vector.field in indexOverrides[dimRepName]
+        @set dimReps = [dimRep for dimRep in vector.field.inBasis(basis) if dimRep.canonicalName == dimRepName]
+        @if not dimReps
+          @continue
+        @end if
+        @assert len(dimReps) == 1
+        @set vectorDimRep = dimReps[0]
+        @set $indexOverride = indexOverrides[dimRepName][vector.field]
+        @set $arrayName = c'${arrayName} + ${indexOverride} * ${vector.field.localPointsInDimensionsAfterDimRepInBasis(vectorDimRep, basis)} * _${vector.id}_ncomponents'
+        @set $size = size + ' / ' + vectorDimRep.localLattice
+      @end if
+    @end for
+MPI_Allreduce(MPI_IN_PLACE, $arrayName, $size,
+              MPI_REAL, MPI_SUM, MPI_COMM_WORLD);
+  @end for
+  @#
+ at end def
+
+ at def findMax($dict)
+  @#
+  @set $variable = dict['variable']
+  @set $count = dict['count']
+  @set $type = dict.get('type', 'real').upper()
+  @set $op = dict.get('op', 'max').upper()
+MPI_Allreduce(MPI_IN_PLACE, $variable, $count, MPI_${type}, MPI_${op}, MPI_COMM_WORLD);
+  @#
+ at end def
+
+
+ at def binaryWriteOutBegin($dict)
+  @#
+// Only write to file if we are rank 0, as we cannot assume
+// that the nodes have equal access to the filesystem
+if (_rank == 0) {
+  @set $dict['extraIndent'] += 2
+  @#
+ at end def
+
+ at def binaryWriteOutEnd($dict)
+  @#
+  @set $field = dict['field']
+  @set $basis = dict['basis']
+  @set $dependentVariables = dict['dependentVariables']
+  @#
+  @set $dict['extraIndent'] -= 2
+  @#
+}
+  @if not all([field.hasDimensionName(dimName) for dimName in $distributedDimensionNames])
+    @# If we don't have all the MPI dimensions, then the data will be local.
+    @stop
+  @end if
+else {
+  // We are some other rank that isn't 0, so we need to send our data to rank 0.
+  ptrdiff_t _sending_var;
+  
+  @for $shadowVariable in $shadowedVariablesForField(field)
+  _sending_var = $shadowVariable;
+  MPI_Ssend(&_sending_var, sizeof(ptrdiff_t), MPI_BYTE, 0, 0, MPI_COMM_WORLD);
+  @end for
+  
+  @# Note that a variable corresponds to an array with given component names
+  @for $variable in $dependentVariables
+  _sending_var = ${variable.vector.sizeInBasisInReals(basis)};
+  MPI_Ssend(&_sending_var, sizeof(ptrdiff_t), MPI_BYTE, 0, 0, MPI_COMM_WORLD);
+  if (_sending_var == 0)
+    goto _BINARY_WRITE_OUT_END;
+  MPI_Ssend(${variable.arrayName}, ${variable.vector.sizeInBasisInReals(basis)}, MPI_REAL, 0, 0, MPI_COMM_WORLD);
+  
+  @end for
+_BINARY_WRITE_OUT_END:;
+}
+
+MPI_Barrier(MPI_COMM_WORLD);
+  @#
+ at end def
+
+ at def binaryWriteOutWriteDataBegin($dict)
+  @#
+  @set $field = dict['field']
+  @set $dependentVariables = dict['dependentVariables']
+  @#
+  @if not all([field.hasDimensionName(dimName) for dimName in $distributedDimensionNames])
+    @# If we don't have all the MPI dimensions, then the data will be local.
+    @return
+  @end if
+  @#
+  @for $shadowVariable in $shadowedVariablesForField(field)
+ptrdiff_t _my${shadowVariable} = ${shadowVariable};
+  @end for
+  @#
+
+  @for $variable in $dependentVariables
+${variable.vector.type}* _local${variable.arrayName};
+${variable.vector.type}* _backup${variable.arrayName} = ${variable.arrayName};
+  @end for
+
+for (long _dataForRank = 0; _dataForRank < _size; _dataForRank++) {
+  @for $shadowVariable in $shadowedVariablesForField(field)
+  ptrdiff_t ${shadowVariable};
+  @end for
+  ptrdiff_t _local_vector_size;
+  
+  if (_dataForRank == 0) {
+  @for $shadowVariable in $shadowedVariablesForField(field)
+    ${shadowVariable} = _my${shadowVariable};
+  @end for
+    
+  } else {
+    MPI_Status status;
+  @for $shadowVariable in $shadowedVariablesForField(field)
+    MPI_Recv(&${shadowVariable}, sizeof(ptrdiff_t), MPI_BYTE, _dataForRank, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
+  @end for
+    
+    // Now allocate the space needed locally, and receive the entire buffer
+  @for $variable in $dependentVariables
+    MPI_Recv(&_local_vector_size, sizeof(ptrdiff_t), MPI_BYTE, _dataForRank, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
+    if (_local_vector_size == 0)
+      continue;
+    
+    _local${variable.arrayName} = (${variable.vector.type}*) xmds_malloc(sizeof(real) * _local_vector_size);
+    MPI_Recv(_local${variable.arrayName}, _local_vector_size,
+             MPI_REAL, _dataForRank, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
+    ${variable.arrayName} = _local${variable.arrayName};
+    
+  @end for
+  }
+  @set $dict['extraIndent'] += 2
+  @#
+ at end def
+
+ at def binaryWriteOutWriteDataEnd($dict)
+  @#
+  @set $field = dict['field']
+  @set $dict['extraIndent'] -= 2
+  @set $dependentVariables = dict['dependentVariables']
+  @#
+  @if not all([field.hasDimensionName(dimName) for dimName in $distributedDimensionNames])
+    @# If we don't have all the MPI dimensions, then the data will be local.
+    @return
+  @end if
+  @#
+  
+  if (_dataForRank != 0) {
+  @for $variable in $dependentVariables
+    xmds_free(_local${variable.arrayName});
+  @end for
+  }
+} // End looping over ranks
+  @for $variable in $dependentVariables
+${variable.arrayName} = _backup${variable.arrayName};
+  @end for
+
+  @#
+ at end def
+
+ at def writeDataHDF5ModifyLoopContents($dict)
+  @#
+  @set $dimRepOrdering = dict['dimRepOrdering']
+  @# We only care about elements that are reordered
+  @set $dimRepOrdering = [(fileDimIndex, memDimIndex, dimRep) \
+                          for fileDimIndex, memDimIndex, dimRep in dimRepOrdering if fileDimIndex != memDimIndex]
+  @# If dimRepOrdering is empty, we have nothing to do
+  @if not dimRepOrdering
+    @return
+  @end if
+  @#
+  @set $writeLoopContents = dict['writeLoopContents']
+  @capture newWriteLoopContents
+    @for fileDimIndex, memDimIndex, dimRep in dimRepOrdering
+hsize_t file_start_${dimRep.name} = file_start[$fileDimIndex];
+hsize_t mem_start_${dimRep.name} = mem_start[$memDimIndex];
+hsize_t count_${dimRep.name} = mem_count[$memDimIndex];
+mem_count[$memDimIndex] = 1;
+
+    @end for
+    @#
+${hdf5DataCopyLoops(dimRepOrdering[:], writeLoopContents)}@slurp
+    @for fileDimIndex, memDimIndex, dimRep in dimRepOrdering
+
+file_start[$fileDimIndex] = file_start_${dimRep.name};
+mem_start[$memDimIndex] = mem_start_${dimRep.name};
+mem_count[$memDimIndex] = count_${dimRep.name};
+    @end for
+  @end capture
+  @#
+  @silent dict['writeLoopContents'] = newWriteLoopContents
+  @#
+ at end def
+
+ at def hdf5DataCopyLoops(remainingDimReps, writeLoopContents)
+  @if not remainingDimReps
+${writeLoopContents}@slurp
+  @else
+    @set fileDimIndex, memDimIndex, dimRep = remainingDimReps.pop(0)
+for (hsize_t _i${dimRep.name} = 0; _i${dimRep.name} < count_${dimRep.name}; _i${dimRep.name}++) {
+  file_start[$fileDimIndex] = file_start_${dimRep.name} + _i${dimRep.name};
+  mem_start[$memDimIndex] = mem_start_${dimRep.name} + _i${dimRep.name};
+  
+  ${hdf5DataCopyLoops(remainingDimReps, writeLoopContents), autoIndent=True}@slurp
+}
+  @end if
+ at end def
+
+ at def evaluateNoiseVectorBegin($dict)
+  @#
+  @set noiseVector = dict['caller']
+  @#
+  @if noiseVector.field.isDistributed
+    @# If the field is distributed, then the noise
+    @# will need to vary along the MPI dimension, so all is
+    @# OK.
+    @return
+  @end if
+  @#
+  @# This means that the noise field doesn't contain the MPI dimension.
+  @# As a result, the noise vector should be identical
+if (_rank == 0) {
+  // This noise is for a field that isn't distributed, so we should
+  // make sure the noise is the same on all ranks
+  @set $dict['extraIndent'] += 2
+  @#
+ at end def
+
+ at def evaluateNoiseVectorEnd($dict)
+  @#
+  @set noiseVector = dict['caller']
+  @#
+  @if noiseVector.field.isDistributed
+    @# If the field is distributed, then the noise
+    @# will need to vary along the MPI dimension, so all is
+    @# OK.
+    @return
+  @end if
+  @#
+}
+// Broadcast the noises to other nodes
+MPI_Bcast(_active_${noiseVector.id}, ${noiseVector.sizeInBasisInReals(noiseVector.initialBasis)}, MPI_REAL, 0, MPI_COMM_WORLD);
+
+  @set $dict['extraIndent'] -= 2
+  @#
+ at end def
+
+ at def runtimeSeedGenerationBegin($dict)
+  @#
+if (_rank == 0) {
+  // Only generate random seeds on the first rank, then distribute to all.
+  @set dict['extraIndent'] += 2
+  @#
+ at end def
+
+ at def runtimeSeedGenerationEnd($dict)
+  @#
+  @set generator = dict['caller']
+  @set dict['extraIndent'] -= 2
+}
+// Broadcast seeds to other nodes
+MPI_Bcast(${generator.generatorName}_seeds, ${generator.seedCount}, MPI_UINT32_T, 0, MPI_COMM_WORLD);
+
+  @#
+ at end def
+
+ at def openXSILFile($dict)
+  @#
+// Only let rank 0 do the writing to disk
+if (_rank != 0)
+  return NULL;
+  @#
+ at end def
+
diff --git a/xpdeint/SimulationDrivers/MPI.py b/xpdeint/SimulationDrivers/MPI.py
new file mode 100644
index 0000000..93f72fa
--- /dev/null
+++ b/xpdeint/SimulationDrivers/MPI.py
@@ -0,0 +1,358 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.ScriptElement import ScriptElement
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.140892
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/SimulationDrivers/MPI.tmpl'
+__CHEETAH_srcLastModified__ = 'Thu Mar 29 16:44:30 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class MPI(ScriptElement):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(MPI, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def includes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def includes at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(MPI, self).includes()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''#include <mpi.h>
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def defines(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def defines at line 34, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''#undef MPI_REAL
+#define MPI_REAL MPI_''')
+        _v = {'double': 'DOUBLE', 'single': 'FLOAT'}[VFFSL(SL,"precision",True)] # u"${{'double': 'DOUBLE', 'single': 'FLOAT'}[$precision]}" on line 36, col 22
+        if _v is not None: write(_filter(_v, rawExpr=u"${{'double': 'DOUBLE', 'single': 'FLOAT'}[$precision]}")) # from line 36, col 22.
+        write(u'''
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def globals at line 39, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(MPI, self).globals()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''int _rank, _size;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def logFunctionBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def logFunctionBegin($dict) at line 47, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  Insert code at the start of the _LOG function
+        # 
+        write(u'''if ((_rank == 0) || (logLevel & ~(_SIMULATION_LOG_LEVEL | _SEGMENT_LOG_LEVEL | _SAMPLE_LOG_LEVEL | _NO_ERROR_TERMINATE_LOG_LEVEL))) { \\
+  if (logLevel & ~(_SIMULATION_LOG_LEVEL | _SEGMENT_LOG_LEVEL | _SAMPLE_LOG_LEVEL | _NO_ERROR_TERMINATE_LOG_LEVEL)) \\
+    printf("Rank[%i]: ", _rank); \\
+''')
+        dict['extraIndent'] += 2
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def logFunctionEnd(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def logFunctionEnd($dict) at line 58, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        dict['extraIndent'] -= 2
+        write(u'''} \\
+if (logLevel & _ERROR_LOG_LEVEL) \\
+  MPI_Abort(MPI_COMM_WORLD, 1); \\
+else if (logLevel & _NO_ERROR_TERMINATE_LOG_LEVEL) \\
+  MPI_Finalize(); \\
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def seedOffset(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def seedOffset($dict) at line 69, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u''' + _rank''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # MPI.tmpl
+        # 
+        # Created by Graham Dennis on 2008-03-28.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    buildVariant = 'mpi'
+
+    _mainCheetahMethod_for_MPI= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(MPI, '_initCheetahAttributes'):
+    templateAPIClass = getattr(MPI, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(MPI)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=MPI()).run()
+
+
diff --git a/xpdeint/SimulationDrivers/MPI.tmpl b/xpdeint/SimulationDrivers/MPI.tmpl
new file mode 100644
index 0000000..ba9c3ca
--- /dev/null
+++ b/xpdeint/SimulationDrivers/MPI.tmpl
@@ -0,0 +1,74 @@
+@*
+MPI.tmpl
+
+Created by Graham Dennis on 2008-03-28.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.ScriptElement
+
+ at attr $buildVariant = 'mpi'
+
+ at def includes
+  @#
+  @super
+  @#
+#include <mpi.h>
+  @#
+ at end def
+
+ at def defines
+#undef MPI_REAL
+#define MPI_REAL MPI_${{'double': 'DOUBLE', 'single': 'FLOAT'}[$precision]}
+ at end def
+
+ at def globals
+  @#
+  @super
+  @#
+int _rank, _size;
+  @#
+ at end def
+
+ at def logFunctionBegin($dict)
+  @#
+  @# Insert code at the start of the _LOG function
+  @#
+if ((_rank == 0) || (logLevel & ~(_SIMULATION_LOG_LEVEL | _SEGMENT_LOG_LEVEL | _SAMPLE_LOG_LEVEL | _NO_ERROR_TERMINATE_LOG_LEVEL))) { \
+  if (logLevel & ~(_SIMULATION_LOG_LEVEL | _SEGMENT_LOG_LEVEL | _SAMPLE_LOG_LEVEL | _NO_ERROR_TERMINATE_LOG_LEVEL)) \
+    printf("Rank[%i]: ", _rank); \
+  @set $dict['extraIndent'] += 2
+  @#
+ at end def
+
+ at def logFunctionEnd($dict)
+  @#
+  @set $dict['extraIndent'] -= 2
+} \
+if (logLevel & _ERROR_LOG_LEVEL) \
+  MPI_Abort(MPI_COMM_WORLD, 1); \
+else if (logLevel & _NO_ERROR_TERMINATE_LOG_LEVEL) \
+  MPI_Finalize(); \
+  @#
+ at end def
+
+ at def seedOffset($dict)
+  @#
+ + _rank at slurp
+  @#
+ at end def
+
diff --git a/xpdeint/SimulationDrivers/MPIMultiPathDriver.py b/xpdeint/SimulationDrivers/MPIMultiPathDriver.py
new file mode 100644
index 0000000..4f7811c
--- /dev/null
+++ b/xpdeint/SimulationDrivers/MPIMultiPathDriver.py
@@ -0,0 +1,338 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.SimulationDrivers._MPIMultiPathDriver import _MPIMultiPathDriver
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.161057
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/SimulationDrivers/MPIMultiPathDriver.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class MPIMultiPathDriver(_MPIMultiPathDriver):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(MPIMultiPathDriver, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: MPI Multipath Simulation Driver at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''MPI Multipath Simulation Driver''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def mainRoutine(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def mainRoutine at line 29, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''int main(int argc, char **argv)
+{
+  MPI_Init(&argc, &argv);
+  MPI_Comm_size(MPI_COMM_WORLD, &_size);
+  MPI_Comm_rank(MPI_COMM_WORLD, &_rank);
+  
+  ''')
+        _v = VFFSL(SL,"mainRoutineInnerContent",True) # u'${mainRoutineInnerContent, autoIndent=True}' on line 37, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${mainRoutineInnerContent, autoIndent=True}')) # from line 37, col 3.
+        write(u'''  
+  MPI_Finalize();
+  
+  return 0;
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def topLevelSegmentFunctionImplementation(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def topLevelSegmentFunctionImplementation at line 47, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''void _segment0()
+{
+''')
+        #  And now insert the code for the features that apply in the top level sequence
+        featureOrdering = ['ErrorCheck', 'Stochastic']
+        dict = {'extraIndent': 0}
+        write(u'''  ''')
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('topLevelSequenceBegin', featureOrdering, dict) # u"${insertCodeForFeatures('topLevelSequenceBegin', featureOrdering, dict), autoIndent=True}" on line 54, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeatures('topLevelSequenceBegin', featureOrdering, dict), autoIndent=True}")) # from line 54, col 3.
+        extraIndent = dict['extraIndent']
+        write(u'''  
+  ''')
+        _v = VFFSL(SL,"topLevelSegmentPathLoop",True) # u'${topLevelSegmentPathLoop, autoIndent=True, extraIndent=extraIndent}' on line 57, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, extraIndent=extraIndent, rawExpr=u'${topLevelSegmentPathLoop, autoIndent=True, extraIndent=extraIndent}')) # from line 57, col 3.
+        write(u'''  
+  ''')
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('topLevelSequenceEnd', featureOrdering, dict) # u"${insertCodeForFeaturesInReverseOrder('topLevelSequenceEnd', featureOrdering, dict), autoIndent=True}" on line 59, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeaturesInReverseOrder('topLevelSequenceEnd', featureOrdering, dict), autoIndent=True}")) # from line 59, col 3.
+        write(u'''  
+''')
+        for mg in VFFSL(SL,"momentGroups",True): # generated from line 61, col 3
+            for vector in mg.outputField.managedVectors: # generated from line 62, col 5
+                arrayNames = [''.join([u'_',str(VFFSL(SL,"vector.id",True))])]
+                VFN(VFFSL(SL,"arrayNames",True),"extend",False)(VFFSL(SL,"vector.aliases",True))
+                for arrayName in arrayNames: # generated from line 65, col 7
+                    write(u'''  
+  if (_rank == 0)
+    MPI_Reduce(MPI_IN_PLACE, ''')
+                    _v = VFFSL(SL,"arrayName",True) # u'$arrayName' on line 68, col 30
+                    if _v is not None: write(_filter(_v, rawExpr=u'$arrayName')) # from line 68, col 30.
+                    write(u''', ''')
+                    _v = VFN(VFFSL(SL,"vector",True),"sizeInBasisInReals",False)(mg.outputBasis) # u'${vector.sizeInBasisInReals(mg.outputBasis)}' on line 68, col 42
+                    if _v is not None: write(_filter(_v, rawExpr=u'${vector.sizeInBasisInReals(mg.outputBasis)}')) # from line 68, col 42.
+                    write(u''',
+               MPI_REAL, MPI_SUM, 0, MPI_COMM_WORLD);
+  else
+    MPI_Reduce(''')
+                    _v = VFFSL(SL,"arrayName",True) # u'$arrayName' on line 71, col 16
+                    if _v is not None: write(_filter(_v, rawExpr=u'$arrayName')) # from line 71, col 16.
+                    write(u''', NULL, ''')
+                    _v = VFN(VFFSL(SL,"vector",True),"sizeInBasisInReals",False)(mg.outputBasis) # u'${vector.sizeInBasisInReals(mg.outputBasis)}' on line 71, col 34
+                    if _v is not None: write(_filter(_v, rawExpr=u'${vector.sizeInBasisInReals(mg.outputBasis)}')) # from line 71, col 34.
+                    write(u''',
+               MPI_REAL, MPI_SUM, 0, MPI_COMM_WORLD);
+''')
+        write(u'''}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeOutBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def writeOutBegin($dict) at line 80, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u"""// If we aren't rank 0, then we don't want to write anything.
+if (_rank != 0)
+  return;
+""")
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # MPIMultiPathDriver.tmpl
+        # 
+        # Created by Graham Dennis on 2008-02-25.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    pathLoopStart = '_rank'
+
+    pathLoopStep = '_size'
+
+    _mainCheetahMethod_for_MPIMultiPathDriver= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(MPIMultiPathDriver, '_initCheetahAttributes'):
+    templateAPIClass = getattr(MPIMultiPathDriver, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(MPIMultiPathDriver)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=MPIMultiPathDriver()).run()
+
+
diff --git a/xpdeint/SimulationDrivers/MPIMultiPathDriver.tmpl b/xpdeint/SimulationDrivers/MPIMultiPathDriver.tmpl
new file mode 100644
index 0000000..9a9de52
--- /dev/null
+++ b/xpdeint/SimulationDrivers/MPIMultiPathDriver.tmpl
@@ -0,0 +1,86 @@
+@*
+MPIMultiPathDriver.tmpl
+
+Created by Graham Dennis on 2008-02-25.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.SimulationDrivers._MPIMultiPathDriver
+
+ at def description: MPI Multipath Simulation Driver
+
+ at attr $pathLoopStart = '_rank'
+ at attr $pathLoopStep = '_size'
+
+ at def mainRoutine
+  @#
+int main(int argc, char **argv)
+{
+  MPI_Init(&argc, &argv);
+  MPI_Comm_size(MPI_COMM_WORLD, &_size);
+  MPI_Comm_rank(MPI_COMM_WORLD, &_rank);
+  
+  ${mainRoutineInnerContent, autoIndent=True}@slurp
+  
+  MPI_Finalize();
+  
+  return 0;
+}
+  @#
+ at end def
+
+
+ at def topLevelSegmentFunctionImplementation
+  @#
+void _segment0()
+{
+  @# And now insert the code for the features that apply in the top level sequence
+  @set $featureOrdering = ['ErrorCheck', 'Stochastic']
+  @set $dict = {'extraIndent': 0}
+  ${insertCodeForFeatures('topLevelSequenceBegin', featureOrdering, dict), autoIndent=True}@slurp
+  @set $extraIndent = dict['extraIndent']
+  
+  ${topLevelSegmentPathLoop, autoIndent=True, extraIndent=extraIndent}@slurp
+  
+  ${insertCodeForFeaturesInReverseOrder('topLevelSequenceEnd', featureOrdering, dict), autoIndent=True}@slurp
+  
+  @for mg in $momentGroups
+    @for vector in mg.outputField.managedVectors
+      @set $arrayNames = [c'_${vector.id}']
+      @silent $arrayNames.extend($vector.aliases)
+      @for arrayName in arrayNames
+  
+  if (_rank == 0)
+    MPI_Reduce(MPI_IN_PLACE, $arrayName, ${vector.sizeInBasisInReals(mg.outputBasis)},
+               MPI_REAL, MPI_SUM, 0, MPI_COMM_WORLD);
+  else
+    MPI_Reduce($arrayName, NULL, ${vector.sizeInBasisInReals(mg.outputBasis)},
+               MPI_REAL, MPI_SUM, 0, MPI_COMM_WORLD);
+      @end for
+    @end for
+  @end for
+}
+  @#
+ at end def
+
+ at def writeOutBegin($dict)
+  @#
+// If we aren't rank 0, then we don't want to write anything.
+if (_rank != 0)
+  return;
+  @#
+ at end def
diff --git a/xpdeint/SimulationDrivers/MultiPathDriver.py b/xpdeint/SimulationDrivers/MultiPathDriver.py
new file mode 100644
index 0000000..e02d485
--- /dev/null
+++ b/xpdeint/SimulationDrivers/MultiPathDriver.py
@@ -0,0 +1,516 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.SimulationDrivers._MultiPathDriver import _MultiPathDriver
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.243509
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/SimulationDrivers/MultiPathDriver.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class MultiPathDriver(_MultiPathDriver):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(MultiPathDriver, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Multipath Simulation Driver at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Multipath Simulation Driver''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def defines(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def defines at line 29, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(MultiPathDriver, self).defines()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''#define _n_paths ''')
+        _v = VFFSL(SL,"pathCount",True) # u'${pathCount}' on line 33, col 18
+        if _v is not None: write(_filter(_v, rawExpr=u'${pathCount}')) # from line 33, col 18.
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def topLevelSegmentFunctionImplementation(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def topLevelSegmentFunctionImplementation at line 37, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''void _segment0()
+{
+''')
+        #  And now insert the code for the features that apply in the top level sequence
+        featureOrdering = ['ErrorCheck', 'Stochastic']
+        dict = {'extraIndent': 0}
+        write(u'''  ''')
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('topLevelSequenceBegin', featureOrdering, dict) # u"${insertCodeForFeatures('topLevelSequenceBegin', featureOrdering, dict), autoIndent=True}" on line 44, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeatures('topLevelSequenceBegin', featureOrdering, dict), autoIndent=True}")) # from line 44, col 3.
+        extraIndent = dict['extraIndent']
+        write(u'''
+  ''')
+        _v = VFFSL(SL,"topLevelSegmentPathLoop",True) # u'${topLevelSegmentPathLoop, autoIndent=True, extraIndent=extraIndent}' on line 47, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, extraIndent=extraIndent, rawExpr=u'${topLevelSegmentPathLoop, autoIndent=True, extraIndent=extraIndent}')) # from line 47, col 3.
+        write(u'''
+  ''')
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('topLevelSequenceEnd', featureOrdering, dict) # u"${insertCodeForFeaturesInReverseOrder('topLevelSequenceEnd', featureOrdering, dict), autoIndent=True}" on line 49, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeaturesInReverseOrder('topLevelSequenceEnd', featureOrdering, dict), autoIndent=True}")) # from line 49, col 3.
+        write(u'''}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def topLevelSegmentPathLoop(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def topLevelSegmentPathLoop at line 54, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        #  Now loop over anything that can be initalised early and initialise them
+        #  so they don't allocate and free stuff for each path. This is done now
+        #  and not before the ErrorCheck and Stochastic Features because the
+        #  initialisation of IP operators will depend on the step size. It would be
+        #  possible to split this up into two stages of initialisation, but that
+        #  seems to me like it would be ugly.
+        #  
+        _v = VFFSL(SL,"topLevelSequence.allocate",True) # u'${topLevelSequence.allocate}' on line 63, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${topLevelSequence.allocate}')) # from line 63, col 1.
+        write(u'''
+''')
+        objectsNeedingInitialisation = [o for o in VFFSL(SL,"templates",True) if o.hasattr('canBeInitialisedEarly') and o.canBeInitialisedEarly]
+        for o in VFFSL(SL,"objectsNeedingInitialisation",True): # generated from line 66, col 3
+            _v = VFFSL(SL,"o.initialise",True) # u'${o.initialise}' on line 67, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${o.initialise}')) # from line 67, col 1.
+        # 
+        #  We must capture the finalisation of all the objects we initialised
+        #  to make sure they don't get finalised early. As that could lead to
+        #  NULL pointer dereferences, and that is bad.
+        # 
+        ## START CAPTURE REGION: _37828414 finalisationCode at line 74, col 3 in the source.
+        _orig_trans_37828414 = trans
+        _wasBuffering_37828414 = self._CHEETAH__isBuffering
+        self._CHEETAH__isBuffering = True
+        trans = _captureCollector_37828414 = DummyTransaction()
+        write = _captureCollector_37828414.response().write
+        for o in VFFSL(SL,"objectsNeedingInitialisation",True): # generated from line 75, col 5
+            _v = VFFSL(SL,"o.finalise",True) # u'${o.finalise}' on line 76, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${o.finalise}')) # from line 76, col 1.
+        write(u'''
+''')
+        _v = VFFSL(SL,"topLevelSequence.free",True) # u'${topLevelSequence.free}' on line 79, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${topLevelSequence.free}')) # from line 79, col 1.
+        trans = _orig_trans_37828414
+        write = trans.response().write
+        self._CHEETAH__isBuffering = _wasBuffering_37828414 
+        finalisationCode = _captureCollector_37828414.response().getvalue()
+        del _orig_trans_37828414
+        del _captureCollector_37828414
+        del _wasBuffering_37828414
+        write(u'''
+for (long _i0 = ''')
+        _v = VFFSL(SL,"pathLoopStart",True) # u'${pathLoopStart}' on line 82, col 17
+        if _v is not None: write(_filter(_v, rawExpr=u'${pathLoopStart}')) # from line 82, col 17.
+        write(u'''; _i0 < _n_paths; _i0+=''')
+        _v = VFFSL(SL,"pathLoopStep",True) # u'${pathLoopStep}' on line 82, col 56
+        if _v is not None: write(_filter(_v, rawExpr=u'${pathLoopStep}')) # from line 82, col 56.
+        write(u''') {
+  _LOG(_PATH_LOG_LEVEL, "Starting path %li\\n", _i0 + 1);
+  
+''')
+        for mg in VFFSL(SL,"momentGroups",True): # generated from line 85, col 3
+            write(u'''  ''')
+            _v = VFN(VFN(VFFSL(SL,"mg.rawVector",True),"functions",True)['initialise'],"call",False)() # u"${mg.rawVector.functions['initialise'].call(), autoIndent=True}" on line 86, col 3
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${mg.rawVector.functions['initialise'].call(), autoIndent=True}")) # from line 86, col 3.
+        write(u'''  
+  ''')
+        _v = VFFSL(SL,"topLevelSequence.topLevelSequenceInnerContent",True) # u'${topLevelSequence.topLevelSequenceInnerContent, autoIndent=True}' on line 89, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${topLevelSequence.topLevelSequenceInnerContent, autoIndent=True}')) # from line 89, col 3.
+        write(u'''}
+
+''')
+        #  Now clean up after all of the objects that we initialised early.
+        _v = VFFSL(SL,"finalisationCode",True) # u'${finalisationCode}' on line 93, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${finalisationCode}')) # from line 93, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideMomentGroupProcessingNoProcessingCodeLoop(self, dict, **KWS):
+
+
+        """
+        This function is called by the moment group so that we can add to the template
+        string that will be used to create a loop to perform the processing. The code
+        that this function adds calculates the variance of the sampled variable.
+        
+        The passed dictionary `dict` has the following key:
+          - ``caller``: The moment group which is letting us modify the template string
+        
+        The return value is the template string that will be added to the processing loop template.
+        """
+
+        ## CHEETAH: generated from @def insideMomentGroupProcessingNoProcessingCodeLoop(dict) at line 97, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        momentGroup = dict['caller']
+        write(u'''_''')
+        _v = VFFSL(SL,"momentGroup.outputField.name",True) # u'${momentGroup.outputField.name}' on line 110, col 2
+        if _v is not None: write(_filter(_v, rawExpr=u'${momentGroup.outputField.name}')) # from line 110, col 2.
+        write(u'''_sd[${index}] += _active_${vector.id}[${index}] * _active_${vector.id}[${index}];''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeOutFunctionImplementationBegin(self, dict, **KWS):
+
+
+        """
+        This function is called by the moment group at the start of the write out function
+        so that we can do any processing necessary before the sampled (and perhaps processed)
+        data is written out. The code that this function adds takes account for the fact that
+        the processed vectors have been adding the results for all of the paths, and now need
+        to be divided by the total number of paths. And something similar needs to be done for
+        the standard-error variables.
+        
+        The passed dictionary `dict` has the following keys:
+          - ``caller``: The moment group calling us.
+          - ``dependentVariables``: A list of dictionaries describing the variables that are to be written out.
+            This list can be modified or added to by this function.
+            
+            Each of these dictionaries has the following keys:
+            
+            - ``vector``: The vector describing the type, field and number of components
+            - ``arrayName``: The name of the array that this variable is in. e.g. ``_mg0_processed``
+            - ``components``: The actual name of the components being written.
+        
+        The return value is the template string that will be
+        """
+
+        ## CHEETAH: generated from @def writeOutFunctionImplementationBegin(dict) at line 115, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        momentGroup = dict['caller']
+        dependentVariables = dict['dependentVariables']
+        fieldName = VFFSL(SL,"momentGroup.outputField.name",True)
+        #  
+        #  First we need to modify the variable names that will be written, and add our own.
+        #  We need to change all processed vector components from 'someName' to 'mean_someName'
+        #  and add a variable called 'stderr_someName'
+        # 
+        processedVector = VFFSL(SL,"momentGroup.processedVector",True)
+        otherArrayNames = set([variable['arrayName'] for variable in VFFSL(SL,"dependentVariables",True)[1:]])
+        # 
+        #  Modify the original variable names to have a 'mean_' prefix.
+        processedVectorVariable = dependentVariables[0]
+        processedVectorVariable['components'] = ['mean_' + componentName for componentName in processedVectorVariable['components']]
+        # 
+        newVariableDict = {'vector': processedVector,                           'arrayName': ''.join([u'_',str(VFFSL(SL,"fieldName",True)),u'_sd']),                           'components': ['stderr_' + componentName for componentName in processedVector.components]                          }
+        dependentVariables.append(newVariableDict)
+        # 
+        write(u'''// Calculate the mean
+_active_${vector.id}[${index}] /= (real) _n_paths;
+
+// Calculate the standard error
+_''')
+        _v = VFFSL(SL,"fieldName",True) # u'${fieldName}' on line 163, col 2
+        if _v is not None: write(_filter(_v, rawExpr=u'${fieldName}')) # from line 163, col 2.
+        write(u'''_sd[${index}] /= (real) _n_paths;
+_''')
+        _v = VFFSL(SL,"fieldName",True) # u'${fieldName}' on line 164, col 2
+        if _v is not None: write(_filter(_v, rawExpr=u'${fieldName}')) # from line 164, col 2.
+        write(u'''_sd[${index}] -= _active_${vector.id}[${index}] * _active_${vector.id}[${index}];
+if (_''')
+        _v = VFFSL(SL,"fieldName",True) # u'${fieldName}' on line 165, col 6
+        if _v is not None: write(_filter(_v, rawExpr=u'${fieldName}')) # from line 165, col 6.
+        write(u'''_sd[${index}] > 0.0) // UNVECTORISABLE
+  _''')
+        _v = VFFSL(SL,"fieldName",True) # u'${fieldName}' on line 166, col 4
+        if _v is not None: write(_filter(_v, rawExpr=u'${fieldName}')) # from line 166, col 4.
+        write(u'''_sd[${index}] = sqrt(_''')
+        _v = VFFSL(SL,"fieldName",True) # u'${fieldName}' on line 166, col 39
+        if _v is not None: write(_filter(_v, rawExpr=u'${fieldName}')) # from line 166, col 39.
+        write(u'''_sd[${index}] / _n_paths);
+else
+  _''')
+        _v = VFFSL(SL,"fieldName",True) # u'${fieldName}' on line 168, col 4
+        if _v is not None: write(_filter(_v, rawExpr=u'${fieldName}')) # from line 168, col 4.
+        write(u'''_sd[${index}] = 0.0;
+''')
+        # 
+        if len(otherArrayNames): # generated from line 170, col 3
+            write(u'''
+// Calculate other means
+''')
+            for arrayName in VFFSL(SL,"otherArrayNames",True): # generated from line 173, col 5
+                _v = VFFSL(SL,"arrayName",True) # u'${arrayName}' on line 174, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${arrayName}')) # from line 174, col 1.
+                write(u'''[${index}] /= (real) _n_paths;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # MultiPathDriver.tmpl
+        # 
+        # Created by Graham Dennis on 2008-02-01.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    pathLoopStart = 0
+
+    pathLoopStep = 1
+
+    _mainCheetahMethod_for_MultiPathDriver= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(MultiPathDriver, '_initCheetahAttributes'):
+    templateAPIClass = getattr(MultiPathDriver, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(MultiPathDriver)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=MultiPathDriver()).run()
+
+
diff --git a/xpdeint/SimulationDrivers/MultiPathDriver.tmpl b/xpdeint/SimulationDrivers/MultiPathDriver.tmpl
new file mode 100644
index 0000000..8a1bf45
--- /dev/null
+++ b/xpdeint/SimulationDrivers/MultiPathDriver.tmpl
@@ -0,0 +1,178 @@
+@*
+MultiPathDriver.tmpl
+
+Created by Graham Dennis on 2008-02-01.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.SimulationDrivers._MultiPathDriver
+
+ at def description: Multipath Simulation Driver
+
+ at attr $pathLoopStart = 0
+ at attr $pathLoopStep = 1
+
+ at def defines
+  @#
+  @super
+  @#
+#define _n_paths ${pathCount}
+  @#
+ at end def
+
+ at def topLevelSegmentFunctionImplementation
+  @#
+void _segment0()
+{
+  @# And now insert the code for the features that apply in the top level sequence
+  @set $featureOrdering = ['ErrorCheck', 'Stochastic']
+  @set $dict = {'extraIndent': 0}
+  ${insertCodeForFeatures('topLevelSequenceBegin', featureOrdering, dict), autoIndent=True}@slurp
+  @set $extraIndent = dict['extraIndent']
+
+  ${topLevelSegmentPathLoop, autoIndent=True, extraIndent=extraIndent}@slurp
+
+  ${insertCodeForFeaturesInReverseOrder('topLevelSequenceEnd', featureOrdering, dict), autoIndent=True}@slurp
+}
+  @#
+ at end def
+
+ at def topLevelSegmentPathLoop
+  @#
+  @# Now loop over anything that can be initalised early and initialise them
+  @# so they don't allocate and free stuff for each path. This is done now
+  @# and not before the ErrorCheck and Stochastic Features because the
+  @# initialisation of IP operators will depend on the step size. It would be
+  @# possible to split this up into two stages of initialisation, but that
+  @# seems to me like it would be ugly.
+  @# 
+${topLevelSequence.allocate}@slurp
+
+  @set $objectsNeedingInitialisation = [o for o in $templates if o.hasattr('canBeInitialisedEarly') and o.canBeInitialisedEarly]
+  @for o in $objectsNeedingInitialisation
+${o.initialise}@slurp
+  @end for
+  @#
+  @# We must capture the finalisation of all the objects we initialised
+  @# to make sure they don't get finalised early. As that could lead to
+  @# NULL pointer dereferences, and that is bad.
+  @#
+  @capture finalisationCode
+    @for o in $objectsNeedingInitialisation
+${o.finalise}@slurp
+    @end for
+
+${topLevelSequence.free}@slurp
+  @end capture
+
+for (long _i0 = ${pathLoopStart}; _i0 < _n_paths; _i0+=${pathLoopStep}) {
+  _LOG(_PATH_LOG_LEVEL, "Starting path %li\n", _i0 + 1);
+  
+  @for $mg in $momentGroups
+  ${mg.rawVector.functions['initialise'].call(), autoIndent=True}@slurp
+  @end for
+  
+  ${topLevelSequence.topLevelSequenceInnerContent, autoIndent=True}@slurp
+}
+
+  @# Now clean up after all of the objects that we initialised early.
+${finalisationCode}@slurp
+  @#
+ at end def
+
+ at def insideMomentGroupProcessingNoProcessingCodeLoop(dict)
+@*doc:
+This function is called by the moment group so that we can add to the template
+string that will be used to create a loop to perform the processing. The code
+that this function adds calculates the variance of the sampled variable.
+
+The passed dictionary `dict` has the following key:
+  - ``caller``: The moment group which is letting us modify the template string
+
+The return value is the template string that will be added to the processing loop template.
+*@
+  @#
+  @set $momentGroup = dict['caller']
+_${momentGroup.outputField.name}_sd[\${index}] += _active_\${vector.id}[\${index}] * _active_\${vector.id}[\${index}];@slurp
+  @#
+ at end def
+
+
+ at def writeOutFunctionImplementationBegin(dict)
+@*doc:
+This function is called by the moment group at the start of the write out function
+so that we can do any processing necessary before the sampled (and perhaps processed)
+data is written out. The code that this function adds takes account for the fact that
+the processed vectors have been adding the results for all of the paths, and now need
+to be divided by the total number of paths. And something similar needs to be done for
+the standard-error variables.
+
+The passed dictionary `dict` has the following keys:
+  - ``caller``: The moment group calling us.
+  - ``dependentVariables``: A list of dictionaries describing the variables that are to be written out.
+    This list can be modified or added to by this function.
+    
+    Each of these dictionaries has the following keys:
+    
+    - ``vector``: The vector describing the type, field and number of components
+    - ``arrayName``: The name of the array that this variable is in. e.g. ``_mg0_processed``
+    - ``components``: The actual name of the components being written.
+
+The return value is the template string that will be 
+*@
+  @#
+  @set $momentGroup = dict['caller']
+  @set $dependentVariables = dict['dependentVariables']
+  @set $fieldName = $momentGroup.outputField.name
+  @# 
+  @# First we need to modify the variable names that will be written, and add our own.
+  @# We need to change all processed vector components from 'someName' to 'mean_someName'
+  @# and add a variable called 'stderr_someName'
+  @#
+  @set $processedVector = $momentGroup.processedVector
+  @set $otherArrayNames = set([variable['arrayName'] for variable in $dependentVariables[1:]])
+  @#
+  @# Modify the original variable names to have a 'mean_' prefix.
+  @set $processedVectorVariable = dependentVariables[0]
+  @set processedVectorVariable['components'] = ['mean_' + componentName for componentName in processedVectorVariable['components']]
+  @#
+  @set $newVariableDict = {'vector': processedVector,
+                           'arrayName': c'_${fieldName}_sd',
+                           'components': ['stderr_' + componentName for componentName in processedVector.components]
+                          }
+  @silent dependentVariables.append(newVariableDict)
+  @#
+// Calculate the mean
+_active_\${vector.id}[\${index}] /= (real) _n_paths;
+
+// Calculate the standard error
+_${fieldName}_sd[\${index}] /= (real) _n_paths;
+_${fieldName}_sd[\${index}] -= _active_\${vector.id}[\${index}] * _active_\${vector.id}[\${index}];
+if (_${fieldName}_sd[\${index}] > 0.0) // UNVECTORISABLE
+  _${fieldName}_sd[\${index}] = sqrt(_${fieldName}_sd[\${index}] / _n_paths);
+else
+  _${fieldName}_sd[\${index}] = 0.0;
+  @#
+  @if len(otherArrayNames)
+
+// Calculate other means
+    @for arrayName in $otherArrayNames
+${arrayName}[\${index}] /= (real) _n_paths;
+    @end for
+  @end if
+  @#
+ at end def
diff --git a/xpdeint/SimulationDrivers/SimulationDriver.py b/xpdeint/SimulationDrivers/SimulationDriver.py
new file mode 100644
index 0000000..a657a8f
--- /dev/null
+++ b/xpdeint/SimulationDrivers/SimulationDriver.py
@@ -0,0 +1,487 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.SimulationDrivers._SimulationDriver import _SimulationDriver
+from xpdeint.Vectors.VectorElement import VectorElement
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.257376
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/SimulationDrivers/SimulationDriver.tmpl'
+__CHEETAH_srcLastModified__ = 'Fri Oct 19 15:05:48 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class SimulationDriver(_SimulationDriver):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(SimulationDriver, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Default Simulation Driver at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Default Simulation Driver''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def functionImplementations(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def functionImplementations at line 28, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(SimulationDriver, self).functionImplementations()
+        if _v is not None: write(_filter(_v))
+        # 
+        _v = VFFSL(SL,"topLevelSegmentFunctionImplementation",True) # u'${topLevelSegmentFunctionImplementation}' on line 32, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${topLevelSegmentFunctionImplementation}')) # from line 32, col 1.
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def topLevelSegmentFunctionImplementation(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def topLevelSegmentFunctionImplementation at line 37, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''void _segment0()
+{
+''')
+        # 
+        #  And now insert the code for the features that apply in the top level sequence
+        featureOrdering = ['ErrorCheck', 'Stochastic']
+        dict = {'extraIndent': 0}
+        write(u'''  ''')
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('topLevelSequenceBegin', featureOrdering, dict) # u"${insertCodeForFeatures('topLevelSequenceBegin', featureOrdering, dict), autoIndent=True}" on line 45, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeatures('topLevelSequenceBegin', featureOrdering, dict), autoIndent=True}")) # from line 45, col 3.
+        extraIndent = dict['extraIndent']
+        write(u'''  ''')
+        _v = VFFSL(SL,"topLevelSequence.topLevelSequenceInnerContent",True) # u'${topLevelSequence.topLevelSequenceInnerContent, autoIndent=True, extraIndent=extraIndent}' on line 47, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, extraIndent=extraIndent, rawExpr=u'${topLevelSequence.topLevelSequenceInnerContent, autoIndent=True, extraIndent=extraIndent}')) # from line 47, col 3.
+        # 
+        write(u'''  ''')
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('topLevelSequenceEnd', featureOrdering, dict) # u"${insertCodeForFeaturesInReverseOrder('topLevelSequenceEnd', featureOrdering, dict), autoIndent=True}" on line 49, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u"${insertCodeForFeaturesInReverseOrder('topLevelSequenceEnd', featureOrdering, dict), autoIndent=True}")) # from line 49, col 3.
+        write(u'''}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def mainRoutine(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def mainRoutine at line 55, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''int main(int argc, char **argv)
+{
+  ''')
+        _v = VFFSL(SL,"mainRoutineInnerContent",True) # u'${mainRoutineInnerContent, autoIndent=True}' on line 59, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${mainRoutineInnerContent, autoIndent=True}')) # from line 59, col 3.
+        write(u'''  
+  return 0;
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def mainRoutineInnerContent(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def mainRoutineInnerContent at line 66, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''#ifdef __APPLE__
+  #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
+{
+  IOPMAssertionID _powerAssertionID = 0;
+  IOReturn __io_result = IOPMAssertionCreateWithDescription(
+    kIOPMAssertionTypePreventUserIdleSystemSleep,
+    CFSTR("XMDS simulation \'''')
+        _v = VFFSL(SL,"simulationName",True) # u'${simulationName}' on line 74, col 29
+        if _v is not None: write(_filter(_v, rawExpr=u'${simulationName}')) # from line 74, col 29.
+        write(u'''\' preventing user idle sleep"), // Assertion name
+    NULL, // Assertion details
+    NULL, // Human-readable reason
+    NULL, // Localization bundle path
+    (CFTimeInterval)0, // never timeout
+    kIOPMAssertionTimeoutActionRelease,
+    &_powerAssertionID
+    );
+  if (__io_result != kIOReturnSuccess) {
+    _LOG(_WARNING_LOG_LEVEL, "Failed to disable user idle sleep\\n");
+  }
+  // Note, this power assertion is automatically released when the process quits.
+}
+  #endif
+#endif
+
+  
+''')
+        preAllocationFeatureOrdering = ['Arguments', 'Driver', 'ChunkedOutput']
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('preAllocation', VFFSL(SL,"preAllocationFeatureOrdering",True)) # u"${insertCodeForFeatures('preAllocation', $preAllocationFeatureOrdering)}" on line 92, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('preAllocation', $preAllocationFeatureOrdering)}")) # from line 92, col 1.
+        write(u'''  
+
+''')
+        vectors = set([v for v in VFFSL(SL,"templates",True) if isinstance(v, VectorElement)])
+        _v = VFFSL(SL,"setVectorAllocSizes",False)(vectors) # u'${setVectorAllocSizes(vectors)}' on line 96, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${setVectorAllocSizes(vectors)}')) # from line 96, col 1.
+        # 
+        for field in VFFSL(SL,"fields",True): # generated from line 98, col 3
+            _v = VFFSL(SL,"field.allocate",True) # u'${field.allocate}' on line 99, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${field.allocate}')) # from line 99, col 1.
+        write(u'''
+''')
+        for mg in VFFSL(SL,"momentGroups",True): # generated from line 102, col 3
+            _v = VFFSL(SL,"mg.allocate",True) # u'${mg.allocate}' on line 103, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${mg.allocate}')) # from line 103, col 1.
+        write(u'''
+''')
+        # 
+        #     And now insert the code for the features that apply in the main function
+        #   
+        featureOrdering = ['Bing', 'Validation', 'Driver', 'OpenMP', 'Stochastic', 'TransformMultiplexer', 'Benchmark', 'Output']
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('mainBegin', VFFSL(SL,"featureOrdering",True)) # u"${insertCodeForFeatures('mainBegin', $featureOrdering)}" on line 110, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('mainBegin', $featureOrdering)}")) # from line 110, col 1.
+        write(u'''
+''')
+        #  This needs to be extracted into a function so that it can be indented further if necessary
+        write(u'''/* Code that actually does stuff goes here */
+_segment0();
+
+''')
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('mainEnd', VFFSL(SL,"featureOrdering",True)) # u"${insertCodeForFeaturesInReverseOrder('mainEnd', $featureOrdering)}" on line 116, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeaturesInReverseOrder('mainEnd', $featureOrdering)}")) # from line 116, col 1.
+        # 
+        for field in VFFSL(SL,"fields",True): # generated from line 118, col 3
+            _v = VFFSL(SL,"field.free",True) # u'${field.free}' on line 119, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${field.free}')) # from line 119, col 1.
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def setVectorAllocSizes(self, vectors, **KWS):
+
+
+
+        ## CHEETAH: generated from @def setVectorAllocSizes($vectors) at line 125, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        for vector in vectors: # generated from line 127, col 3
+            for basis in vector.basesNeeded: # generated from line 128, col 5
+                _v = VFFSL(SL,"vector.allocSize",True) # u'${vector.allocSize}' on line 129, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.allocSize}')) # from line 129, col 1.
+                write(u''' = MAX(''')
+                _v = VFFSL(SL,"vector.allocSize",True) # u'${vector.allocSize}' on line 129, col 27
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.allocSize}')) # from line 129, col 27.
+                write(u''', ''')
+                _v = VFN(VFFSL(SL,"vector.field",True),"sizeInBasis",False)(basis) # u'${vector.field.sizeInBasis(basis)}' on line 129, col 48
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.field.sizeInBasis(basis)}')) # from line 129, col 48.
+                write(u''' * _''')
+                _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 129, col 86
+                if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 129, col 86.
+                write(u'''_ncomponents);
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def mainBegin(self, dict, **KWS):
+
+
+
+        ## CHEETAH: generated from @def mainBegin($dict) at line 135, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        initialisedDimRepArrays = set()
+        # 
+        for field in VFFSL(SL,"fields",True): # generated from line 139, col 3
+            # 
+            for dim in field.dimensions: # generated from line 141, col 5
+                for dimRep in [dimRep for dimRep in dim.representations if dimRep and not dimRep.arrayName in initialisedDimRepArrays]: # generated from line 142, col 7
+                    _v = VFFSL(SL,"dimRep.initialiseArray",True) # u'${dimRep.initialiseArray}' on line 143, col 1
+                    if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.initialiseArray}')) # from line 143, col 1.
+                    initialisedDimRepArrays.add(dimRep.arrayName)
+        for mg in VFFSL(SL,"momentGroups",True): # generated from line 148, col 3
+            _v = VFFSL(SL,"mg.outputField.initialise",True) # u'${mg.outputField.initialise}' on line 149, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${mg.outputField.initialise}')) # from line 149, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # SimulationDriver.tmpl
+        # 
+        # Created by Graham Dennis on 2008-02-27.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_SimulationDriver= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(SimulationDriver, '_initCheetahAttributes'):
+    templateAPIClass = getattr(SimulationDriver, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(SimulationDriver)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=SimulationDriver()).run()
+
+
diff --git a/xpdeint/SimulationDrivers/SimulationDriver.tmpl b/xpdeint/SimulationDrivers/SimulationDriver.tmpl
new file mode 100644
index 0000000..118e3a2
--- /dev/null
+++ b/xpdeint/SimulationDrivers/SimulationDriver.tmpl
@@ -0,0 +1,152 @@
+@*
+SimulationDriver.tmpl
+
+Created by Graham Dennis on 2008-02-27.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.SimulationDrivers._SimulationDriver
+
+ at from xpdeint.Vectors.VectorElement import VectorElement
+
+ at def description: Default Simulation Driver
+
+ at def functionImplementations
+  @#
+  @super
+  @#
+${topLevelSegmentFunctionImplementation}@slurp
+
+  @#
+ at end def
+
+ at def topLevelSegmentFunctionImplementation
+  @#
+void _segment0()
+{
+  @#
+  @# And now insert the code for the features that apply in the top level sequence
+  @set $featureOrdering = ['ErrorCheck', 'Stochastic']
+  @set $dict = {'extraIndent': 0}
+  ${insertCodeForFeatures('topLevelSequenceBegin', featureOrdering, dict), autoIndent=True}@slurp
+  @set $extraIndent = dict['extraIndent']
+  ${topLevelSequence.topLevelSequenceInnerContent, autoIndent=True, extraIndent=extraIndent}@slurp
+  @#
+  ${insertCodeForFeaturesInReverseOrder('topLevelSequenceEnd', featureOrdering, dict), autoIndent=True}@slurp
+}
+  @#
+ at end def
+
+
+ at def mainRoutine
+  @#
+int main(int argc, char **argv)
+{
+  ${mainRoutineInnerContent, autoIndent=True}@slurp
+  
+  return 0;
+}
+  @#
+ at end def
+
+ at def mainRoutineInnerContent
+  @#
+#ifdef __APPLE__
+  #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
+{
+  IOPMAssertionID _powerAssertionID = 0;
+  IOReturn __io_result = IOPMAssertionCreateWithDescription(
+    kIOPMAssertionTypePreventUserIdleSystemSleep,
+    CFSTR("XMDS simulation '${simulationName}' preventing user idle sleep"), // Assertion name
+    NULL, // Assertion details
+    NULL, // Human-readable reason
+    NULL, // Localization bundle path
+    (CFTimeInterval)0, // never timeout
+    kIOPMAssertionTimeoutActionRelease,
+    &_powerAssertionID
+    );
+  if (__io_result != kIOReturnSuccess) {
+    _LOG(_WARNING_LOG_LEVEL, "Failed to disable user idle sleep\n");
+  }
+  // Note, this power assertion is automatically released when the process quits.
+}
+  #endif
+#endif
+
+  
+  @set $preAllocationFeatureOrdering = ['Arguments', 'Driver', 'ChunkedOutput']
+${insertCodeForFeatures('preAllocation', $preAllocationFeatureOrdering)}@slurp
+  
+
+  @set vectors = set([v for v in $templates if isinstance(v, VectorElement)])
+${setVectorAllocSizes(vectors)}@slurp
+  @#
+  @for field in $fields
+${field.allocate}@slurp
+  @end for
+
+  @for $mg in $momentGroups
+${mg.allocate}@slurp
+  @end for
+
+  @*
+    And now insert the code for the features that apply in the main function
+  *@
+  @set $featureOrdering = ['Bing', 'Validation', 'Driver', 'OpenMP', 'Stochastic', 'TransformMultiplexer', 'Benchmark', 'Output']
+${insertCodeForFeatures('mainBegin', $featureOrdering)}@slurp
+
+@# This needs to be extracted into a function so that it can be indented further if necessary
+/* Code that actually does stuff goes here */
+_segment0();
+
+${insertCodeForFeaturesInReverseOrder('mainEnd', $featureOrdering)}@slurp
+  @#
+  @for $field in $fields
+${field.free}@slurp
+  @end for
+
+  @#
+ at end def
+
+ at def setVectorAllocSizes($vectors)
+  @#
+  @for vector in vectors
+    @for basis in vector.basesNeeded
+${vector.allocSize} = MAX(${vector.allocSize}, ${vector.field.sizeInBasis(basis)} * _${vector.id}_ncomponents);
+    @end for
+  @end for
+  @#
+ at end def
+
+ at def mainBegin($dict)
+  @#
+  @set $initialisedDimRepArrays = set()
+  @#
+  @for field in $fields
+    @#
+    @for dim in field.dimensions
+      @for dimRep in [dimRep for dimRep in dim.representations if dimRep and not dimRep.arrayName in initialisedDimRepArrays]
+${dimRep.initialiseArray}@slurp
+        @silent initialisedDimRepArrays.add(dimRep.arrayName)
+      @end for
+    @end for
+  @end for
+  @for $mg in $momentGroups
+${mg.outputField.initialise}@slurp
+  @end for
+  @#
+ at end def
diff --git a/xpdeint/SimulationDrivers/_DistributedMPIDriver.py b/xpdeint/SimulationDrivers/_DistributedMPIDriver.py
new file mode 100755
index 0000000..8944c5a
--- /dev/null
+++ b/xpdeint/SimulationDrivers/_DistributedMPIDriver.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_DistributedMPIDriver.py
+
+Created by Graham Dennis on 2008-03-29.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.SimulationDrivers.SimulationDriver import SimulationDriver
+from xpdeint.SimulationDrivers.MPI import MPI
+from xpdeint.Features.OutputFormat import OutputFormat
+
+from xpdeint.ParserException import ParserException
+
+class _DistributedMPIDriver (SimulationDriver, MPI):
+  def __init__(self, *args, **KWs):
+    SimulationDriver.__init__(self, *args, **KWs)
+    MPI.__init__(self, *args, **KWs)
+    
+    self._distributedTransform = None
+  
+  def _getDistributedTransform(self):
+    return self._distributedTransform
+  
+  def _setDistributedTransform(self, value):
+    assert not self._distributedTransform
+    self._distributedTransform = value
+  
+  distributedTransform = property(_getDistributedTransform, _setDistributedTransform)
+  del _getDistributedTransform, _setDistributedTransform
+  
+  def isFieldDistributed(self, field):
+    return self._distributedTransform.isFieldDistributed(field)
+  
+  def shadowedVariablesForField(self, field):
+    if not self.isFieldDistributed(field):
+      return []
+    result = []
+    for dim in field.dimensions:
+      for rep in [rep for rep in dim.representations if rep and rep.hasLocalOffset]:
+        result.extend([rep.localLattice, rep.localOffset])
+    return result
+  
+  def basisWithTransverseDimensionsMovedAfterMPIDimensions(self, basis):
+    geometry = self.getVar('geometry')
+    dimRepNameMap = dict()
+    for dim in geometry.dimensions:
+      for dimRep in dim.representations:
+        dimRepNameMap[dimRep.canonicalName] = dim
+        dimRepNameMap[dimRep.name] = dim
+    basis = list(basis)
+    for dimRepName in basis[:]:
+      if dimRepNameMap[dimRepName].transverse and dimRepNameMap[dimRepName].name not in self.distributedDimensionNames:
+        # Move it to the end.
+        basis.remove(dimRepName)
+        basis.append(dimRepName)
+    return tuple(basis)
+  
+  def preflight(self):
+    super(_DistributedMPIDriver, self).preflight()
+    
+    outputFormats = [o for o in self.getVar('templates') if isinstance(o, OutputFormat)]
+    outputFeature = self.getVar('features')['Output']
+    
+    for outputFormat in outputFormats:
+      if not outputFormat.mpiSafe:
+        raise ParserException(outputFeature.xmlElement, "The '%s' output format cannot be used with the 'distributed-mpi' driver." % outputFormat.name)
+  
+  def canonicalBasisForBasis(self, basis, **KWs):
+    basis = self.basisWithTransverseDimensionsMovedAfterMPIDimensions(basis)
+    if self._distributedTransform.hasattr('canonicalBasisForBasis'):
+      return self._distributedTransform.canonicalBasisForBasis(basis, **KWs)
+    return super(_DistributedMPIDriver, self).canonicalBasisForBasis(basis, **KWs)
+  
diff --git a/xpdeint/SimulationDrivers/_MPIMultiPathDriver.py b/xpdeint/SimulationDrivers/_MPIMultiPathDriver.py
new file mode 100644
index 0000000..245156e
--- /dev/null
+++ b/xpdeint/SimulationDrivers/_MPIMultiPathDriver.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_MPIMultiPathDriver.py
+
+Created by Graham Dennis on 2008-03-28.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.SimulationDrivers.MultiPathDriver import MultiPathDriver
+from xpdeint.SimulationDrivers.MPI import MPI
+
+class _MPIMultiPathDriver (MultiPathDriver, MPI):
+  def __init__(self, *args, **KWs):
+    MultiPathDriver.__init__(self, *args, **KWs)
+    MPI.__init__(self, *args, **KWs)
+  
diff --git a/xpdeint/SimulationDrivers/_MultiPathDriver.py b/xpdeint/SimulationDrivers/_MultiPathDriver.py
new file mode 100644
index 0000000..4c33fee
--- /dev/null
+++ b/xpdeint/SimulationDrivers/_MultiPathDriver.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_MultiPathDriver.py
+
+Created by Graham Dennis on 2008-02-02.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.SimulationDrivers.SimulationDriver import SimulationDriver
+
+class _MultiPathDriver (SimulationDriver):
+  logLevelsBeingLogged = "_PATH_LOG_LEVEL|_SIMULATION_LOG_LEVEL|_WARNING_LOG_LEVEL|_ERROR_LOG_LEVEL|_NO_ERROR_TERMINATE_LOG_LEVEL"
+  
+  def preflight(self):
+    super(_MultiPathDriver, self).preflight()
+    
+    for mg in self.getVar('momentGroups'):
+      mg.processedVector.aliases.add('_%s_sd' % mg.outputField.name)
+    
+  
+  def rawVectorNeedsToBeAllocated(self, dict):
+    """
+    This function makes moment groups allocate their raw sampling vectors so that
+    we can sample both the mean and the standard error.
+    """
+    dict['returnValue'] = True
+  
diff --git a/xpdeint/SimulationDrivers/_SimulationDriver.py b/xpdeint/SimulationDrivers/_SimulationDriver.py
new file mode 100644
index 0000000..916e5d6
--- /dev/null
+++ b/xpdeint/SimulationDrivers/_SimulationDriver.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_SimulationDriver.py
+
+Created by Graham Dennis on 2008-02-01.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.ScriptElement import ScriptElement
+
+class _SimulationDriver (ScriptElement):
+  logLevelsBeingLogged = "_ALL_LOG_LEVELS"
+  
+  def __init__(self, *args, **KWs):
+    ScriptElement.__init__(self, *args, **KWs)
+    
+    self.getVar('features')['Driver'] = self
+    # Put ourselves at the start after the simulation element
+    self.distributedDimensionNames = []
+  
+  def isFieldDistributed(self, field):
+    return False
+  
+  def canonicalBasisForBasis(self, basis, **KWs):
+    return basis
+  
diff --git a/xpdeint/SimulationDrivers/__init__.py b/xpdeint/SimulationDrivers/__init__.py
new file mode 100644
index 0000000..792d600
--- /dev/null
+++ b/xpdeint/SimulationDrivers/__init__.py
@@ -0,0 +1 @@
+#
diff --git a/xpdeint/SimulationElement.py b/xpdeint/SimulationElement.py
new file mode 100644
index 0000000..5f9b25e
--- /dev/null
+++ b/xpdeint/SimulationElement.py
@@ -0,0 +1,283 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.ScriptElement import ScriptElement
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.277653
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/SimulationElement.tmpl'
+__CHEETAH_srcLastModified__ = 'Fri Feb 24 16:41:39 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class SimulationElement(ScriptElement):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(SimulationElement, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Simulation at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Simulation''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def defines(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def defines at line 29, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(SimulationElement, self).defines()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''#define _EPSILON 1e-6
+#ifndef INFINITY
+#define INFINITY HUGE_VAL
+#endif
+
+#ifndef MAX
+#define MAX(a, b) \\
+  ({ typeof(a) _a = (a); \\
+     typeof(b) _b = (b); \\
+     _a > _b ? _a : _b; })
+#endif
+
+#ifndef MIN
+#define MIN(a, b) \\
+   ({ typeof(a) _a = (a); \\
+      typeof(b) _b = (b); \\
+      _a < _b ? _a : _b; })
+#endif
+
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def globals at line 58, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(SimulationElement, self).globals()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''
+''')
+        #  If the simulation uses <Arguments append_args_to_output_filename="yes" >	
+        #  we'll need to store the args and their values in a global string for
+        #  use when we construct output filenames.
+        #  The arguments and values are assigned to this string in the Arguments.tmpl code.
+        write(u'''string gsArgsAndValues = "";
+  
+real ''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 69, col 6
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 69, col 6.
+        write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # SimulationElement.tmpl
+        # 
+        # Created by Graham Dennis on 2007-08-23.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+''')
+        # 
+        #   Description of template
+        write(u'''
+
+''')
+        # 
+        #   Globals needed at the start of the simulation
+        write(u'''
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_SimulationElement= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(SimulationElement, '_initCheetahAttributes'):
+    templateAPIClass = getattr(SimulationElement, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(SimulationElement)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=SimulationElement()).run()
+
+
diff --git a/xpdeint/SimulationElement.tmpl b/xpdeint/SimulationElement.tmpl
new file mode 100644
index 0000000..4e3ce7c
--- /dev/null
+++ b/xpdeint/SimulationElement.tmpl
@@ -0,0 +1,72 @@
+@*
+SimulationElement.tmpl
+
+Created by Graham Dennis on 2007-08-23.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.ScriptElement
+
+@*
+  Description of template
+*@
+ at def description: Simulation
+
+ at def defines
+  @#
+  @super
+  @#
+#define _EPSILON 1e-6
+#ifndef INFINITY
+#define INFINITY HUGE_VAL
+#endif
+
+#ifndef MAX
+#define MAX(a, b) \
+  ({ typeof(a) _a = (a); \
+     typeof(b) _b = (b); \
+     _a > _b ? _a : _b; })
+#endif
+
+#ifndef MIN
+#define MIN(a, b) \
+   ({ typeof(a) _a = (a); \
+      typeof(b) _b = (b); \
+      _a < _b ? _a : _b; })
+#endif
+
+  @#
+ at end def
+
+@*
+  Globals needed at the start of the simulation
+*@
+ at def globals
+  @#
+  @super
+  @#
+
+@# If the simulation uses <Arguments append_args_to_output_filename="yes" >	
+@# we'll need to store the args and their values in a global string for
+@# use when we construct output filenames.
+@# The arguments and values are assigned to this string in the Arguments.tmpl code.
+string gsArgsAndValues = "";
+  
+real ${propagationDimension};
+  @#
+ at end def
+
diff --git a/xpdeint/Stochastic/Generators/DSFMTGenerator.py b/xpdeint/Stochastic/Generators/DSFMTGenerator.py
new file mode 100644
index 0000000..a0c0406
--- /dev/null
+++ b/xpdeint/Stochastic/Generators/DSFMTGenerator.py
@@ -0,0 +1,706 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Stochastic.Generators.Generator import Generator
+from xpdeint.CallOnceGuards import callOnceGuard
+import random
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.426863
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Stochastic/Generators/DSFMTGenerator.tmpl'
+__CHEETAH_srcLastModified__ = 'Wed Aug 28 15:52:21 2013'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class DSFMTGenerator(Generator):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(DSFMTGenerator, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Generic dSFMT noise at line 29, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Generic dSFMT noise''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def generatorType(self, **KWS):
+
+
+
+        ## Generated from @def generatorType: dsfmt_t* at line 30, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''dsfmt_t*''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def globals at line 31, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(DSFMTGenerator, self).globals()
+        if _v is not None: write(_filter(_v))
+        # 
+        _v = VFFSL(SL,"generatorType",True) # u'$generatorType' on line 35, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'$generatorType')) # from line 35, col 1.
+        write(u''' ''')
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 35, col 16
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 35, col 16.
+        write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOnceGuard
+    def static_includes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def static_includes at line 44, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(DSFMTGenerator, self).static_includes()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''#define DSFMT_DO_NOT_USE_OLD_NAMES
+#if CFG_HAVE_SSE2
+  #define HAVE_SSE2
+#elif CFG_HAVE_ALTIVEC
+  #define HAVE_ALTIVEC
+#endif
+
+#define DSFMT_MEXP 19937
+
+#include <dSFMT/dSFMT.h>
+#include <dSFMT/dSFMT.c>
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOnceGuard
+    def static_globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def static_globals at line 63, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        if VFFSL(SL,"precision",True) == 'single': # generated from line 64, col 3
+            write(u'''// ********************************************************
+//   Struct and typedef to help convert a double to two floats
+union float_double {
+       uint64_t u;
+       uint32_t u32[2];
+       double d;
+       float f[2];
+};
+
+typedef union float_double float_double_t;
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOnceGuard
+    def static_defines(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def static_defines at line 79, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        if VFFSL(SL,"precision",True) == 'single': # generated from line 80, col 3
+            write(u'''// defines to help convert a double to two floats
+#define LOWER_FLOAT_MASK   0x00000000007fffffULL
+#define UPPER_FLOAT_MASK   0x007fffff00000000ULL
+#define UPPER_FLOAT_LSHIFT 3
+#define EXPONENT_BITS      0x3f8000003f800000ULL
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOnceGuard
+    def static_functionPrototypes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def static_functionPrototypes at line 90, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        if VFFSL(SL,"precision",True) == 'single': # generated from line 91, col 3
+            write(u'''float generate_float_close1_open2_via_dsfmt(dsfmt_t *dsfmt_array);
+void generate_float_pair_close1_open2_via_dsfmt(dsfmt_t *dsfmt_array, float &f1, float &f2);
+void generate_float_array_close0_open1(dsfmt_t *noise, real array[], int vector_size);
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOnceGuard
+    def static_functionImplementations(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def static_functionImplementations at line 99, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        if VFFSL(SL,"precision",True) == 'single': # generated from line 100, col 3
+            noiseVector = VFFSL(SL,"parent.parent",True)
+            write(u'''// Converts a double in the range [1,2) into two floats in the range [1,2)
+// returns one and stores the other in reserve for the next call to this
+// function.
+float generate_float_close1_open2_via_dsfmt(dsfmt_t *dsfmt_array) 
+{
+  static float_double_t twiddle;
+  static bool bSpareNoise = false;
+
+  if (bSpareNoise) {
+    bSpareNoise = false;
+    return twiddle.f[1];
+  }
+  
+  twiddle.d = dsfmt_genrand_close1_open2(dsfmt_array);
+  twiddle.u = ((twiddle.u << UPPER_FLOAT_LSHIFT) & UPPER_FLOAT_MASK) | (twiddle.u & LOWER_FLOAT_MASK) | EXPONENT_BITS;
+  bSpareNoise = true;
+  return twiddle.f[0];
+}
+
+// Returns two random floats [1,2) by generating one double and converting it 
+void generate_float_pair_close1_open2_via_dsfmt(dsfmt_t *noise, float &f1, float &f2) 
+{
+  float_double_t twiddle;
+
+  twiddle.d = dsfmt_genrand_close1_open2(noise);
+  twiddle.u = ((twiddle.u << UPPER_FLOAT_LSHIFT) & UPPER_FLOAT_MASK) | (twiddle.u & LOWER_FLOAT_MASK) | EXPONENT_BITS;
+  f1 = twiddle.f[0];
+  f2 = twiddle.f[1];
+}
+
+/* Fills an array with random floats [0,1) by calling dsfmt_fill_array_close1_open2
+** to fill an array half as long with doubles [1,2), then converting these to twice 
+** as many floats [1,2), then subtracting one.
+** This seems to be slightly faster than calling generate_float_pair_close1_open2_via_dsfmt
+** over and over again.
+*/
+void generate_float_array_close0_open1(dsfmt_t *noise, real noiseVector[], int vector_size) {
+  // We can only ask dsfmt to fill arrays that have an even number of doubles, and the
+  // number of floats must therefore be divisible by four
+  int padding = vector_size & 0x3;
+  int num_doubles = (vector_size - padding)/2;
+  float_double_t twiddle;
+
+  if (num_doubles > dsfmt_get_min_array_size()) {
+    double *array_double = new double[num_doubles];
+    dsfmt_fill_array_close1_open2(noise, array_double, num_doubles);
+
+    for (int i=0; i<num_doubles; i++) {
+      twiddle.d = array_double[i];
+      twiddle.u = ((twiddle.u << UPPER_FLOAT_LSHIFT) & UPPER_FLOAT_MASK) | (twiddle.u & LOWER_FLOAT_MASK) | EXPONENT_BITS;
+      reinterpret_cast<real*>(_active_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 152, col 39
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 152, col 39.
+            write(u''')[2*i] = twiddle.f[0] - 1.0f;
+      reinterpret_cast<real*>(_active_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 153, col 39
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 153, col 39.
+            write(u''')[2*i+1] = twiddle.f[1] - 1.0f;
+    }
+    
+    // Finish up by generating the 0,1,2 or 3 numbers on the end of the noise vector
+    for (int i=0; i<padding; i++)
+    {
+      reinterpret_cast<real*>(_active_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 159, col 39
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 159, col 39.
+            write(u''')[vector_size-i] = generate_float_close1_open2_via_dsfmt(''')
+            _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 159, col 113
+            if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 159, col 113.
+            write(u''') - 1.0f;
+    }
+    delete [] array_double;
+  }
+  else {
+    // The number of floats we need does meet the minimum of what dsfmt can provide in 
+    // and array, so it by a single number at a time instead.
+    for (long _i0 = 0; _i0 < vector_size; _i0++) {
+      reinterpret_cast<real*>(_active_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 167, col 39
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 167, col 39.
+            write(u''')[_i0] = generate_float_close1_open2_via_dsfmt(''')
+            _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 167, col 103
+            if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 167, col 103.
+            write(u''') - 1.0f;
+    }
+  }
+}
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def constructArrayUniformRandomNumbers(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def constructArrayUniformRandomNumbers at line 175, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        noiseVector = VFFSL(SL,"parent.parent",True)
+        if VFFSL(SL,"precision",True) == 'single': # generated from line 177, col 3
+            write(u'''generate_float_array_close0_open1(''')
+            _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 178, col 35
+            if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 178, col 35.
+            write(u''', reinterpret_cast<real*>(_active_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 178, col 85
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 178, col 85.
+            write(u'''), _vector_size);
+''')
+        else: # generated from line 179, col 3
+            write(u'''if (!(_vector_size & 0x1) && _vector_size > dsfmt_get_min_array_size())
+  dsfmt_fill_array_open_open(''')
+            _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 181, col 30
+            if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 181, col 30.
+            write(u''', reinterpret_cast<real*>(_active_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 181, col 80
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 181, col 80.
+            write(u'''), _vector_size);
+else {
+  for (long _i0 = 0; _i0 < _vector_size; _i0++) {
+    reinterpret_cast<real*>(_active_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 184, col 37
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 184, col 37.
+            write(u''')[_i0] = dsfmt_genrand_open_open(''')
+            _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 184, col 87
+            if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 184, col 87.
+            write(u''');
+  }
+}
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def minusOneToOneRandomNumber(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def minusOneToOneRandomNumber at line 190, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        if VFFSL(SL,"precision",True) == 'single': # generated from line 191, col 3
+            write(u'''(2.0*generate_float_close1_open2_via_dsfmt(''')
+            _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 192, col 44
+            if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 192, col 44.
+            write(u''') - 3.0)''')
+        else: # generated from line 193, col 3
+            write(u'''(2.0*dsfmt_genrand_close1_open2(''')
+            _v = VFFSL(SL,"generatorName",True) # u'$generatorName' on line 194, col 33
+            if _v is not None: write(_filter(_v, rawExpr=u'$generatorName')) # from line 194, col 33.
+            write(u''') - 3.0)''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def zeroToOneRandomNumber(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def zeroToOneRandomNumber at line 198, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        if VFFSL(SL,"precision",True) == 'single': # generated from line 199, col 3
+            write(u'''(generate_float_close1_open2_via_dsfmt(''')
+            _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 200, col 40
+            if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 200, col 40.
+            write(u''') - 1.0)''')
+        else: # generated from line 201, col 3
+            write(u'''dsfmt_genrand_open_open(''')
+            _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 202, col 25
+            if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 202, col 25.
+            write(u''')''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def initialiseLocalSeeds(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def initialiseLocalSeeds at line 206, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(DSFMTGenerator, self).initialiseLocalSeeds()
+        if _v is not None: write(_filter(_v))
+        # 
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 210, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 210, col 1.
+        write(u''' = (dsfmt_t *)xmds_malloc(sizeof(dsfmt_t));
+dsfmt_init_by_array(''')
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 211, col 21
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 211, col 21.
+        write(u''', ''')
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 211, col 39
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 211, col 39.
+        write(u'''_local_seeds, ''')
+        _v = VFFSL(SL,"seedCount",True) # u'${seedCount}' on line 211, col 69
+        if _v is not None: write(_filter(_v, rawExpr=u'${seedCount}')) # from line 211, col 69.
+        write(u''');
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # DSFMTGenerator.tmpl
+        # 
+        # Created by Joe Hope on 2009-08-22.
+        # 
+        # Copyright (c) 2009-2012, Joe Hope
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+''')
+        # 
+        #   Static includes
+        #   The callOnceGuard won't work until the same includes are gone from the stochastic feature.
+        write(u'''
+
+
+
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    uselib = ['dsfmt']
+
+    _mainCheetahMethod_for_DSFMTGenerator= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(DSFMTGenerator, '_initCheetahAttributes'):
+    templateAPIClass = getattr(DSFMTGenerator, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(DSFMTGenerator)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=DSFMTGenerator()).run()
+
+
diff --git a/xpdeint/Stochastic/Generators/DSFMTGenerator.tmpl b/xpdeint/Stochastic/Generators/DSFMTGenerator.tmpl
new file mode 100644
index 0000000..9de60ee
--- /dev/null
+++ b/xpdeint/Stochastic/Generators/DSFMTGenerator.tmpl
@@ -0,0 +1,215 @@
+@*
+DSFMTGenerator.tmpl
+
+Created by Joe Hope on 2009-08-22.
+
+Copyright (c) 2009-2012, Joe Hope
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Stochastic.Generators.Generator
+
+ at from xpdeint.CallOnceGuards import callOnceGuard
+ at import random
+
+ at attr uselib = ['dsfmt']
+
+ at def description: Generic dSFMT noise
+ at def generatorType: dsfmt_t*
+ at def globals
+  @#
+  @super
+  @#
+$generatorType ${generatorName};
+  @#
+ at end def
+
+@*
+  Static includes
+*@
+@#  The callOnceGuard won't work until the same includes are gone from the stochastic feature.
+@@callOnceGuard
+ at def static_includes
+  @#
+  @super
+  @#
+#define DSFMT_DO_NOT_USE_OLD_NAMES
+#if CFG_HAVE_SSE2
+  #define HAVE_SSE2
+#elif CFG_HAVE_ALTIVEC
+  #define HAVE_ALTIVEC
+#endif
+
+#define DSFMT_MEXP 19937
+
+#include <dSFMT/dSFMT.h>
+#include <dSFMT/dSFMT.c>
+  @#
+ at end def
+
+@@callOnceGuard
+ at def static_globals
+  @if $precision == 'single'
+// ********************************************************
+//   Struct and typedef to help convert a double to two floats
+union float_double {
+       uint64_t u;
+       uint32_t u32[2];
+       double d;
+       float f[2];
+};
+
+typedef union float_double float_double_t;
+  @end if
+ at end def
+
+@@callOnceGuard
+ at def static_defines
+  @if $precision == 'single'
+// defines to help convert a double to two floats
+#define LOWER_FLOAT_MASK   0x00000000007fffffULL
+#define UPPER_FLOAT_MASK   0x007fffff00000000ULL
+#define UPPER_FLOAT_LSHIFT 3
+#define EXPONENT_BITS      0x3f8000003f800000ULL
+  @end if  
+ at end def
+
+@@callOnceGuard
+ at def static_functionPrototypes
+  @if $precision == 'single'
+float generate_float_close1_open2_via_dsfmt(dsfmt_t *dsfmt_array);
+void generate_float_pair_close1_open2_via_dsfmt(dsfmt_t *dsfmt_array, float &f1, float &f2);
+void generate_float_array_close0_open1(dsfmt_t *noise, real array[], int vector_size);
+  @end if  
+ at end def
+
+@@callOnceGuard
+ at def static_functionImplementations
+  @if $precision == 'single'
+    @set noiseVector = $parent.parent
+// Converts a double in the range [1,2) into two floats in the range [1,2)
+// returns one and stores the other in reserve for the next call to this
+// function.
+float generate_float_close1_open2_via_dsfmt(dsfmt_t *dsfmt_array) 
+{
+  static float_double_t twiddle;
+  static bool bSpareNoise = false;
+
+  if (bSpareNoise) {
+    bSpareNoise = false;
+    return twiddle.f[1];
+  }
+  
+  twiddle.d = dsfmt_genrand_close1_open2(dsfmt_array);
+  twiddle.u = ((twiddle.u << UPPER_FLOAT_LSHIFT) & UPPER_FLOAT_MASK) | (twiddle.u & LOWER_FLOAT_MASK) | EXPONENT_BITS;
+  bSpareNoise = true;
+  return twiddle.f[0];
+}
+
+// Returns two random floats [1,2) by generating one double and converting it 
+void generate_float_pair_close1_open2_via_dsfmt(dsfmt_t *noise, float &f1, float &f2) 
+{
+  float_double_t twiddle;
+
+  twiddle.d = dsfmt_genrand_close1_open2(noise);
+  twiddle.u = ((twiddle.u << UPPER_FLOAT_LSHIFT) & UPPER_FLOAT_MASK) | (twiddle.u & LOWER_FLOAT_MASK) | EXPONENT_BITS;
+  f1 = twiddle.f[0];
+  f2 = twiddle.f[1];
+}
+
+/* Fills an array with random floats [0,1) by calling dsfmt_fill_array_close1_open2
+** to fill an array half as long with doubles [1,2), then converting these to twice 
+** as many floats [1,2), then subtracting one.
+** This seems to be slightly faster than calling generate_float_pair_close1_open2_via_dsfmt
+** over and over again.
+*/
+void generate_float_array_close0_open1(dsfmt_t *noise, real noiseVector[], int vector_size) {
+  // We can only ask dsfmt to fill arrays that have an even number of doubles, and the
+  // number of floats must therefore be divisible by four
+  int padding = vector_size & 0x3;
+  int num_doubles = (vector_size - padding)/2;
+  float_double_t twiddle;
+
+  if (num_doubles > dsfmt_get_min_array_size()) {
+    double *array_double = new double[num_doubles];
+    dsfmt_fill_array_close1_open2(noise, array_double, num_doubles);
+
+    for (int i=0; i<num_doubles; i++) {
+      twiddle.d = array_double[i];
+      twiddle.u = ((twiddle.u << UPPER_FLOAT_LSHIFT) & UPPER_FLOAT_MASK) | (twiddle.u & LOWER_FLOAT_MASK) | EXPONENT_BITS;
+      reinterpret_cast<real*>(_active_${noiseVector.id})[2*i] = twiddle.f[0] - 1.0f;
+      reinterpret_cast<real*>(_active_${noiseVector.id})[2*i+1] = twiddle.f[1] - 1.0f;
+    }
+    
+    // Finish up by generating the 0,1,2 or 3 numbers on the end of the noise vector
+    for (int i=0; i<padding; i++)
+    {
+      reinterpret_cast<real*>(_active_${noiseVector.id})[vector_size-i] = generate_float_close1_open2_via_dsfmt(${generatorName}) - 1.0f;
+    }
+    delete [] array_double;
+  }
+  else {
+    // The number of floats we need does meet the minimum of what dsfmt can provide in 
+    // and array, so it by a single number at a time instead.
+    for (long _i0 = 0; _i0 < vector_size; _i0++) {
+      reinterpret_cast<real*>(_active_${noiseVector.id})[_i0] = generate_float_close1_open2_via_dsfmt(${generatorName}) - 1.0f;
+    }
+  }
+}
+  @end if
+ at end def
+
+
+ at def constructArrayUniformRandomNumbers
+  @set noiseVector = $parent.parent
+  @if $precision == 'single'  
+generate_float_array_close0_open1(${generatorName}, reinterpret_cast<real*>(_active_${noiseVector.id}), _vector_size);
+  @else
+if (!(_vector_size & 0x1) && _vector_size > dsfmt_get_min_array_size())
+  dsfmt_fill_array_open_open(${generatorName}, reinterpret_cast<real*>(_active_${noiseVector.id}), _vector_size);
+else {
+  for (long _i0 = 0; _i0 < _vector_size; _i0++) {
+    reinterpret_cast<real*>(_active_${noiseVector.id})[_i0] = dsfmt_genrand_open_open(${generatorName});
+  }
+}
+  @end if
+ at end def
+
+ at def minusOneToOneRandomNumber
+  @if $precision == 'single'
+(2.0*generate_float_close1_open2_via_dsfmt(${generatorName}) - 3.0)@slurp
+  @else
+(2.0*dsfmt_genrand_close1_open2($generatorName) - 3.0)@slurp
+  @end if
+ at end def
+
+ at def zeroToOneRandomNumber
+  @if $precision == 'single'
+(generate_float_close1_open2_via_dsfmt(${generatorName}) - 1.0)@slurp
+  @else
+dsfmt_genrand_open_open(${generatorName})@slurp
+  @end if
+ at end def
+
+ at def initialiseLocalSeeds
+  @#
+  @super
+  @#
+${generatorName} = (dsfmt_t *)xmds_malloc(sizeof(dsfmt_t));
+dsfmt_init_by_array(${generatorName}, ${generatorName}_local_seeds, ${seedCount});
+  @#
+ at end def
+
+
diff --git a/xpdeint/Stochastic/Generators/Generator.py b/xpdeint/Stochastic/Generators/Generator.py
new file mode 100644
index 0000000..d7040ed
--- /dev/null
+++ b/xpdeint/Stochastic/Generators/Generator.py
@@ -0,0 +1,468 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.ScriptElement import ScriptElement
+from xpdeint.PrintfSafeFilter import PrintfSafeFilter
+from xpdeint.CallOnceGuards import callOnceGuard
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.35564
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Stochastic/Generators/Generator.tmpl'
+__CHEETAH_srcLastModified__ = 'Wed Aug 28 15:52:21 2013'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class Generator(ScriptElement):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(Generator, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def seedCount(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def seedCount at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        return len(VFFSL(SL,"seedArray",True)) or 10
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def globals at line 30, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''uint32_t ''')
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 32, col 10
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 32, col 10.
+        write(u'''_seeds[''')
+        _v = VFFSL(SL,"seedCount",True) # u'${seedCount}' on line 32, col 33
+        if _v is not None: write(_filter(_v, rawExpr=u'${seedCount}')) # from line 32, col 33.
+        write(u'''];
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def initialiseGlobalSeeds(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def initialiseGlobalSeeds at line 36, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        featureOrdering = ['Driver']
+        # 
+        if not VFFSL(SL,"seedArray",True): # generated from line 40, col 3
+            _v = VFFSL(SL,"seedSystemRandomNumberGenerator",True) # u'${seedSystemRandomNumberGenerator}' on line 41, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${seedSystemRandomNumberGenerator}')) # from line 41, col 1.
+            # 
+            seedGenerationDict = {'extraIndent': 0}
+            _v = VFFSL(SL,"insertCodeForFeatures",False)('runtimeSeedGenerationBegin', VFFSL(SL,"featureOrdering",True), VFFSL(SL,"seedGenerationDict",True)) # u"${insertCodeForFeatures('runtimeSeedGenerationBegin', $featureOrdering, $seedGenerationDict)}" on line 44, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('runtimeSeedGenerationBegin', $featureOrdering, $seedGenerationDict)}")) # from line 44, col 1.
+            extraIndent = seedGenerationDict['extraIndent']
+            _v = VFFSL(SL,"runtimeGenerateSeeds",True) # u'${runtimeGenerateSeeds, extraIndent = extraIndent}' on line 46, col 1
+            if _v is not None: write(_filter(_v, extraIndent = extraIndent, rawExpr=u'${runtimeGenerateSeeds, extraIndent = extraIndent}')) # from line 46, col 1.
+            _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('runtimeSeedGenerationEnd', VFFSL(SL,"featureOrdering",True), VFFSL(SL,"seedGenerationDict",True)) # u"${insertCodeForFeaturesInReverseOrder('runtimeSeedGenerationEnd', $featureOrdering, $seedGenerationDict)}" on line 47, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeaturesInReverseOrder('runtimeSeedGenerationEnd', $featureOrdering, $seedGenerationDict)}")) # from line 47, col 1.
+        else: # generated from line 48, col 3
+            for seedIdx, seed in enumerate(VFFSL(SL,"seedArray",True)): # generated from line 49, col 5
+                _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 50, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 50, col 1.
+                write(u'''_seeds[''')
+                _v = VFFSL(SL,"seedIdx",True) # u'$seedIdx' on line 50, col 24
+                if _v is not None: write(_filter(_v, rawExpr=u'$seedIdx')) # from line 50, col 24.
+                write(u'''] = ''')
+                _v = VFFSL(SL,"seed",True) # u'$seed' on line 50, col 36
+                if _v is not None: write(_filter(_v, rawExpr=u'$seed')) # from line 50, col 36.
+                write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOnceGuard
+    def seedSystemRandomNumberGenerator(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def seedSystemRandomNumberGenerator at line 58, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''#if HAVE_SRANDOMDEV
+srandomdev();
+#elif HAVE_DEV_URANDOM
+{
+  size_t __state_size = 256;
+  char __state[__state_size];
+  unsigned __seed;
+  FILE *__urandom_fp = fopen("/dev/urandom", "r");
+  if (__urandom_fp == NULL) {
+    _LOG(_ERROR_LOG_LEVEL, "Unable to seed random number generator from /dev/urandom.  Is it accessible?\\n");
+    // Implicit quit
+  }
+  size_t __bytes_read = 0;
+  __bytes_read = fread(&__seed, sizeof(__seed), 1, __urandom_fp);
+  if (__bytes_read != 1) {
+    _LOG(_ERROR_LOG_LEVEL, "Unable to read from /dev/urandom while seeding the random number generator.\\n");
+    // Implicit quit
+  }
+  __bytes_read = fread(__state, sizeof(__state), 1, __urandom_fp);
+  if (__bytes_read != 1) {
+    _LOG(_ERROR_LOG_LEVEL, "Unable to read from /dev/urandom while seeding the random number generator.\\n");
+    // Implicit quit
+  }
+  fclose(__urandom_fp);
+  initstate(__seed, __state, __state_size);
+}
+#else
+#error Do not have a run-time random number source! Please supply seeds manually.
+#endif
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def initialiseLocalSeeds(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def initialiseLocalSeeds at line 90, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        featureOrdering = ['Driver']
+        seedOffset = VFFSL(SL,"insertCodeForFeatures",False)('seedOffset', VFFSL(SL,"featureOrdering",True))
+        # 
+        write(u'''uint32_t ''')
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 95, col 10
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 95, col 10.
+        write(u'''_local_seeds[''')
+        _v = VFFSL(SL,"seedCount",True) # u'${seedCount}' on line 95, col 39
+        if _v is not None: write(_filter(_v, rawExpr=u'${seedCount}')) # from line 95, col 39.
+        write(u'''] = { ''')
+        _v = ', '.join([''.join([str(VFFSL(SL,"generatorName",True)),u'_seeds[',str(VFFSL(SL,"i",True)),u']',str(VFFSL(SL,"seedOffset",True))]) for i in xrange(VFFSL(SL,"seedCount",True))]) # u"${', '.join([c'${generatorName}_seeds[$i]${seedOffset}' for i in xrange($seedCount)])}" on line 95, col 57
+        if _v is not None: write(_filter(_v, rawExpr=u"${', '.join([c'${generatorName}_seeds[$i]${seedOffset}' for i in xrange($seedCount)])}")) # from line 95, col 57.
+        write(u''' };
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def runtimeGenerateSeeds(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def runtimeGenerateSeeds at line 99, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''for (unsigned long _i0=0; _i0 < ''')
+        _v = VFFSL(SL,"seedCount",True) # u'${seedCount}' on line 100, col 33
+        if _v is not None: write(_filter(_v, rawExpr=u'${seedCount}')) # from line 100, col 33.
+        write(u'''; _i0++)
+  ''')
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 101, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 101, col 3.
+        write(u'''_seeds[_i0] = (uint32_t)random();
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def xsilOutputInfo(self, dict, **KWS):
+
+
+        """
+        Write to the XSIL file lines naming the seeds that we generated if no seed was provided
+        in the script file. These are the seeds that should be provided in the script file to get
+        the same results.
+        """
+
+        ## CHEETAH: generated from @def xsilOutputInfo($dict) at line 104, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        fp = dict['fp']
+        # 
+        if len(VFFSL(SL,"seedArray",True)): # generated from line 113, col 3
+            return
+        # 
+        write(u'''fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 117, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 117, col 9.
+        write(u''', "\\nNo seeds were provided for noise vector \'''')
+        _v = VFFSL(SL,"parent.parent.name",True) # u'${parent.parent.name}' on line 117, col 58
+        if _v is not None: write(_filter(_v, rawExpr=u'${parent.parent.name}')) # from line 117, col 58.
+        write(u'''\'. The seeds generated were:\\n");
+fprintf(''')
+        _v = VFFSL(SL,"fp",True) # u'$fp' on line 118, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'$fp')) # from line 118, col 9.
+        write(u''', "    ''')
+        _v = ', '.join(['%u' for _ in xrange(VFFSL(SL,"seedCount",True))]) # u"${', '.join(['%u' for _ in xrange($seedCount)])}" on line 118, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u"${', '.join(['%u' for _ in xrange($seedCount)])}")) # from line 118, col 19.
+        write(u'''\\n", ''')
+        _v = ', '.join([''.join([str(VFFSL(SL,"generatorName",True)),u'_seeds[',str(VFFSL(SL,"i",True)),u']']) for i in xrange(VFFSL(SL,"seedCount",True))]) # u"${', '.join([c'${generatorName}_seeds[$i]' for i in xrange($seedCount)])}" on line 118, col 72
+        if _v is not None: write(_filter(_v, rawExpr=u"${', '.join([c'${generatorName}_seeds[$i]' for i in xrange($seedCount)])}")) # from line 118, col 72.
+        write(u''');
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # POSIXGenerator.tmpl
+        # 
+        # Created by Graham Dennis on 2010-11-28.
+        # 
+        # Copyright (c) 2010-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+''')
+        #  We only need to seed the system random number generator once, even if there are multiple Generator objects.
+        write(u'''
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_Generator= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(Generator, '_initCheetahAttributes'):
+    templateAPIClass = getattr(Generator, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(Generator)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=Generator()).run()
+
+
diff --git a/xpdeint/Stochastic/Generators/Generator.tmpl b/xpdeint/Stochastic/Generators/Generator.tmpl
new file mode 100644
index 0000000..0b4223f
--- /dev/null
+++ b/xpdeint/Stochastic/Generators/Generator.tmpl
@@ -0,0 +1,119 @@
+@*
+POSIXGenerator.tmpl
+
+Created by Graham Dennis on 2010-11-28.
+
+Copyright (c) 2010-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.ScriptElement
+ at from xpdeint.PrintfSafeFilter import PrintfSafeFilter
+ at from xpdeint.CallOnceGuards import callOnceGuard
+
+ at def seedCount
+  @return len($seedArray) or 10
+ at end def
+
+ at def globals
+  @#
+uint32_t ${generatorName}_seeds[${seedCount}];
+  @#
+ at end def
+
+ at def initialiseGlobalSeeds
+  @#
+  @set $featureOrdering = ['Driver']
+  @#
+  @if not $seedArray
+${seedSystemRandomNumberGenerator}@slurp
+    @#
+    @set $seedGenerationDict = {'extraIndent': 0}
+${insertCodeForFeatures('runtimeSeedGenerationBegin', $featureOrdering, $seedGenerationDict)}@slurp
+    @silent extraIndent = seedGenerationDict['extraIndent']
+${runtimeGenerateSeeds, extraIndent = extraIndent}@slurp
+${insertCodeForFeaturesInReverseOrder('runtimeSeedGenerationEnd', $featureOrdering, $seedGenerationDict)}@slurp
+  @else
+    @for seedIdx, seed in enumerate($seedArray)
+${generatorName}_seeds[$seedIdx] = $seed;
+    @end for
+  @end if
+  @#
+ at end def
+
+@# We only need to seed the system random number generator once, even if there are multiple Generator objects.
+@@callOnceGuard
+ at def seedSystemRandomNumberGenerator
+#if HAVE_SRANDOMDEV
+srandomdev();
+#elif HAVE_DEV_URANDOM
+{
+  size_t __state_size = 256;
+  char __state[__state_size];
+  unsigned __seed;
+  FILE *__urandom_fp = fopen("/dev/urandom", "r");
+  if (__urandom_fp == NULL) {
+    _LOG(_ERROR_LOG_LEVEL, "Unable to seed random number generator from /dev/urandom.  Is it accessible?\n");
+    // Implicit quit
+  }
+  size_t __bytes_read = 0;
+  __bytes_read = fread(&__seed, sizeof(__seed), 1, __urandom_fp);
+  if (__bytes_read != 1) {
+    _LOG(_ERROR_LOG_LEVEL, "Unable to read from /dev/urandom while seeding the random number generator.\n");
+    // Implicit quit
+  }
+  __bytes_read = fread(__state, sizeof(__state), 1, __urandom_fp);
+  if (__bytes_read != 1) {
+    _LOG(_ERROR_LOG_LEVEL, "Unable to read from /dev/urandom while seeding the random number generator.\n");
+    // Implicit quit
+  }
+  fclose(__urandom_fp);
+  initstate(__seed, __state, __state_size);
+}
+#else
+#error Do not have a run-time random number source! Please supply seeds manually.
+#endif
+ at end def
+
+ at def initialiseLocalSeeds
+  @#
+  @set $featureOrdering = ['Driver']
+  @silent seedOffset = $insertCodeForFeatures('seedOffset', $featureOrdering)
+  @#
+uint32_t ${generatorName}_local_seeds[${seedCount}] = { ${', '.join([c'${generatorName}_seeds[$i]${seedOffset}' for i in xrange($seedCount)])} };
+  @#
+ at end def
+
+ at def runtimeGenerateSeeds
+for (unsigned long _i0=0; _i0 < ${seedCount}; _i0++)
+  ${generatorName}_seeds[_i0] = (uint32_t)random();
+ at end def
+
+ at def xsilOutputInfo($dict)
+@*doc:
+Write to the XSIL file lines naming the seeds that we generated if no seed was provided
+in the script file. These are the seeds that should be provided in the script file to get
+the same results.
+*@
+  @#
+  @set $fp = dict['fp']
+  @#
+  @if len($seedArray)
+    @return
+  @end if
+  @#
+fprintf($fp, "\nNo seeds were provided for noise vector '${parent.parent.name}'. The seeds generated were:\n");
+fprintf($fp, "    ${', '.join(['%u' for _ in xrange($seedCount)])}\n", ${', '.join([c'${generatorName}_seeds[$i]' for i in xrange($seedCount)])});
+ at end def
diff --git a/xpdeint/Stochastic/Generators/MKLGenerator.py b/xpdeint/Stochastic/Generators/MKLGenerator.py
new file mode 100644
index 0000000..e9a9ba5
--- /dev/null
+++ b/xpdeint/Stochastic/Generators/MKLGenerator.py
@@ -0,0 +1,394 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Stochastic.Generators.Generator import Generator
+from xpdeint.CallOnceGuards import callOnceGuard
+import random
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.370998
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Stochastic/Generators/MKLGenerator.tmpl'
+__CHEETAH_srcLastModified__ = 'Wed Aug 28 15:52:21 2013'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class MKLGenerator(Generator):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(MKLGenerator, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Generator for Intel MKL random numbers at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Generator for Intel MKL random numbers''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def generatorType(self, **KWS):
+
+
+
+        ## Generated from @def generatorType: VSLStreamStatePtr at line 28, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''VSLStreamStatePtr''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def seedCount(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def seedCount at line 31, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        return 1
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def globals at line 35, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(MKLGenerator, self).globals()
+        if _v is not None: write(_filter(_v))
+        # 
+        _v = VFFSL(SL,"generatorType",True) # u'$generatorType' on line 39, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'$generatorType')) # from line 39, col 1.
+        write(u''' ''')
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 39, col 16
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 39, col 16.
+        write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def constructArrayUniformRandomNumbers(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def constructArrayUniformRandomNumbers at line 43, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        noiseVector = VFFSL(SL,"parent.parent",True)
+        write(u'''vdRngUniform(VSL_METHOD_DUNIFORM_STD, ''')
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 45, col 39
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 45, col 39.
+        write(u''', _vector_size, reinterpret_cast<real*>(_active_''')
+        _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 45, col 103
+        if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 45, col 103.
+        write(u'''), 0.0, 1.0);
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOnceGuard
+    def static_includes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def static_includes at line 53, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(MKLGenerator, self).static_includes()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''#include <mkl_vsl.h>
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def initialiseLocalSeeds(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def initialiseLocalSeeds at line 62, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(MKLGenerator, self).initialiseLocalSeeds()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''vslNewStream(&''')
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 66, col 15
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 66, col 15.
+        write(u''', VSL_BRNG_MT19937, ''')
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 66, col 51
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 66, col 51.
+        write(u'''_local_seeds[0]);
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # MKLGenerator.tmpl
+        # 
+        # Created by Joe Hope on 2009-08-22.
+        # 
+        # Copyright (c) 2009-2012, Joe Hope
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+''')
+        # 
+        #   Static includes
+        #   The callOnceGuard won't work until the same includes are gone from the stochastic feature.
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    uselib = ['mkl_vsl']
+
+    _mainCheetahMethod_for_MKLGenerator= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(MKLGenerator, '_initCheetahAttributes'):
+    templateAPIClass = getattr(MKLGenerator, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(MKLGenerator)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=MKLGenerator()).run()
+
+
diff --git a/xpdeint/Stochastic/Generators/MKLGenerator.tmpl b/xpdeint/Stochastic/Generators/MKLGenerator.tmpl
new file mode 100644
index 0000000..e6067d3
--- /dev/null
+++ b/xpdeint/Stochastic/Generators/MKLGenerator.tmpl
@@ -0,0 +1,68 @@
+@*
+MKLGenerator.tmpl
+
+Created by Joe Hope on 2009-08-22.
+
+Copyright (c) 2009-2012, Joe Hope
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Stochastic.Generators.Generator
+
+ at from xpdeint.CallOnceGuards import callOnceGuard
+ at import random
+
+ at def description: Generator for Intel MKL random numbers
+ at def generatorType: VSLStreamStatePtr
+ at attr uselib = ['mkl_vsl']
+
+ at def seedCount
+  @return 1
+ at end def
+
+ at def globals
+  @#
+  @super
+  @#
+$generatorType ${generatorName};
+  @#
+ at end def
+
+ at def constructArrayUniformRandomNumbers
+  @set noiseVector = $parent.parent
+vdRngUniform(VSL_METHOD_DUNIFORM_STD, ${generatorName}, _vector_size, reinterpret_cast<real*>(_active_${noiseVector.id}), 0.0, 1.0);
+ at end def
+
+@*
+  Static includes
+*@
+@#  The callOnceGuard won't work until the same includes are gone from the stochastic feature.
+@@callOnceGuard
+ at def static_includes
+  @#
+  @super
+  @#
+#include <mkl_vsl.h>
+  @#
+ at end def
+
+
+ at def initialiseLocalSeeds
+  @#
+  @super
+  @#
+vslNewStream(&${generatorName}, VSL_BRNG_MT19937, ${generatorName}_local_seeds[0]);
+  @#
+ at end def
diff --git a/xpdeint/Stochastic/Generators/POSIXGenerator.py b/xpdeint/Stochastic/Generators/POSIXGenerator.py
new file mode 100644
index 0000000..1a0ad1c
--- /dev/null
+++ b/xpdeint/Stochastic/Generators/POSIXGenerator.py
@@ -0,0 +1,406 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Stochastic.Generators.Generator import Generator
+import random
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.400994
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Stochastic/Generators/POSIXGenerator.tmpl'
+__CHEETAH_srcLastModified__ = 'Thu Aug 29 13:13:17 2013'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class POSIXGenerator(Generator):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(POSIXGenerator, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Generic POSIX noise at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Generic POSIX noise''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def generatorType(self, **KWS):
+
+
+
+        ## Generated from @def generatorType: unsigned short* at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''unsigned short*''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def globals at line 32, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(POSIXGenerator, self).globals()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''unsigned short ''')
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 36, col 16
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 36, col 16.
+        write(u'''[3];
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def minusOneToOneRandomNumber(self, **KWS):
+
+
+
+        ## Generated from @def minusOneToOneRandomNumber: 2.0*erand48($generatorName) - 1.0 at line 40, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''2.0*erand48(''')
+        _v = VFFSL(SL,"generatorName",True) # u'$generatorName' on line 40, col 45
+        if _v is not None: write(_filter(_v, rawExpr=u'$generatorName')) # from line 40, col 45.
+        write(u''') - 1.0''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def zeroToOneRandomNumber(self, **KWS):
+
+
+
+        ## Generated from @def zeroToOneRandomNumber(): erand48(${generatorName}) at line 42, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''erand48(''')
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 42, col 39
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 42, col 39.
+        write(u''')''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def constructArrayUniformRandomNumbers(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def constructArrayUniformRandomNumbers at line 44, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        noiseVector = VFFSL(SL,"parent.parent",True)
+        write(u'''for (long _i0 = 0; _i0 < _vector_size; _i0++) {
+  _active_''')
+        _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 47, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 47, col 11.
+        write(u'''[_i0] = erand48(''')
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 47, col 44
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 47, col 44.
+        write(u''');
+}
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def initialiseLocalSeeds(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def initialiseLocalSeeds at line 54, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(POSIXGenerator, self).initialiseLocalSeeds()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''bzero(''')
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 58, col 7
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 58, col 7.
+        write(u''', sizeof(''')
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 58, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 58, col 32.
+        write(u'''));
+for (unsigned long _i0=0; _i0<MIN(3, ''')
+        _v = VFFSL(SL,"seedCount",True) # u'${seedCount}' on line 59, col 38
+        if _v is not None: write(_filter(_v, rawExpr=u'${seedCount}')) # from line 59, col 38.
+        write(u'''); _i0++)
+  ''')
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 60, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 60, col 3.
+        write(u'''[_i0] = (unsigned short)''')
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 60, col 43
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 60, col 43.
+        write(u'''_local_seeds[_i0];
+
+erand48(''')
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 62, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 62, col 9.
+        write(u''');
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # POSIXGenerator.tmpl
+        # 
+        # Created by Joe Hope on 2009-08-20.
+        # 
+        # Copyright (c) 2009-2012, Joe Hope
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+''')
+        # 
+        #   Globals
+        write(u'''
+
+
+
+''')
+        # 
+        #   Initialise seeds
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_POSIXGenerator= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(POSIXGenerator, '_initCheetahAttributes'):
+    templateAPIClass = getattr(POSIXGenerator, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(POSIXGenerator)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=POSIXGenerator()).run()
+
+
diff --git a/xpdeint/Stochastic/Generators/POSIXGenerator.tmpl b/xpdeint/Stochastic/Generators/POSIXGenerator.tmpl
new file mode 100644
index 0000000..ca64552
--- /dev/null
+++ b/xpdeint/Stochastic/Generators/POSIXGenerator.tmpl
@@ -0,0 +1,64 @@
+@*
+POSIXGenerator.tmpl
+
+Created by Joe Hope on 2009-08-20.
+
+Copyright (c) 2009-2012, Joe Hope
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Stochastic.Generators.Generator
+
+ at import random
+
+ at def description: Generic POSIX noise
+ at def generatorType: unsigned short*
+
+@*
+  Globals
+*@
+ at def globals
+  @#
+  @super
+  @#
+unsigned short ${generatorName}[3];
+  @#
+ at end def
+
+ at def minusOneToOneRandomNumber: 2.0*erand48($generatorName) - 1.0
+
+ at def zeroToOneRandomNumber(): erand48(${generatorName})
+
+ at def constructArrayUniformRandomNumbers
+  @set noiseVector = $parent.parent
+for (long _i0 = 0; _i0 < _vector_size; _i0++) {
+  _active_${noiseVector.id}[_i0] = erand48(${generatorName});
+}
+ at end def
+
+@*
+  Initialise seeds
+*@
+ at def initialiseLocalSeeds
+  @#
+  @super
+  @#
+bzero(${generatorName}, sizeof(${generatorName}));
+for (unsigned long _i0=0; _i0<MIN(3, ${seedCount}); _i0++)
+  ${generatorName}[_i0] = (unsigned short)${generatorName}_local_seeds[_i0];
+
+erand48(${generatorName});
+  @#
+ at end def
diff --git a/xpdeint/Stochastic/Generators/SolirteGenerator.py b/xpdeint/Stochastic/Generators/SolirteGenerator.py
new file mode 100644
index 0000000..9ba5401
--- /dev/null
+++ b/xpdeint/Stochastic/Generators/SolirteGenerator.py
@@ -0,0 +1,341 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Stochastic.Generators.Generator import Generator
+from xpdeint.CallOnceGuards import callOnceGuard
+import random
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.421733
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Stochastic/Generators/SolirteGenerator.tmpl'
+__CHEETAH_srcLastModified__ = 'Wed Aug 28 15:52:21 2013'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class SolirteGenerator(Generator):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(SolirteGenerator, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Generic Solirte noise at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Generic Solirte noise''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def generatorType(self, **KWS):
+
+
+
+        ## Generated from @def generatorType: CPRNG<CSFMTParams_19937>* at line 28, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''CPRNG<CSFMTParams_19937>*''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def globals at line 30, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(SolirteGenerator, self).globals()
+        if _v is not None: write(_filter(_v))
+        # 
+        _v = VFFSL(SL,"generatorType",True) # u'$generatorType' on line 34, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'$generatorType')) # from line 34, col 1.
+        write(u''' ''')
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 34, col 16
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 34, col 16.
+        write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOnceGuard
+    def static_includes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def static_includes at line 43, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(SolirteGenerator, self).static_includes()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u"""#define CFG_TIMETRACK_DISABLE
+// We have disabled Solirte's MMX version.
+// Use SSE2 or get a newer computer.
+#undef CFG_HAVE_MMX
+#define CFG_HAVE_MMX 0
+#include <solirte/SFMTparams.h>
+#include <solirte/prng.h>
+#include <solirte/ziggurat.cpp>
+""")
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def initialiseLocalSeeds(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def initialiseLocalSeeds at line 61, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        featureOrdering = ['Driver']
+        seedOffset = VFFSL(SL,"insertCodeForFeatures",False)('seedOffset', featureOrdering)
+        # 
+        if not len(VFFSL(SL,"seedArray",True)): # generated from line 66, col 3
+            self.generatedSeeds = [random.randrange(0, pow(2, 31)) for i in xrange(1)]
+            seedArray = self.generatedSeeds
+        # 
+        seedString = str(VFFSL(SL,"seedArray",True)[0])+seedOffset
+        # 
+        _v = VFFSL(SL,"generatorName",True) # u'${generatorName}' on line 73, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${generatorName}')) # from line 73, col 1.
+        write(u''' = new CPRNG<CSFMTParams_19937>(''')
+        _v = VFFSL(SL,"seedString",True) # u'$seedString' on line 73, col 49
+        if _v is not None: write(_filter(_v, rawExpr=u'$seedString')) # from line 73, col 49.
+        write(u''');
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # SolirteGenerator.tmpl
+        # 
+        # Created by Joe Hope on 2009-08-22.
+        # 
+        # Copyright (c) 2009-2012, Joe Hope
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+''')
+        # 
+        #   Static includes
+        #   The callOnceGuard won't work until the same includes are gone from the stochastic feature.
+        write(u'''
+''')
+        # 
+        #   Initialise seeds
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_SolirteGenerator= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(SolirteGenerator, '_initCheetahAttributes'):
+    templateAPIClass = getattr(SolirteGenerator, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(SolirteGenerator)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=SolirteGenerator()).run()
+
+
diff --git a/xpdeint/Stochastic/Generators/SolirteGenerator.tmpl b/xpdeint/Stochastic/Generators/SolirteGenerator.tmpl
new file mode 100644
index 0000000..74aa2e6
--- /dev/null
+++ b/xpdeint/Stochastic/Generators/SolirteGenerator.tmpl
@@ -0,0 +1,75 @@
+@*
+SolirteGenerator.tmpl
+
+Created by Joe Hope on 2009-08-22.
+
+Copyright (c) 2009-2012, Joe Hope
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Stochastic.Generators.Generator
+
+ at from xpdeint.CallOnceGuards import callOnceGuard
+ at import random
+
+ at def description: Generic Solirte noise
+ at def generatorType: CPRNG<CSFMTParams_19937>*
+
+ at def globals
+  @#
+  @super
+  @#
+$generatorType ${generatorName};
+  @#
+ at end def
+
+@*
+  Static includes
+*@
+@#  The callOnceGuard won't work until the same includes are gone from the stochastic feature.
+@@callOnceGuard
+ at def static_includes
+  @#
+  @super
+  @#
+#define CFG_TIMETRACK_DISABLE
+// We have disabled Solirte's MMX version.
+// Use SSE2 or get a newer computer.
+#undef CFG_HAVE_MMX
+#define CFG_HAVE_MMX 0
+#include <solirte/SFMTparams.h>
+#include <solirte/prng.h>
+#include <solirte/ziggurat.cpp>
+  @#
+ at end def
+
+@*
+  Initialise seeds
+*@
+ at def initialiseLocalSeeds
+  @#
+  @set $featureOrdering = ['Driver']
+  @silent seedOffset = $insertCodeForFeatures('seedOffset', featureOrdering)
+  @#
+  @if not len($seedArray)
+    @set self.generatedSeeds = [random.randrange(0, pow(2, 31)) for i in xrange(1)]
+    @set seedArray = self.generatedSeeds
+  @end if
+  @#
+  @set $seedString = str($seedArray[0])+seedOffset
+  @#
+${generatorName} = new CPRNG<CSFMTParams_19937>($seedString);
+  @#
+ at end def
diff --git a/xpdeint/Stochastic/Generators/__init__.py b/xpdeint/Stochastic/Generators/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/xpdeint/Stochastic/RandomVariables/GaussianBoxMuellerRandomVariable.py b/xpdeint/Stochastic/RandomVariables/GaussianBoxMuellerRandomVariable.py
new file mode 100644
index 0000000..effa9fc
--- /dev/null
+++ b/xpdeint/Stochastic/RandomVariables/GaussianBoxMuellerRandomVariable.py
@@ -0,0 +1,273 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Stochastic.RandomVariables.GaussianRandomVariable import GaussianRandomVariable
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.452896
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Stochastic/RandomVariables/GaussianBoxMuellerRandomVariable.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class GaussianBoxMuellerRandomVariable(GaussianRandomVariable):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(GaussianBoxMuellerRandomVariable, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def boxMuellerAlgorithm(self, **KWS):
+
+
+        """
+        Return the code to generate two gaussian noises
+          using the Box-Mueller algorithm
+        """
+
+        ## CHEETAH: generated from @def boxMuellerAlgorithm at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''real _v1, _v2, _rsq;
+do {
+  _v1 = ''')
+        _v = VFFSL(SL,"generator.minusOneToOneRandomNumber",True) # u'${generator.minusOneToOneRandomNumber}' on line 32, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${generator.minusOneToOneRandomNumber}')) # from line 32, col 9.
+        write(u''';
+  _v2 = ''')
+        _v = VFFSL(SL,"generator.minusOneToOneRandomNumber",True) # u'${generator.minusOneToOneRandomNumber}' on line 33, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${generator.minusOneToOneRandomNumber}')) # from line 33, col 9.
+        write(u''';
+  _rsq = _v1*_v1 + _v2*_v2;
+} while(_rsq >= 1.0 || _rsq == 0.0);
+const real _fac = sqrt(-2.0*_var*log(_rsq)/_rsq);
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def makeFixedVarianceNoises(self, **KWS):
+
+
+        """
+        Return the code for the contents of the makeNoises function for
+          a gaussian noise generated with the Box Mueller algorithm
+        """
+
+        ## CHEETAH: generated from @def makeFixedVarianceNoises at line 40, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        noiseVector = VFFSL(SL,"parent",True)
+        write(u'''const ptrdiff_t _evenNoises = _vector_size & ~1;
+for (ptrdiff_t _i0 = 0; _i0 < _evenNoises; _i0 += 2) {
+  ''')
+        _v = VFFSL(SL,"boxMuellerAlgorithm",True) # u'${boxMuellerAlgorithm, autoIndent=True}' on line 48, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${boxMuellerAlgorithm, autoIndent=True}')) # from line 48, col 3.
+        write(u'''  reinterpret_cast<real*>(_active_''')
+        _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 49, col 35
+        if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 49, col 35.
+        write(u''')[_i0 + 0] = _v1*_fac;
+  reinterpret_cast<real*>(_active_''')
+        _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 50, col 35
+        if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 50, col 35.
+        write(u''')[_i0 + 1] = _v2*_fac;
+}
+
+// If _n is odd, we need to generate the last random number
+if (_vector_size & 1) {
+  static real _spareNoise = 0.0;
+  static bool _spareNoiseAvailable = false;
+  static real _old_var = 0.0;
+  
+  if (_spareNoiseAvailable && _old_var == _var) {
+    reinterpret_cast<real*>(_active_''')
+        _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 60, col 37
+        if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 60, col 37.
+        write(u''')[_vector_size - 1] = _spareNoise;
+    _spareNoiseAvailable = false;
+  } else {
+    ''')
+        _v = VFFSL(SL,"boxMuellerAlgorithm",True) # u'${boxMuellerAlgorithm, autoIndent=True}' on line 63, col 5
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${boxMuellerAlgorithm, autoIndent=True}')) # from line 63, col 5.
+        write(u'''    reinterpret_cast<real*>(_active_''')
+        _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 64, col 37
+        if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 64, col 37.
+        write(u''')[_vector_size - 1] = _v1*_fac;
+    _spareNoise = _v2*_fac;
+    
+    _spareNoiseAvailable = true;
+    _old_var = _var;
+  }
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # GaussianBoxMuellerRandomVariable.tmpl
+        # 
+        # Created by Joe Hope on 2009-08-20.
+        # 
+        # Copyright (c) 2009-2012, Joe Hope
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_GaussianBoxMuellerRandomVariable= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(GaussianBoxMuellerRandomVariable, '_initCheetahAttributes'):
+    templateAPIClass = getattr(GaussianBoxMuellerRandomVariable, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(GaussianBoxMuellerRandomVariable)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=GaussianBoxMuellerRandomVariable()).run()
+
+
diff --git a/xpdeint/Stochastic/RandomVariables/GaussianBoxMuellerRandomVariable.tmpl b/xpdeint/Stochastic/RandomVariables/GaussianBoxMuellerRandomVariable.tmpl
new file mode 100644
index 0000000..1d223a6
--- /dev/null
+++ b/xpdeint/Stochastic/RandomVariables/GaussianBoxMuellerRandomVariable.tmpl
@@ -0,0 +1,72 @@
+@*
+GaussianBoxMuellerRandomVariable.tmpl
+
+Created by Joe Hope on 2009-08-20.
+
+Copyright (c) 2009-2012, Joe Hope
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Stochastic.RandomVariables.GaussianRandomVariable
+
+ at def boxMuellerAlgorithm
+@*doc:
+  Return the code to generate two gaussian noises
+  using the Box-Mueller algorithm
+*@
+  @#
+real _v1, _v2, _rsq;
+do {
+  _v1 = ${generator.minusOneToOneRandomNumber};
+  _v2 = ${generator.minusOneToOneRandomNumber};
+  _rsq = _v1*_v1 + _v2*_v2;
+} while(_rsq >= 1.0 || _rsq == 0.0);
+const real _fac = sqrt(-2.0*_var*log(_rsq)/_rsq);
+  @#
+ at end def
+
+ at def makeFixedVarianceNoises
+@*doc:
+  Return the code for the contents of the makeNoises function for
+  a gaussian noise generated with the Box Mueller algorithm
+*@
+  @set noiseVector = $parent
+const ptrdiff_t _evenNoises = _vector_size & ~1;
+for (ptrdiff_t _i0 = 0; _i0 < _evenNoises; _i0 += 2) {
+  ${boxMuellerAlgorithm, autoIndent=True}@slurp
+  reinterpret_cast<real*>(_active_${noiseVector.id})[_i0 + 0] = _v1*_fac;
+  reinterpret_cast<real*>(_active_${noiseVector.id})[_i0 + 1] = _v2*_fac;
+}
+
+// If _n is odd, we need to generate the last random number
+if (_vector_size & 1) {
+  static real _spareNoise = 0.0;
+  static bool _spareNoiseAvailable = false;
+  static real _old_var = 0.0;
+  
+  if (_spareNoiseAvailable && _old_var == _var) {
+    reinterpret_cast<real*>(_active_${noiseVector.id})[_vector_size - 1] = _spareNoise;
+    _spareNoiseAvailable = false;
+  } else {
+    ${boxMuellerAlgorithm, autoIndent=True}@slurp
+    reinterpret_cast<real*>(_active_${noiseVector.id})[_vector_size - 1] = _v1*_fac;
+    _spareNoise = _v2*_fac;
+    
+    _spareNoiseAvailable = true;
+    _old_var = _var;
+  }
+}
+  @#
+ at end def
diff --git a/xpdeint/Stochastic/RandomVariables/GaussianMKLRandomVariable.py b/xpdeint/Stochastic/RandomVariables/GaussianMKLRandomVariable.py
new file mode 100644
index 0000000..6db4180
--- /dev/null
+++ b/xpdeint/Stochastic/RandomVariables/GaussianMKLRandomVariable.py
@@ -0,0 +1,192 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Stochastic.RandomVariables.GaussianRandomVariable import GaussianRandomVariable
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.455465
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Stochastic/RandomVariables/GaussianMKLRandomVariable.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class GaussianMKLRandomVariable(GaussianRandomVariable):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(GaussianMKLRandomVariable, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def makeFixedVarianceNoises(self, **KWS):
+
+
+        """
+        Return the code for the contents of the makeNoises function for
+          a gaussian noise generated with the MKL generator
+        """
+
+        ## CHEETAH: generated from @def makeFixedVarianceNoises at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        noiseVector = VFFSL(SL,"parent",True)
+        write(u'''vdRngGaussian(VSL_METHOD_DGAUSSIAN_BOXMULLER2, ''')
+        _v = VFFSL(SL,"generator.generatorName",True) # u'${generator.generatorName}' on line 30, col 48
+        if _v is not None: write(_filter(_v, rawExpr=u'${generator.generatorName}')) # from line 30, col 48.
+        write(u''', _vector_size, reinterpret_cast<real*>(_active_''')
+        _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 30, col 122
+        if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 30, col 122.
+        write(u'''), 0.0, sqrt(_var));
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # GaussianMKLRandomVariable.tmpl
+        # 
+        # Created by Joe Hope on 2009-08-22.
+        # 
+        # Copyright (c) 2009-2012, Joe Hope
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_GaussianMKLRandomVariable= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(GaussianMKLRandomVariable, '_initCheetahAttributes'):
+    templateAPIClass = getattr(GaussianMKLRandomVariable, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(GaussianMKLRandomVariable)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=GaussianMKLRandomVariable()).run()
+
+
diff --git a/xpdeint/Stochastic/RandomVariables/GaussianMKLRandomVariable.tmpl b/xpdeint/Stochastic/RandomVariables/GaussianMKLRandomVariable.tmpl
new file mode 100644
index 0000000..cb5b96b
--- /dev/null
+++ b/xpdeint/Stochastic/RandomVariables/GaussianMKLRandomVariable.tmpl
@@ -0,0 +1,32 @@
+@*
+GaussianMKLRandomVariable.tmpl
+
+Created by Joe Hope on 2009-08-22.
+
+Copyright (c) 2009-2012, Joe Hope
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Stochastic.RandomVariables.GaussianRandomVariable
+
+ at def makeFixedVarianceNoises
+@*doc:
+  Return the code for the contents of the makeNoises function for
+  a gaussian noise generated with the MKL generator
+*@
+  @set noiseVector = $parent
+vdRngGaussian(VSL_METHOD_DGAUSSIAN_BOXMULLER2, ${generator.generatorName}, _vector_size, reinterpret_cast<real*>(_active_${noiseVector.id}), 0.0, sqrt(_var));
+  @#
+ at end def
diff --git a/xpdeint/Stochastic/RandomVariables/GaussianRandomVariable.py b/xpdeint/Stochastic/RandomVariables/GaussianRandomVariable.py
new file mode 100644
index 0000000..4bd5fe7
--- /dev/null
+++ b/xpdeint/Stochastic/RandomVariables/GaussianRandomVariable.py
@@ -0,0 +1,282 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.ScriptElement import ScriptElement
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.475867
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Stochastic/RandomVariables/GaussianRandomVariable.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class GaussianRandomVariable(ScriptElement):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(GaussianRandomVariable, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def splitNoise(self, function, **KWS):
+
+
+        """
+        Return the code to generate a new smaller gaussian noise from a previous noise.
+        
+        The previous noise had a time step of ``old_smallest_step`` a variable available in the C
+        code, not in the template itself.
+        """
+
+        ## CHEETAH: generated from @def splitNoise($function) at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        noiseVector = VFFSL(SL,"parent",True)
+        # 
+        write(u'''// Split a gaussian noise
+''')
+        #  Generate a new noise of the appropriate variance
+        _v = VFN(VFN(VFFSL(SL,"noiseVector",True),"functions",True)['evaluate'],"call",False)(_step = '(_new_step * _old_step)/(_old_step - _new_step)') # u"${noiseVector.functions['evaluate'].call(_step = '(_new_step * _old_step)/(_old_step - _new_step)')}" on line 36, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${noiseVector.functions['evaluate'].call(_step = '(_new_step * _old_step)/(_old_step - _new_step)')}")) # from line 36, col 1.
+        write(u'''
+
+''')
+        #  Then add the old noise.
+        #  When adding the old noise, the first step is to get a pointer to the old noise itself.
+        #  This pointer is called _old_${noiseVector.id}
+        write(u'''// Now complete creation of the new noise.
+
+''')
+        #  Now do the actual adding. This code creates a loop over the noiseVector
+        #  adding the old vector at each point.
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)([VFFSL(SL,"noiseVector",True)], 
+"""_active_${vector.id}[$index] += _old_array[$index];
+""", basis = noiseVector.initialBasis)
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${loopOverVectorsWithInnerContentTemplate([$noiseVector], \n"""_active_${vector.id}[$index] += _old_array[$index];\n""", basis = noiseVector.initialBasis), autoIndent=True}')) # from line 45, col 1.
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def makeNoises(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def makeNoises at line 52, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        #  Subclasses can implement makeFixedVarianceNoises and the parent will fix up the noises.
+        #    Alternatively, subclasses may implement makeNoises if they can do the entire thing correctly.
+        noiseVector = VFFSL(SL,"parent",True)
+        # 
+        write(u'''const real _var = ''')
+        _v = {'complex': 0.5, 'real': 1.0}[noiseVector.type] # u"${{'complex': 0.5, 'real': 1.0}[noiseVector.type]}" on line 58, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u"${{'complex': 0.5, 'real': 1.0}[noiseVector.type]}")) # from line 58, col 19.
+        write(u''' / (''')
+        _v = VFFSL(SL,"noiseVector.spatiallyIndependentVolumeElement",True) # u'${noiseVector.spatiallyIndependentVolumeElement}' on line 58, col 73
+        if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.spatiallyIndependentVolumeElement}')) # from line 58, col 73.
+        if not noiseVector.static: # generated from line 59, col 3
+            write(u'''* _step''')
+        write(u''');
+
+''')
+        _v = VFFSL(SL,"makeFixedVarianceNoises",True) # u'${makeFixedVarianceNoises}' on line 64, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${makeFixedVarianceNoises}')) # from line 64, col 1.
+        # 
+        nonUniformDimReps = noiseVector.nonUniformDimReps
+        if nonUniformDimReps: # generated from line 67, col 3
+            ## START CAPTURE REGION: _77271064 loopString at line 68, col 5 in the source.
+            _orig_trans_77271064 = trans
+            _wasBuffering_77271064 = self._CHEETAH__isBuffering
+            self._CHEETAH__isBuffering = True
+            trans = _captureCollector_77271064 = DummyTransaction()
+            write = _captureCollector_77271064.response().write
+            fixupString = ' * '.join(''.join([str(VFFSL(SL,"dimRep.stepSizeArrayName",True)),u'_invsqrt[',str(VFFSL(SL,"dimRep.index",True)),u' + ',str(VFFSL(SL,"dimRep.localOffset",True)),u']']) for dimRep in nonUniformDimReps)
+            for component in noiseVector.components: # generated from line 70, col 7
+                _v = VFFSL(SL,"component",True) # u'${component}' on line 71, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${component}')) # from line 71, col 1.
+                write(u''' *= ''')
+                _v = VFFSL(SL,"fixupString",True) # u'${fixupString}' on line 71, col 17
+                if _v is not None: write(_filter(_v, rawExpr=u'${fixupString}')) # from line 71, col 17.
+                write(u''';
+''')
+            trans = _orig_trans_77271064
+            write = trans.response().write
+            self._CHEETAH__isBuffering = _wasBuffering_77271064 
+            loopString = _captureCollector_77271064.response().getvalue()
+            del _orig_trans_77271064
+            del _captureCollector_77271064
+            del _wasBuffering_77271064
+            _v = VFFSL(SL,"loopOverFieldInBasisWithVectorsAndInnerContent",False)(noiseVector.field, noiseVector.initialBasis, [noiseVector], loopString) # u'${loopOverFieldInBasisWithVectorsAndInnerContent(noiseVector.field, noiseVector.initialBasis, [noiseVector], loopString)}' on line 74, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${loopOverFieldInBasisWithVectorsAndInnerContent(noiseVector.field, noiseVector.initialBasis, [noiseVector], loopString)}')) # from line 74, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # GaussianRandomVariable.tmpl
+        # 
+        # Created by Joe Hope on 2009-08-20.
+        # 
+        # Copyright (c) 2009-2012, Joe Hope
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_GaussianRandomVariable= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(GaussianRandomVariable, '_initCheetahAttributes'):
+    templateAPIClass = getattr(GaussianRandomVariable, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(GaussianRandomVariable)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=GaussianRandomVariable()).run()
+
+
diff --git a/xpdeint/Stochastic/RandomVariables/GaussianRandomVariable.tmpl b/xpdeint/Stochastic/RandomVariables/GaussianRandomVariable.tmpl
new file mode 100644
index 0000000..ec0aef4
--- /dev/null
+++ b/xpdeint/Stochastic/RandomVariables/GaussianRandomVariable.tmpl
@@ -0,0 +1,77 @@
+@*
+GaussianRandomVariable.tmpl
+
+Created by Joe Hope on 2009-08-20.
+
+Copyright (c) 2009-2012, Joe Hope
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.ScriptElement
+
+ at def splitNoise($function)
+@*doc:
+Return the code to generate a new smaller gaussian noise from a previous noise.
+
+The previous noise had a time step of ``old_smallest_step`` a variable available in the C
+code, not in the template itself.
+*@
+  @#
+  @set $noiseVector = $parent
+  @#
+// Split a gaussian noise
+  @# Generate a new noise of the appropriate variance
+${noiseVector.functions['evaluate'].call(_step = '(_new_step * _old_step)/(_old_step - _new_step)')}
+
+  @# Then add the old noise.
+  @# When adding the old noise, the first step is to get a pointer to the old noise itself.
+  @# This pointer is called _old_${noiseVector.id}
+// Now complete creation of the new noise.
+
+  @# Now do the actual adding. This code creates a loop over the noiseVector
+  @# adding the old vector at each point.
+${loopOverVectorsWithInnerContentTemplate([$noiseVector], 
+"""_active_${vector.id}[$index] += _old_array[$index];
+""", basis = noiseVector.initialBasis), autoIndent=True}@slurp
+
+  @#
+ at end def
+
+ at def makeNoises
+@* Subclasses can implement makeFixedVarianceNoises and the parent will fix up the noises.
+   Alternatively, subclasses may implement makeNoises if they can do the entire thing correctly.
+*@
+  @set noiseVector = $parent
+  @#
+const real _var = ${{'complex': 0.5, 'real': 1.0}[noiseVector.type]} / (${noiseVector.spatiallyIndependentVolumeElement}@slurp
+  @if not noiseVector.static:
+* _step at slurp
+  @end if
+);
+
+${makeFixedVarianceNoises}@slurp
+  @#
+  @set nonUniformDimReps = noiseVector.nonUniformDimReps
+  @if nonUniformDimReps
+    @capture loopString
+      @set fixupString = ' * '.join(c'${dimRep.stepSizeArrayName}_invsqrt[${dimRep.index} + ${dimRep.localOffset}]' for dimRep in nonUniformDimReps)
+      @for component in noiseVector.components
+${component} *= ${fixupString};
+      @end for
+    @end capture
+${loopOverFieldInBasisWithVectorsAndInnerContent(noiseVector.field, noiseVector.initialBasis, [noiseVector], loopString)}@slurp
+  @end if
+  @#
+ at end def
diff --git a/xpdeint/Stochastic/RandomVariables/GaussianSolirteRandomVariable.py b/xpdeint/Stochastic/RandomVariables/GaussianSolirteRandomVariable.py
new file mode 100644
index 0000000..3ceefbe
--- /dev/null
+++ b/xpdeint/Stochastic/RandomVariables/GaussianSolirteRandomVariable.py
@@ -0,0 +1,199 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Stochastic.RandomVariables.GaussianRandomVariable import GaussianRandomVariable
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.471774
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Stochastic/RandomVariables/GaussianSolirteRandomVariable.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class GaussianSolirteRandomVariable(GaussianRandomVariable):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(GaussianSolirteRandomVariable, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def makeFixedVarianceNoises(self, **KWS):
+
+
+        """
+        Return the code for the contents of the makeNoises function for
+          a Solirte Gaussian (Ziggurat method) noise
+        """
+
+        ## CHEETAH: generated from @def makeFixedVarianceNoises at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        noiseVector = VFFSL(SL,"parent",True)
+        _v = VFFSL(SL,"generator.generatorName",True) # u'${generator.generatorName}' on line 30, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${generator.generatorName}')) # from line 30, col 1.
+        write(u'''->RandFill_gaussian_FP64(reinterpret_cast<real*>(_active_''')
+        _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 30, col 84
+        if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 30, col 84.
+        write(u'''), _vector_size);
+const real _sigma = sqrt(_var);
+#pragma ivdep
+for (long _i0 = 0; _i0 < _vector_size; _i0++)
+  reinterpret_cast<real*>(_active_''')
+        _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 34, col 35
+        if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 34, col 35.
+        write(u''')[_i0] *= _sigma;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # GaussianSolirteRandomVariable.tmpl
+        # 
+        # Created by Joe Hope on 2009-08-22.
+        # 
+        # Copyright (c) 2009-2012, Joe Hope
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_GaussianSolirteRandomVariable= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(GaussianSolirteRandomVariable, '_initCheetahAttributes'):
+    templateAPIClass = getattr(GaussianSolirteRandomVariable, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(GaussianSolirteRandomVariable)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=GaussianSolirteRandomVariable()).run()
+
+
diff --git a/xpdeint/Stochastic/RandomVariables/GaussianSolirteRandomVariable.tmpl b/xpdeint/Stochastic/RandomVariables/GaussianSolirteRandomVariable.tmpl
new file mode 100644
index 0000000..bed2186
--- /dev/null
+++ b/xpdeint/Stochastic/RandomVariables/GaussianSolirteRandomVariable.tmpl
@@ -0,0 +1,37 @@
+@*
+GaussianSolirteRandomVariable.tmpl
+
+Created by Joe Hope on 2009-08-22.
+
+Copyright (c) 2009-2012, Joe Hope
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Stochastic.RandomVariables.GaussianRandomVariable
+
+ at def makeFixedVarianceNoises
+@*doc:
+  Return the code for the contents of the makeNoises function for
+  a Solirte Gaussian (Ziggurat method) noise
+*@
+  @set noiseVector = $parent
+${generator.generatorName}->RandFill_gaussian_FP64(reinterpret_cast<real*>(_active_${noiseVector.id}), _vector_size);
+const real _sigma = sqrt(_var);
+#pragma ivdep
+for (long _i0 = 0; _i0 < _vector_size; _i0++)
+  reinterpret_cast<real*>(_active_${noiseVector.id})[_i0] *= _sigma;
+  @#
+ at end def
+
diff --git a/xpdeint/Stochastic/RandomVariables/PoissonianRandomVariable.py b/xpdeint/Stochastic/RandomVariables/PoissonianRandomVariable.py
new file mode 100644
index 0000000..d15cbeb
--- /dev/null
+++ b/xpdeint/Stochastic/RandomVariables/PoissonianRandomVariable.py
@@ -0,0 +1,530 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.ScriptElement import ScriptElement
+from xpdeint.CallOnceGuards import callOnceGuard
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.562143
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Stochastic/RandomVariables/PoissonianRandomVariable.tmpl'
+__CHEETAH_srcLastModified__ = 'Sun Feb 12 20:15:16 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class PoissonianRandomVariable(ScriptElement):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(PoissonianRandomVariable, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def splitNoise(self, function, **KWS):
+
+
+        """
+        Return the code to generate a new smaller poissonian noise from a previous noise.
+        
+        The previous noise had a time step of ``_old_smallest_step`` a variable available in the C
+        code, not in the template itself.
+        """
+
+        ## CHEETAH: generated from @def splitNoise($function) at line 26, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        noiseVector = VFFSL(SL,"parent",True)
+        write(u'''// Split a poissonian noise
+const real _new_var = 1.0 / (''')
+        _v = VFFSL(SL,"noiseVector.spatiallyIndependentVolumeElement",True) # u'${noiseVector.spatiallyIndependentVolumeElement}' on line 36, col 30
+        if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.spatiallyIndependentVolumeElement}')) # from line 36, col 30.
+        write(u''' * _new_step);
+const real _old_volume = (''')
+        _v = VFFSL(SL,"noiseVector.spatiallyIndependentVolumeElement",True) # u'${noiseVector.spatiallyIndependentVolumeElement}' on line 37, col 27
+        if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.spatiallyIndependentVolumeElement}')) # from line 37, col 27.
+        write(u''' * _old_step);
+
+''')
+        ## START CAPTURE REGION: _54657516 loopString at line 39, col 3 in the source.
+        _orig_trans_54657516 = trans
+        _wasBuffering_54657516 = self._CHEETAH__isBuffering
+        self._CHEETAH__isBuffering = True
+        trans = _captureCollector_54657516 = DummyTransaction()
+        write = _captureCollector_54657516.response().write
+        nonUniformDimReps = noiseVector.nonUniformDimReps
+        if nonUniformDimReps: # generated from line 41, col 5
+            volumeFixup = ' * '.join('%s * (%s)' % (dimRep.stepSize, dimRep.volumePrefactor) for dimRep in nonUniformDimReps)
+            varFixup = ' / (' + volumeFixup + ')'
+            volumeFixup = ' * ' + volumeFixup
+        else: # generated from line 45, col 5
+            volumeFixup = ''
+            varFixup = ''
+        for componentNumber, component in enumerate(noiseVector.components): # generated from line 49, col 5
+            _v = VFFSL(SL,"component",True) # u'${component}' on line 50, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${component}')) # from line 50, col 1.
+            write(u''' = _new_var''')
+            _v = VFFSL(SL,"varFixup",True) # u'${varFixup}' on line 50, col 24
+            if _v is not None: write(_filter(_v, rawExpr=u'${varFixup}')) # from line 50, col 24.
+            write(u''' * _poisplit_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 50, col 48
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 50, col 48.
+            write(u'''(_new_step/_old_step, lrint(_old_array[_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 50, col 105
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 50, col 105.
+            write(u'''_index_pointer + ''')
+            _v = VFFSL(SL,"componentNumber",True) # u'${componentNumber}' on line 50, col 139
+            if _v is not None: write(_filter(_v, rawExpr=u'${componentNumber}')) # from line 50, col 139.
+            write(u'''] * _old_volume''')
+            _v = VFFSL(SL,"volumeFixup",True) # u'${volumeFixup}' on line 50, col 172
+            if _v is not None: write(_filter(_v, rawExpr=u'${volumeFixup}')) # from line 50, col 172.
+            write(u'''));
+''')
+        trans = _orig_trans_54657516
+        write = trans.response().write
+        self._CHEETAH__isBuffering = _wasBuffering_54657516 
+        loopString = _captureCollector_54657516.response().getvalue()
+        del _orig_trans_54657516
+        del _captureCollector_54657516
+        del _wasBuffering_54657516
+        _v = VFFSL(SL,"loopOverFieldInBasisWithVectorsAndInnerContent",False)(noiseVector.field, noiseVector.initialBasis, [noiseVector], loopString) # u'${loopOverFieldInBasisWithVectorsAndInnerContent(noiseVector.field, noiseVector.initialBasis, [noiseVector], loopString)}' on line 53, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverFieldInBasisWithVectorsAndInnerContent(noiseVector.field, noiseVector.initialBasis, [noiseVector], loopString)}')) # from line 53, col 1.
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def makeNoises(self, **KWS):
+
+
+        """
+        Return the code for the contents of the makeNoises function for
+          a poissonian random variable, by which we mean a jump process.  
+          Much of this is likely to change when we implement triggered filters
+          to model jump processes efficiently.
+        """
+
+        ## CHEETAH: generated from @def makeNoises at line 58, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        noiseVector = VFFSL(SL,"parent",True)
+        # 
+        write(u'''const real _dVdt = ''')
+        _v = VFFSL(SL,"noiseVector.spatiallyIndependentVolumeElement",True) # u'${noiseVector.spatiallyIndependentVolumeElement}' on line 68, col 20
+        if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.spatiallyIndependentVolumeElement}')) # from line 68, col 20.
+        if not noiseVector.static: # generated from line 69, col 3
+            write(u''' * _step''')
+        write(u''';
+const real _var = 1.0 / _dVdt;
+''')
+        ## START CAPTURE REGION: _83720223 loopString at line 74, col 3 in the source.
+        _orig_trans_83720223 = trans
+        _wasBuffering_83720223 = self._CHEETAH__isBuffering
+        self._CHEETAH__isBuffering = True
+        trans = _captureCollector_83720223 = DummyTransaction()
+        write = _captureCollector_83720223.response().write
+        nonUniformDimReps = noiseVector.nonUniformDimReps
+        if nonUniformDimReps: # generated from line 76, col 5
+            volumeFixup = ' * '.join('%s * (%s)' % (dimRep.stepSize, dimRep.volumePrefactor) for dimRep in nonUniformDimReps)
+            varFixup = ' / (' + volumeFixup + ')'
+            volumeFixup = ' * ' + volumeFixup
+        else: # generated from line 80, col 5
+            volumeFixup = ''
+            varFixup = ''
+        for component in noiseVector.components: # generated from line 84, col 5
+            _v = VFFSL(SL,"component",True) # u'${component}' on line 85, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${component}')) # from line 85, col 1.
+            write(u''' = _var''')
+            _v = VFFSL(SL,"varFixup",True) # u'${varFixup}' on line 85, col 20
+            if _v is not None: write(_filter(_v, rawExpr=u'${varFixup}')) # from line 85, col 20.
+            write(u''' * _poidev_''')
+            _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 85, col 42
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 85, col 42.
+            write(u'''(''')
+            _v = VFFSL(SL,"noiseMeanRate",True) # u'${noiseMeanRate}' on line 85, col 60
+            if _v is not None: write(_filter(_v, rawExpr=u'${noiseMeanRate}')) # from line 85, col 60.
+            write(u''' * _dVdt''')
+            _v = VFFSL(SL,"volumeFixup",True) # u'${volumeFixup}' on line 85, col 84
+            if _v is not None: write(_filter(_v, rawExpr=u'${volumeFixup}')) # from line 85, col 84.
+            write(u''');
+''')
+        trans = _orig_trans_83720223
+        write = trans.response().write
+        self._CHEETAH__isBuffering = _wasBuffering_83720223 
+        loopString = _captureCollector_83720223.response().getvalue()
+        del _orig_trans_83720223
+        del _captureCollector_83720223
+        del _wasBuffering_83720223
+        _v = VFFSL(SL,"loopOverFieldInBasisWithVectorsAndInnerContent",False)(noiseVector.field, noiseVector.initialBasis, [noiseVector], loopString) # u'${loopOverFieldInBasisWithVectorsAndInnerContent(noiseVector.field, noiseVector.initialBasis, [noiseVector], loopString)}' on line 88, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverFieldInBasisWithVectorsAndInnerContent(noiseVector.field, noiseVector.initialBasis, [noiseVector], loopString)}')) # from line 88, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def functionPrototypes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def functionPrototypes at line 92, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(PoissonianRandomVariable, self).functionPrototypes()
+        if _v is not None: write(_filter(_v))
+        # 
+        noiseVector = VFFSL(SL,"parent",True)
+        # 
+        write(u'''real _poidev_''')
+        _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 98, col 14
+        if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 98, col 14.
+        write(u'''(real xm);
+real _poisplit_''')
+        _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 99, col 16
+        if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 99, col 16.
+        write(u'''(real pp, int n);
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def functionImplementations(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def functionImplementations at line 103, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(PoissonianRandomVariable, self).functionImplementations()
+        if _v is not None: write(_filter(_v))
+        # 
+        noiseVector = VFFSL(SL,"parent",True)
+        # 
+        write(u'''real _poidev_''')
+        _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 109, col 14
+        if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 109, col 14.
+        write(u'''(real xm)
+{
+  real sq, alxm, g, em, t, y;
+
+  if (xm < 12.0) {        // Use direct method
+    g = exp(-xm);
+    em = -1.0;
+    t = 1.0;
+    // Instead of adding exponential deviates it is equivalent
+    // to multiply uniform deviates.  We never actually have to
+    // take the log, merely compare to the pre-computed exponential
+    do {
+      ++em;
+      t *= ''')
+        _v = VFN(VFFSL(SL,"generator",True),"zeroToOneRandomNumber",False)() # u'${generator.zeroToOneRandomNumber()}' on line 122, col 12
+        if _v is not None: write(_filter(_v, rawExpr=u'${generator.zeroToOneRandomNumber()}')) # from line 122, col 12.
+        write(u''';
+    } while (t > g);
+  } else {
+    // Use rejection method
+    sq = sqrt(2.0*xm);
+    alxm = log(xm);
+    g = xm*alxm - lgamma(xm + 1.0);
+    do {
+      do {
+        // y is a deviate from a Lorenzian comparison function
+        y = tan(M_PI*''')
+        _v = VFN(VFFSL(SL,"generator",True),"zeroToOneRandomNumber",False)() # u'${generator.zeroToOneRandomNumber()}' on line 132, col 22
+        if _v is not None: write(_filter(_v, rawExpr=u'${generator.zeroToOneRandomNumber()}')) # from line 132, col 22.
+        write(u''');
+        // em is y, shifted and scaled
+        em = sq*y + xm;
+      } while (em < 0.0);  // Reject if in regime of zero probability
+      em = floor(em);      // The trick for integer-valued distributions
+      t = 0.9*(1.0 + y*y)*exp(em*alxm - lgamma(em + 1.0) - g);
+      // The ratio of the desired distribution to the comparison
+      // function; we reject by comparing it to another uniform
+      // deviate. The factor 0.9 so that t never exceeds 1.
+    } while (''')
+        _v = VFN(VFFSL(SL,"generator",True),"zeroToOneRandomNumber",False)() # u'${generator.zeroToOneRandomNumber()}' on line 141, col 14
+        if _v is not None: write(_filter(_v, rawExpr=u'${generator.zeroToOneRandomNumber()}')) # from line 141, col 14.
+        write(u''' > t);
+  }
+  return em;
+}
+
+real _poisplit_''')
+        _v = VFFSL(SL,"noiseVector.id",True) # u'${noiseVector.id}' on line 146, col 16
+        if _v is not None: write(_filter(_v, rawExpr=u'${noiseVector.id}')) # from line 146, col 16.
+        write(u'''(real pp, int n)
+{
+  /*
+  Returns as a floating-point number an integer value that is a random deviate drawn from
+  a binomial distribution of n trials each of probability pp, using erand48(_generator) as a source of
+  uniform random deviates. This is exactly the distribution that must be sampled when a poissonian process is split over two smaller time steps
+  */
+
+  long j;
+  real am, em, g, p, bnl, sq, t, y;
+  static real pc, plog, pclog, en, oldg;
+
+  // The binomial distribution is invariant under changing pp to 1-pp,
+  // if we also change the answer to n minus itself; we do this at the end.
+  p = (pp <= 0.5 ? pp : 1.0-pp);
+
+  // This is the mean of the deviate to be produced.
+  am = n * p;
+
+  if (n < 25) {
+    // Use the direct method while n is not too large. This can require up to 25 calls to erand48(_generator).
+    bnl = 0.0;
+    for (j = 1; j <= n; j++)
+      if (''')
+        _v = VFN(VFFSL(SL,"generator",True),"zeroToOneRandomNumber",False)() # u'${generator.zeroToOneRandomNumber()}' on line 169, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'${generator.zeroToOneRandomNumber()}')) # from line 169, col 11.
+        write(u''' < p)
+        ++bnl;
+  } else if (am < 1.0) {
+    // If fewer than one event is expected out of 25 or more trials, then the distribution is quite accurately Poisson. Use direct Poisson method.
+    g = exp(-am);
+    t = 1.0;
+    for (j = 0; j <= n; j++) {
+      t *= ''')
+        _v = VFN(VFFSL(SL,"generator",True),"zeroToOneRandomNumber",False)() # u'${generator.zeroToOneRandomNumber()}' on line 176, col 12
+        if _v is not None: write(_filter(_v, rawExpr=u'${generator.zeroToOneRandomNumber()}')) # from line 176, col 12.
+        write(u''';
+      if (t < g)
+        break;
+    }
+    bnl = (j <= n ? j : n);
+  } else {
+    en = n;
+    oldg = lgamma(en + 1.0);
+    pc = 1.0 - p;
+    plog = log(p);
+    pclog = log(pc);
+    sq = sqrt(2.0*am*pc);
+    // The following code should by now seem familiar: rejection method with a Lorentzian comparison function.
+    do {
+      do {
+        y = tan(M_PI*''')
+        _v = VFN(VFFSL(SL,"generator",True),"zeroToOneRandomNumber",False)() # u'${generator.zeroToOneRandomNumber()}' on line 191, col 22
+        if _v is not None: write(_filter(_v, rawExpr=u'${generator.zeroToOneRandomNumber()}')) # from line 191, col 22.
+        write(u''');
+        em = sq*y + am;
+      } while (em < 0.0 || em >= (en+1.0)); // Reject.
+      em = floor(em); // Trick for integer-valued distribution. 
+      t = 1.2 * sq * (1.0 + y*y) * exp(oldg - lgamma(em + 1.0) - lgamma(en - em + 1.0) + em*plog + (en - em)*pclog); 
+    } while (''')
+        _v = VFN(VFFSL(SL,"generator",True),"zeroToOneRandomNumber",False)() # u'${generator.zeroToOneRandomNumber()}' on line 196, col 14
+        if _v is not None: write(_filter(_v, rawExpr=u'${generator.zeroToOneRandomNumber()}')) # from line 196, col 14.
+        write(u''' > t); // Reject. This happens about 1.5 times per deviate, on average.
+    bnl = em;
+  }
+  if (p != pp) bnl = n - bnl; // Remember to undo the symmetry transformation.
+  return bnl;
+}
+
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # PoissonianRandomVariable.tmpl
+        # 
+        # Created by Joe Hope on 2009-08-22.
+        # 
+        # Copyright (c) 2009-2012, Joe Hope
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_PoissonianRandomVariable= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(PoissonianRandomVariable, '_initCheetahAttributes'):
+    templateAPIClass = getattr(PoissonianRandomVariable, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(PoissonianRandomVariable)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=PoissonianRandomVariable()).run()
+
+
diff --git a/xpdeint/Stochastic/RandomVariables/PoissonianRandomVariable.tmpl b/xpdeint/Stochastic/RandomVariables/PoissonianRandomVariable.tmpl
new file mode 100644
index 0000000..ab8bb12
--- /dev/null
+++ b/xpdeint/Stochastic/RandomVariables/PoissonianRandomVariable.tmpl
@@ -0,0 +1,205 @@
+@*
+PoissonianRandomVariable.tmpl
+
+Created by Joe Hope on 2009-08-22.
+
+Copyright (c) 2009-2012, Joe Hope
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.ScriptElement
+
+ at from xpdeint.CallOnceGuards import callOnceGuard
+
+ at def splitNoise($function)
+@*doc:
+Return the code to generate a new smaller poissonian noise from a previous noise.
+
+The previous noise had a time step of ``_old_smallest_step`` a variable available in the C
+code, not in the template itself.
+*@
+  @#
+  @set noiseVector = $parent
+// Split a poissonian noise
+const real _new_var = 1.0 / (${noiseVector.spatiallyIndependentVolumeElement} * _new_step);
+const real _old_volume = (${noiseVector.spatiallyIndependentVolumeElement} * _old_step);
+
+  @capture loopString
+    @silent nonUniformDimReps = noiseVector.nonUniformDimReps
+    @if nonUniformDimReps
+      @set volumeFixup = ' * '.join('%s * (%s)' % (dimRep.stepSize, dimRep.volumePrefactor) for dimRep in nonUniformDimReps)
+      @set varFixup = ' / (' + volumeFixup + ')'
+      @set volumeFixup = ' * ' + volumeFixup
+    @else
+      @set volumeFixup = ''
+      @set varFixup = ''
+    @end if
+    @for componentNumber, component in enumerate(noiseVector.components)
+${component} = _new_var${varFixup} * _poisplit_${noiseVector.id}(_new_step/_old_step, lrint(_old_array[_${noiseVector.id}_index_pointer + ${componentNumber}] * _old_volume${volumeFixup}));
+    @end for
+  @end capture
+${loopOverFieldInBasisWithVectorsAndInnerContent(noiseVector.field, noiseVector.initialBasis, [noiseVector], loopString)}@slurp
+
+  @#
+ at end def
+
+ at def makeNoises
+@*doc:
+  Return the code for the contents of the makeNoises function for
+  a poissonian random variable, by which we mean a jump process.  
+  Much of this is likely to change when we implement triggered filters
+  to model jump processes efficiently.
+*@
+  @#
+  @set noiseVector = $parent
+  @#
+const real _dVdt = ${noiseVector.spatiallyIndependentVolumeElement}@slurp
+  @if not noiseVector.static:
+ * _step at slurp
+  @end if
+;
+const real _var = 1.0 / _dVdt;
+  @capture loopString
+    @silent nonUniformDimReps = noiseVector.nonUniformDimReps
+    @if nonUniformDimReps
+      @set volumeFixup = ' * '.join('%s * (%s)' % (dimRep.stepSize, dimRep.volumePrefactor) for dimRep in nonUniformDimReps)
+      @set varFixup = ' / (' + volumeFixup + ')'
+      @set volumeFixup = ' * ' + volumeFixup
+    @else
+      @set volumeFixup = ''
+      @set varFixup = ''
+    @end if
+    @for component in noiseVector.components
+${component} = _var${varFixup} * _poidev_${noiseVector.id}(${noiseMeanRate} * _dVdt${volumeFixup});
+    @end for
+  @end capture
+${loopOverFieldInBasisWithVectorsAndInnerContent(noiseVector.field, noiseVector.initialBasis, [noiseVector], loopString)}@slurp
+  @#
+ at end def
+
+ at def functionPrototypes
+  @#
+  @super
+  @#
+  @set noiseVector = $parent
+  @#
+real _poidev_${noiseVector.id}(real xm);
+real _poisplit_${noiseVector.id}(real pp, int n);
+  @#
+ at end def
+
+ at def functionImplementations
+  @#
+  @super
+  @#
+  @set noiseVector = $parent
+  @#
+real _poidev_${noiseVector.id}(real xm)
+{
+  real sq, alxm, g, em, t, y;
+
+  if (xm < 12.0) {        // Use direct method
+    g = exp(-xm);
+    em = -1.0;
+    t = 1.0;
+    // Instead of adding exponential deviates it is equivalent
+    // to multiply uniform deviates.  We never actually have to
+    // take the log, merely compare to the pre-computed exponential
+    do {
+      ++em;
+      t *= ${generator.zeroToOneRandomNumber()};
+    } while (t > g);
+  } else {
+    // Use rejection method
+    sq = sqrt(2.0*xm);
+    alxm = log(xm);
+    g = xm*alxm - lgamma(xm + 1.0);
+    do {
+      do {
+        // y is a deviate from a Lorenzian comparison function
+        y = tan(M_PI*${generator.zeroToOneRandomNumber()});
+        // em is y, shifted and scaled
+        em = sq*y + xm;
+      } while (em < 0.0);  // Reject if in regime of zero probability
+      em = floor(em);      // The trick for integer-valued distributions
+      t = 0.9*(1.0 + y*y)*exp(em*alxm - lgamma(em + 1.0) - g);
+      // The ratio of the desired distribution to the comparison
+      // function; we reject by comparing it to another uniform
+      // deviate. The factor 0.9 so that t never exceeds 1.
+    } while (${generator.zeroToOneRandomNumber()} > t);
+  }
+  return em;
+}
+
+real _poisplit_${noiseVector.id}(real pp, int n)
+{
+  /*
+  Returns as a floating-point number an integer value that is a random deviate drawn from
+  a binomial distribution of n trials each of probability pp, using erand48(_generator) as a source of
+  uniform random deviates. This is exactly the distribution that must be sampled when a poissonian process is split over two smaller time steps
+  */
+
+  long j;
+  real am, em, g, p, bnl, sq, t, y;
+  static real pc, plog, pclog, en, oldg;
+
+  // The binomial distribution is invariant under changing pp to 1-pp,
+  // if we also change the answer to n minus itself; we do this at the end.
+  p = (pp <= 0.5 ? pp : 1.0-pp);
+
+  // This is the mean of the deviate to be produced.
+  am = n * p;
+
+  if (n < 25) {
+    // Use the direct method while n is not too large. This can require up to 25 calls to erand48(_generator).
+    bnl = 0.0;
+    for (j = 1; j <= n; j++)
+      if (${generator.zeroToOneRandomNumber()} < p)
+        ++bnl;
+  } else if (am < 1.0) {
+    // If fewer than one event is expected out of 25 or more trials, then the distribution is quite accurately Poisson. Use direct Poisson method.
+    g = exp(-am);
+    t = 1.0;
+    for (j = 0; j <= n; j++) {
+      t *= ${generator.zeroToOneRandomNumber()};
+      if (t < g)
+        break;
+    }
+    bnl = (j <= n ? j : n);
+  } else {
+    en = n;
+    oldg = lgamma(en + 1.0);
+    pc = 1.0 - p;
+    plog = log(p);
+    pclog = log(pc);
+    sq = sqrt(2.0*am*pc);
+    // The following code should by now seem familiar: rejection method with a Lorentzian comparison function.
+    do {
+      do {
+        y = tan(M_PI*${generator.zeroToOneRandomNumber()});
+        em = sq*y + am;
+      } while (em < 0.0 || em >= (en+1.0)); // Reject.
+      em = floor(em); // Trick for integer-valued distribution. 
+      t = 1.2 * sq * (1.0 + y*y) * exp(oldg - lgamma(em + 1.0) - lgamma(en - em + 1.0) + em*plog + (en - em)*pclog); 
+    } while (${generator.zeroToOneRandomNumber()} > t); // Reject. This happens about 1.5 times per deviate, on average.
+    bnl = em;
+  }
+  if (p != pp) bnl = n - bnl; // Remember to undo the symmetry transformation.
+  return bnl;
+}
+
+  @#
+ at end def
+
diff --git a/xpdeint/Stochastic/RandomVariables/UniformRandomVariable.py b/xpdeint/Stochastic/RandomVariables/UniformRandomVariable.py
new file mode 100644
index 0000000..0f65831
--- /dev/null
+++ b/xpdeint/Stochastic/RandomVariables/UniformRandomVariable.py
@@ -0,0 +1,187 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.ScriptElement import ScriptElement
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.491777
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Stochastic/RandomVariables/UniformRandomVariable.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class UniformRandomVariable(ScriptElement):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(UniformRandomVariable, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def makeNoises(self, **KWS):
+
+
+        """
+        Return the code for the contents of the makeNoises function for
+          a uniform random variable.  
+          Essentially, this is generator specific code, hence the lack of anything here.
+        """
+
+        ## CHEETAH: generated from @def makeNoises at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = VFFSL(SL,"generator.constructArrayUniformRandomNumbers",True) # u'${generator.constructArrayUniformRandomNumbers}' on line 31, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${generator.constructArrayUniformRandomNumbers}')) # from line 31, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # UniformRandomVariable.tmpl
+        # 
+        # Created by Joe Hope on 2009-08-22.
+        # 
+        # Copyright (c) 2009-2012, Joe Hope
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_UniformRandomVariable= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(UniformRandomVariable, '_initCheetahAttributes'):
+    templateAPIClass = getattr(UniformRandomVariable, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(UniformRandomVariable)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=UniformRandomVariable()).run()
+
+
diff --git a/xpdeint/Stochastic/RandomVariables/UniformRandomVariable.tmpl b/xpdeint/Stochastic/RandomVariables/UniformRandomVariable.tmpl
new file mode 100644
index 0000000..e4373d4
--- /dev/null
+++ b/xpdeint/Stochastic/RandomVariables/UniformRandomVariable.tmpl
@@ -0,0 +1,33 @@
+@*
+UniformRandomVariable.tmpl
+
+Created by Joe Hope on 2009-08-22.
+
+Copyright (c) 2009-2012, Joe Hope
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.ScriptElement
+
+ at def makeNoises
+@*doc:
+  Return the code for the contents of the makeNoises function for
+  a uniform random variable.  
+  Essentially, this is generator specific code, hence the lack of anything here.
+*@
+  @#
+${generator.constructArrayUniformRandomNumbers}@slurp
+  @#
+ at end def
diff --git a/xpdeint/Stochastic/RandomVariables/__init__.py b/xpdeint/Stochastic/RandomVariables/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/xpdeint/Stochastic/__init__.py b/xpdeint/Stochastic/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/xpdeint/Utilities.py b/xpdeint/Utilities.py
new file mode 100644
index 0000000..1ccb223
--- /dev/null
+++ b/xpdeint/Utilities.py
@@ -0,0 +1,365 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+Utilities.py
+
+Created by Graham Dennis on 2008-09-15.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+    * Neither the name of The Australian National University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROF [...]
+
+"""
+
+from xpdeint.ParserException import ParserException
+import re
+import sys
+
+from heapq import heapify, heappush, heappop
+import operator
+
+class lazy_property(object):
+  """
+  A data descriptor that provides a default value for the attribute
+  represented via a user-defined function, and this function is evaluated
+  at most once with the result cached. Additionally, the property can be
+  overridden.
+  """
+  
+  def __init__(self, fget, doc=None):
+    self.fget = fget
+    self.__doc__ = doc
+    if not self.__doc__:
+      self.__doc__ = fget.__doc__
+    self.__name__ = fget.__name__
+  
+  def __get__(self, obj, objtype=None):
+    if obj is None:
+      return self
+    if self.fget is None:
+      raise AttributeError, "unreadable attribute"
+    result = obj.__dict__[self.__name__] = self.fget(obj)
+    return result
+  
+
+def valueForKeyPath(base, keyPath):
+  """
+  Return the value for a dotted-name lookup of `keyPath` anchored at `base`.
+
+  This is similar to the KVC methods in Objective-C, however its use is appropriate in Python.
+  Evaluating the `keyPath` 'foo.bar.baz' returns the object that would be returned by evaluating
+  the string (in Python) base.foo.bar.baz
+  """
+  attrNames = keyPath.split('.')
+  try:
+    currentObject = base
+    for attrName in attrNames:
+      if isinstance(currentObject, dict):
+        # Access via dictionary key
+        currentObject = currentObject[attrName]
+      else:
+        # Access attribute
+        currentObject = getattr(currentObject, attrName)
+  except Exception, err:
+    baseRep = repr(base)
+    print >> sys.stderr, "Hit exception trying to get keyPath '%(keyPath)s' on object %(baseRep)s." % locals()
+    raise
+  return currentObject
+
+def setValueForKeyPath(base, value, keyPath):
+  """Set the value of the result of the dotted-name lookup of `keyPath` anchored at `base` to `value`."""
+  attrNames = keyPath.split('.')
+  lastAttrName = attrNames.pop()
+  currentObject = base
+  try:
+    for attrName in attrNames:
+      currentObject = getattr(currentObject, attrName)
+    if isinstance(currentObject, dict):
+      # Set dictionary entry
+      currentObject[lastAttrName] = value
+    else:
+      # Set attribute
+      setattr(currentObject, lastAttrName, value)
+  except Exception, err:
+    baseRep = repr(base)
+    print >> sys.stderr, "Hit exception trying to set keyPath '%(keyPath)s' on object %(baseRep)s." % locals()
+    raise
+
+
+def greatestCommonFactor(num):
+    num = [n for n in num if n > 0]
+    t_val = num[0]
+    for cnt in range(len(num)-1):
+        num1 = t_val
+        num2 = num[cnt+1]
+        if num1 < num2:
+            num1,num2=num2,num1
+        while num1 - num2:
+            num3 = num1 - num2
+            num1 = max(num2,num3)
+            num2 = min(num2,num3)
+        t_val = num1
+    return t_val
+
+def leastCommonMultiple(num):
+    num = [n for n in num if n > 0]
+    if len(num) == 0:
+        return 1
+    t_val = num[0]
+    for cnt in range(len(num)-1):
+        num1 = t_val
+        num2 = num[cnt+1]
+        tmp = greatestCommonFactor([num1,num2])
+        t_val = tmp * num1/tmp * num2/tmp
+    return t_val
+
+protectedNamesSet = set("""
+gamma nan ceil floor trunc round remainder abs sqrt hypot
+exp log pow cos sin tan cosh sinh tanh acos asin atan
+j0 j1 jn y0 y1 yn erf real complex Re Im mod2 integer mod
+""".split())
+
+def symbolsInString(string, xmlElement = None):
+    wordRegex = re.compile(r'\b\w+\b')
+    symbolRegex = re.compile(r'[a-zA-Z]\w*')
+    words = wordRegex.findall(string)
+    for word in words:
+        if not symbolRegex.match(word):
+            raise ParserException(
+                xmlElement,
+                "'%(word)s' is not a valid name. All names must start with a letter, "
+                "after that letters, numbers and underscores ('_') may be used." % locals()
+            )
+        if word in protectedNamesSet:
+            raise ParserException(
+                xmlElement,
+                "'%(word)s' cannot be used as a name because it conflicts with an internal function or variable of the same name. "
+                "Choose another name." % locals()
+            )
+    return words
+
+def symbolInString(string, xmlElement = None):
+    words = symbolsInString(string, xmlElement)
+    if len(words) > 1:
+        raise ParserException(
+            xmlElement,
+            "Only one name was expected at this point. The problem was with the string '%(string)s'" % locals()
+        )
+    if words:
+        return words[0]
+    else:
+        return None
+    
+
+def unique(seq, idfun=None):
+    # order preserving
+    if idfun is None:
+        def idfun(x): return x
+    seen = {}
+    result = []
+    for item in seq:
+        marker = idfun(item)
+        if marker in seen: continue
+        seen[marker] = 1
+        result.append(item)
+    return result
+
+def permutations(*iterables):
+    def permuteTwo(it1, it2):
+        for o1 in it1:
+            for o2 in it2:
+                if isinstance(o1, tuple):
+                    yield o1 + (o2,)
+                else:
+                    yield (o1, o2)
+    
+    if len(iterables) == 1:
+        return iterables[0]
+    
+    it = iterables[0]
+    for it2 in iterables[1:]:
+        it = permuteTwo(it, it2)
+    
+    return it
+
+def combinations(itemCount, *lsts):
+    """Generator for all unique combinations of each list in `lsts` containing `itemCount` elements."""
+    def _combinations(itemCount, lst):
+        if itemCount == 0 or itemCount > len(lst):
+            return
+        if itemCount == 1:
+            for o in lst:
+                yield (o,)
+        elif itemCount == len(lst):
+            yield tuple(lst)
+        else:
+            if not isinstance(lst, list):
+              lst = list(lst)
+            for o in _combinations(itemCount-1, lst[1:]):
+                yield (lst[0],) + o
+            for o in _combinations(itemCount, lst[1:]):
+                yield o
+    if len(lsts) == 1:
+        return _combinations(itemCount, lsts[0])
+    iterables = [list(_combinations(itemCount, lst)) for lst in lsts]
+    return permutations(*iterables)
+
+
+class GeneralisedBidirectionalSearch(object):
+    """
+    A Generalised bidirectional search is an algorithm to search for the least-cost
+    route between a subset of nodes in a graph.
+    
+    Typically, only one of the least-cost solutions are desired, however
+    as we will have some additional criteria to apply later to the returned
+    paths, this implementation returns all of the least-cost paths between
+    two nodes.
+    """
+    class State(object):
+        """
+        A helper class to store information about a given node, the cost to get there
+        and the step that was used to get to this node.
+        
+        It is intended that this class be subclassed for use in searches.
+        """
+        __slots__ = ['cost', 'location', 'previous', 'source', 'transformation']
+        def __init__(self, cost, location, source, previous = None, transformation = None):
+            self.cost = cost
+            self.location = location
+            self.source = source
+            self.previous = previous
+            self.transformation = transformation
+        
+        def next(self):
+            """
+            This function is to return the nodes reachable from this node, the costs and
+            some related information.
+            
+            This function must be implemented by a subclass.
+            """
+            assert False
+        
+    
+    class NodeInfo(object):
+        """
+        This helper class stores the information known about the minimum-cost
+        routes to the target nodes from a given node. This information includes the minimum cost
+        to reach the target nodes and the next step towards each target node.
+        """
+        __slots__ = ['costs', 'next', 'transformations']
+        def __init__(self, sourceIdx, cost, next = None, transformation = None):
+            self.costs = [None] * GeneralisedBidirectionalSearch.NodeInfo.targetCount
+            self.next = self.costs[:]
+            self.transformations = self.costs[:]
+            self.costs[sourceIdx] = cost
+            self.next[sourceIdx] = next
+            self.transformations[sourceIdx] = transformation
+        
+    @staticmethod
+    def perform(targetNodes):
+        """
+        This function performs the 'bidirectional' search between the nodes `targetNodes`
+        This information is returned in a dictionary that
+        maps a given node to a `NodeInfo` object that contains information about
+        the minimum-cost routes to reach that node.
+        """
+        targetLocations = [node.location for node in targetNodes]
+        queue = [(node.cost, node) for node in targetNodes]
+        heapify(queue)
+        GeneralisedBidirectionalSearch.NodeInfo.targetCount = len(targetNodes)
+        pathInfo = dict()
+        targetRoutes = dict()
+        
+        maxCost = None
+        
+        # This algorithm works by iterating over a queue considering paths in
+        # order of increasing cost. As a path is considered, every possible
+        # single-step extension to this path is considered and added to the queue.
+        # Eventually the queue empties when the only paths contained are more expensive
+        # versions of paths that have already been considered.
+        #
+        # But we don't have to wait for the queue to empty, we can stop whenever we know how to get between
+        # each of our targetNodes
+        
+        def processState(state):
+            for nextState in state.next():
+                if nextState.location in pathInfo \
+                    and pathInfo[nextState.location].costs[nextState.source] is not None:
+                    continue
+                heappush(queue, (nextState.cost, nextState))
+        
+        def costsOperation(op, A, B):
+          return tuple(op(a, b) for a, b in zip(A, B))
+        
+        while queue:
+            currentState = heappop(queue)[1]
+            if maxCost is not None and currentState.cost > maxCost: break
+            if not currentState.location in pathInfo:
+                # This location hasn't been reached. Add a NodeInfo object to pathInfo
+                pathInfo[currentState.location] = GeneralisedBidirectionalSearch.NodeInfo(
+                    currentState.source,
+                    currentState.cost,
+                    currentState.previous,
+                    currentState.transformation,
+                )
+                if currentState.location in targetLocations \
+                    and not currentState.source == targetLocations.index(currentState.location) \
+                    and not frozenset([currentState.source, targetLocations.index(currentState.location)]) in targetRoutes:
+                    targetRoutes[frozenset([currentState.source, targetLocations.index(currentState.location)])] = currentState.cost
+                    maxCost = max(currentState.cost, maxCost)
+                processState(currentState)
+            elif pathInfo[currentState.location].costs[currentState.source] is None \
+                or pathInfo[currentState.location].costs[currentState.source] > currentState.cost:
+                # While this location has been reached before, it hasn't been reached from this source
+                # or it has been reached, but with a higher cost.
+                
+                nodeInfo = pathInfo[currentState.location]
+                nodeInfo.costs[currentState.source] = currentState.cost
+                nodeInfo.next[currentState.source] = currentState.previous
+                nodeInfo.transformations[currentState.source] = currentState.transformation
+                
+                # If we have reached a location which itself is reachable from a different targetNode,
+                # then we have found a shortest route from our source to the targetNode (and vice-versa)
+                for destination, destCost in enumerate(nodeInfo.costs):
+                    if destCost is None \
+                        or not frozenset([currentState.source, destination]) in targetRoutes \
+                        or targetRoutes[frozenset([currentState.source, destination])] < destCost + currentState.cost \
+                        or destination == currentState.source:
+                        continue
+                    
+                    # The total cost for the route
+                    totalCost = costsOperation(operator.add, destCost, currentState.cost)
+                    targetRoutes[frozenset([currentState.source, destination])] = currentState.cost
+                    maxCost = max(currentState.cost, maxCost)
+                    
+                    # Now that we have found two intersecting routes, we must update each part with
+                    # the cost and path information to the corresponding targets
+                    
+                    forwardBackwardPathUpdateInfo = [
+                      (currentState.location, currentState.previous, currentState.source, destination),
+                      (currentState.previous, currentState.location, destination, currentState.source)
+                    ]
+                    
+                    for loc, prev, source, dest in forwardBackwardPathUpdateInfo:
+                        transformation = currentState.transformation
+                        while loc is not None:
+                            nodeInfo = pathInfo[loc]
+                            cost = costsOperation(operator.sub, totalCost, nodeInfo.costs[dest])
+                            nodeInfo.costs[source] = cost
+                            nodeInfo.next[source] = prev
+                            nodeInfo.transformations[source] = transformation
+                            processState(currentState.__class__(cost, loc, source, prev, transformation))
+                            prev, loc = loc, nodeInfo.next[dest]
+                            transformation = nodeInfo.transformations[dest]
+                    
+                processState(currentState)
+        return pathInfo
+    
diff --git a/xpdeint/Vectors/ComputedVector.py b/xpdeint/Vectors/ComputedVector.py
new file mode 100644
index 0000000..041dd59
--- /dev/null
+++ b/xpdeint/Vectors/ComputedVector.py
@@ -0,0 +1,285 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Vectors._ComputedVector import _ComputedVector
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.542305
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Vectors/ComputedVector.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class ComputedVector(_ComputedVector):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(ComputedVector, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: computed vector $name at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''computed vector ''')
+        _v = VFFSL(SL,"name",True) # u'$name' on line 27, col 35
+        if _v is not None: write(_filter(_v, rawExpr=u'$name')) # from line 27, col 35.
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def evaluateFunctionContents(self, function, **KWS):
+
+
+        """
+        This function returns the code for the calculated vector's ``evaluate()`` function.
+          
+          The ``evaluate()`` function executes the code that defines the calculated vector.
+        """
+
+        ## CHEETAH: generated from @def evaluateFunctionContents($function) at line 29, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        if VFFSL(SL,"integratingComponents",True): # generated from line 36, col 3
+            #  If this vector is constructed through an integral, then we first
+            #  need to initialise ourselves to zero.
+            _v = VFFSL(SL,"initialise",True) # u'${initialise}' on line 39, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${initialise}')) # from line 39, col 1.
+            write(u'''
+''')
+        # 
+        featureOrdering = ['Stochastic']
+        featureDict = {'codeBlock': VFFSL(SL,"codeBlocks",True)['evaluation']}
+        # 
+        vectorOverrides = []
+        if VFFSL(SL,"integratingComponents",True): # generated from line 47, col 3
+            vectorOverrides.append(self)
+        # 
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('computedVectorEvaluationBegin', VFFSL(SL,"featureOrdering",True), featureDict) # u"${insertCodeForFeatures('computedVectorEvaluationBegin', $featureOrdering, featureDict)}" on line 51, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('computedVectorEvaluationBegin', $featureOrdering, featureDict)}")) # from line 51, col 1.
+        _v = VFN(VFFSL(SL,"codeBlocks",True)['evaluation'],"loop",False)(self.insideEvaluationLoops, vectorOverrides=vectorOverrides) # u"${codeBlocks['evaluation'].loop(self.insideEvaluationLoops, vectorOverrides=vectorOverrides)}" on line 52, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${codeBlocks['evaluation'].loop(self.insideEvaluationLoops, vectorOverrides=vectorOverrides)}")) # from line 52, col 1.
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('computedVectorEvaluationEnd', VFFSL(SL,"featureOrdering",True), featureDict) # u"${insertCodeForFeaturesInReverseOrder('computedVectorEvaluationEnd', $featureOrdering, featureDict)}" on line 53, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeaturesInReverseOrder('computedVectorEvaluationEnd', $featureOrdering, featureDict)}")) # from line 53, col 1.
+        # 
+        if VFFSL(SL,"needsTransforms",True): # generated from line 55, col 3
+            write(u'''
+_''')
+            _v = VFFSL(SL,"id",True) # u'${id}' on line 57, col 2
+            if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 57, col 2.
+            write(u'''_basis = ''')
+            _v = VFFSL(SL,"basisIndexForBasis",False)(self.initialBasis) # u'$basisIndexForBasis(self.initialBasis)' on line 57, col 16
+            if _v is not None: write(_filter(_v, rawExpr=u'$basisIndexForBasis(self.initialBasis)')) # from line 57, col 16.
+            write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideEvaluationLoops(self, codeString, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideEvaluationLoops(codeString) at line 62, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''// ************* Evaluation code ****************
+''')
+        _v = VFFSL(SL,"codeString",True) # u'${codeString}' on line 65, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${codeString}')) # from line 65, col 1.
+        write(u'''// **********************************************
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # ComputedVector.tmpl
+        # 
+        # Created by Graham Dennis on 2008-03-12.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+''')
+        # 
+        #   Description of template
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_ComputedVector= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(ComputedVector, '_initCheetahAttributes'):
+    templateAPIClass = getattr(ComputedVector, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(ComputedVector)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=ComputedVector()).run()
+
+
diff --git a/xpdeint/Vectors/ComputedVector.tmpl b/xpdeint/Vectors/ComputedVector.tmpl
new file mode 100644
index 0000000..9ab474d
--- /dev/null
+++ b/xpdeint/Vectors/ComputedVector.tmpl
@@ -0,0 +1,68 @@
+@*
+ComputedVector.tmpl
+
+Created by Graham Dennis on 2008-03-12.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Vectors._ComputedVector
+
+@*
+  Description of template
+*@
+ at def description: computed vector $name
+
+ at def evaluateFunctionContents($function)
+@*doc:
+  This function returns the code for the calculated vector's ``evaluate()`` function.
+  
+  The ``evaluate()`` function executes the code that defines the calculated vector.
+*@
+  @#
+  @if $integratingComponents
+    @# If this vector is constructed through an integral, then we first
+    @# need to initialise ourselves to zero.
+${initialise}@slurp
+
+  @end if
+  @#
+  @set $featureOrdering = ['Stochastic']
+  @set $featureDict = {'codeBlock': $codeBlocks['evaluation']}
+  @#
+  @set $vectorOverrides = []
+  @if $integratingComponents
+    @silent vectorOverrides.append(self)
+  @end if
+  @#
+${insertCodeForFeatures('computedVectorEvaluationBegin', $featureOrdering, featureDict)}@slurp
+${codeBlocks['evaluation'].loop(self.insideEvaluationLoops, vectorOverrides=vectorOverrides)}@slurp
+${insertCodeForFeaturesInReverseOrder('computedVectorEvaluationEnd', $featureOrdering, featureDict)}@slurp
+  @#
+  @if $needsTransforms
+
+_${id}_basis = $basisIndexForBasis(self.initialBasis);
+  @end if
+  @#
+ at end def
+
+ at def insideEvaluationLoops(codeString)
+  @#
+// ************* Evaluation code ****************
+${codeString}@slurp
+// **********************************************
+  @#
+ at end def
diff --git a/xpdeint/Vectors/NoiseVector.py b/xpdeint/Vectors/NoiseVector.py
new file mode 100644
index 0000000..7b8e07e
--- /dev/null
+++ b/xpdeint/Vectors/NoiseVector.py
@@ -0,0 +1,369 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Vectors._NoiseVector import _NoiseVector
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.558946
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Vectors/NoiseVector.tmpl'
+__CHEETAH_srcLastModified__ = 'Sat Feb  4 18:39:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class NoiseVector(_NoiseVector):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(NoiseVector, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: noise vector $name at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''noise vector ''')
+        _v = VFFSL(SL,"name",True) # u'$name' on line 27, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'$name')) # from line 27, col 32.
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def evaluateFunctionContents(self, function, **KWS):
+
+
+        """
+        This function returns the code for the calculated vector's ``evaluate()`` function.
+          
+          The ``evaluate()`` function executes the code that defines the calculated vector.
+        """
+
+        ## CHEETAH: generated from @def evaluateFunctionContents($function) at line 29, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        #  For distributed MPI drivers, we may need to share the noise if it is defined on a field
+        #   that is not distributed.
+        featureOrdering = ['Driver']
+        featureDict = {'extraIndent': 0}
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('evaluateNoiseVectorBegin', featureOrdering, featureDict) # u"${insertCodeForFeatures('evaluateNoiseVectorBegin', featureOrdering, featureDict)}" on line 39, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('evaluateNoiseVectorBegin', featureOrdering, featureDict)}")) # from line 39, col 1.
+        extraIndent = featureDict['extraIndent']
+        # 
+        _v = VFFSL(SL,"evaluateFunctionContentsInner",False)(function) # u'${evaluateFunctionContentsInner(function), extraIndent=extraIndent}' on line 42, col 1
+        if _v is not None: write(_filter(_v, extraIndent=extraIndent, rawExpr=u'${evaluateFunctionContentsInner(function), extraIndent=extraIndent}')) # from line 42, col 1.
+        # 
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('evaluateNoiseVectorEnd', featureOrdering, featureDict) # u"${insertCodeForFeaturesInReverseOrder('evaluateNoiseVectorEnd', featureOrdering, featureDict)}" on line 44, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeaturesInReverseOrder('evaluateNoiseVectorEnd', featureOrdering, featureDict)}")) # from line 44, col 1.
+        # 
+        if VFFSL(SL,"needsTransforms",True): # generated from line 46, col 3
+            write(u'''_''')
+            _v = VFFSL(SL,"id",True) # u'${id}' on line 47, col 2
+            if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 47, col 2.
+            write(u'''_basis = ''')
+            _v = VFFSL(SL,"basisIndexForBasis",False)(self.initialBasis) # u'$basisIndexForBasis(self.initialBasis)' on line 47, col 16
+            if _v is not None: write(_filter(_v, rawExpr=u'$basisIndexForBasis(self.initialBasis)')) # from line 47, col 16.
+            write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def evaluateFunctionContentsInner(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def evaluateFunctionContentsInner($function) at line 52, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''const ptrdiff_t _vector_size = ''')
+        _v = VFFSL(SL,"sizeInBasisInReals",False)(self.initialBasis) # u'${sizeInBasisInReals(self.initialBasis)}' on line 54, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'${sizeInBasisInReals(self.initialBasis)}')) # from line 54, col 32.
+        write(u''';
+''')
+        _v = VFFSL(SL,"randomVariable.makeNoises",True) # u'${randomVariable.makeNoises}' on line 55, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${randomVariable.makeNoises}')) # from line 55, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def splitFunctionContents(self, function, **KWS):
+
+
+        """
+        This function is responsible for splitting the noise due to a failed step.
+          
+          As the implementation of this function is dependent on the random variable,
+          it is the responsibility of the random variable to implement this.
+        """
+
+        ## CHEETAH: generated from @def splitFunctionContents($function) at line 59, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        #  For distributed MPI drivers, we may need to share the split noise. So we perform the split
+        #  on only one of the nodes.
+        featureOrdering = ['Driver']
+        featureDict = {'extraIndent': 0}
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('evaluateNoiseVectorBegin', featureOrdering, featureDict) # u"${insertCodeForFeatures('evaluateNoiseVectorBegin', featureOrdering, featureDict)}" on line 70, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('evaluateNoiseVectorBegin', featureOrdering, featureDict)}")) # from line 70, col 1.
+        extraIndent = featureDict['extraIndent']
+        # 
+        _v = VFFSL(SL,"splitFunctionContentsInner",False)(function) # u'${splitFunctionContentsInner(function), extraIndent = extraIndent}' on line 73, col 1
+        if _v is not None: write(_filter(_v, extraIndent = extraIndent, rawExpr=u'${splitFunctionContentsInner(function), extraIndent = extraIndent}')) # from line 73, col 1.
+        # 
+        _v = VFFSL(SL,"insertCodeForFeaturesInReverseOrder",False)('evaluateNoiseVectorEnd', featureOrdering, featureDict) # u"${insertCodeForFeaturesInReverseOrder('evaluateNoiseVectorEnd', featureOrdering, featureDict)}" on line 75, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeaturesInReverseOrder('evaluateNoiseVectorEnd', featureOrdering, featureDict)}")) # from line 75, col 1.
+        # 
+        if VFFSL(SL,"needsTransforms",True): # generated from line 77, col 3
+            write(u'''_''')
+            _v = VFFSL(SL,"id",True) # u'${id}' on line 78, col 2
+            if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 78, col 2.
+            write(u'''_basis = ''')
+            _v = VFFSL(SL,"basisIndexForBasis",False)(self.initialBasis) # u'${basisIndexForBasis(self.initialBasis)}' on line 78, col 16
+            if _v is not None: write(_filter(_v, rawExpr=u'${basisIndexForBasis(self.initialBasis)}')) # from line 78, col 16.
+            write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def splitFunctionContentsInner(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def splitFunctionContentsInner($function) at line 83, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''const ptrdiff_t _vector_size = ''')
+        _v = VFFSL(SL,"sizeInBasisInReals",False)(self.initialBasis) # u'${sizeInBasisInReals(self.initialBasis)}' on line 85, col 32
+        if _v is not None: write(_filter(_v, rawExpr=u'${sizeInBasisInReals(self.initialBasis)}')) # from line 85, col 32.
+        write(u''';
+''')
+        _v = VFN(VFFSL(SL,"randomVariable",True),"splitNoise",False)(function) # u'${randomVariable.splitNoise(function)}' on line 86, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${randomVariable.splitNoise(function)}')) # from line 86, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # NoiseVector.tmpl
+        # 
+        # Created by Joe Hope on 2009-08-17.
+        # 
+        # Copyright (c) 2009-2012, Joe Hope
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+''')
+        # 
+        #   Description of template
+        write(u'''
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_NoiseVector= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(NoiseVector, '_initCheetahAttributes'):
+    templateAPIClass = getattr(NoiseVector, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(NoiseVector)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=NoiseVector()).run()
+
+
diff --git a/xpdeint/Vectors/NoiseVector.tmpl b/xpdeint/Vectors/NoiseVector.tmpl
new file mode 100644
index 0000000..5244e9a
--- /dev/null
+++ b/xpdeint/Vectors/NoiseVector.tmpl
@@ -0,0 +1,88 @@
+@*
+NoiseVector.tmpl
+
+Created by Joe Hope on 2009-08-17.
+
+Copyright (c) 2009-2012, Joe Hope
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Vectors._NoiseVector
+
+@*
+  Description of template
+*@
+ at def description: noise vector $name
+
+ at def evaluateFunctionContents($function)
+@*doc:
+  This function returns the code for the calculated vector's ``evaluate()`` function.
+  
+  The ``evaluate()`` function executes the code that defines the calculated vector.
+*@
+  @# For distributed MPI drivers, we may need to share the noise if it is defined on a field
+  @#  that is not distributed.
+  @set $featureOrdering = ['Driver']
+  @set $featureDict = {'extraIndent': 0}
+${insertCodeForFeatures('evaluateNoiseVectorBegin', featureOrdering, featureDict)}@slurp
+  @set $extraIndent = featureDict['extraIndent']
+  @#
+${evaluateFunctionContentsInner(function), extraIndent=extraIndent}@slurp
+  @#
+${insertCodeForFeaturesInReverseOrder('evaluateNoiseVectorEnd', featureOrdering, featureDict)}@slurp
+  @#
+  @if $needsTransforms
+_${id}_basis = $basisIndexForBasis(self.initialBasis);
+  @end if
+  @#
+ at end def
+
+ at def evaluateFunctionContentsInner($function)
+  @#
+const ptrdiff_t _vector_size = ${sizeInBasisInReals(self.initialBasis)};
+${randomVariable.makeNoises}@slurp
+  @#
+ at end def
+
+ at def splitFunctionContents($function)
+@*doc:
+  This function is responsible for splitting the noise due to a failed step.
+  
+  As the implementation of this function is dependent on the random variable,
+  it is the responsibility of the random variable to implement this.
+*@
+  @# For distributed MPI drivers, we may need to share the split noise. So we perform the split
+  @# on only one of the nodes.
+  @set featureOrdering = ['Driver']
+  @set featureDict = {'extraIndent': 0}
+${insertCodeForFeatures('evaluateNoiseVectorBegin', featureOrdering, featureDict)}@slurp
+  @set $extraIndent = featureDict['extraIndent']
+  @#
+${splitFunctionContentsInner(function), extraIndent = extraIndent}@slurp
+  @#
+${insertCodeForFeaturesInReverseOrder('evaluateNoiseVectorEnd', featureOrdering, featureDict)}@slurp
+  @#
+  @if $needsTransforms
+_${id}_basis = ${basisIndexForBasis(self.initialBasis)};
+  @end if
+  @#
+ at end def
+
+ at def splitFunctionContentsInner($function)
+  @#
+const ptrdiff_t _vector_size = ${sizeInBasisInReals(self.initialBasis)};
+${randomVariable.splitNoise(function)}@slurp
+  @#
+ at end def
diff --git a/xpdeint/Vectors/VectorElement.py b/xpdeint/Vectors/VectorElement.py
new file mode 100644
index 0000000..c0f402c
--- /dev/null
+++ b/xpdeint/Vectors/VectorElement.py
@@ -0,0 +1,654 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Vectors._VectorElement import _VectorElement
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.616958
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Vectors/VectorElement.tmpl'
+__CHEETAH_srcLastModified__ = 'Fri May 25 16:30:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class VectorElement(_VectorElement):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(VectorElement, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: vector $name at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''vector ''')
+        _v = VFFSL(SL,"name",True) # u'$name' on line 27, col 26
+        if _v is not None: write(_filter(_v, rawExpr=u'$name')) # from line 27, col 26.
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def defines(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def defines at line 32, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(VectorElement, self).defines()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''// vector ''')
+        _v = VFFSL(SL,"name",True) # u'$name' on line 36, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$name')) # from line 36, col 11.
+        write(u''' defines
+#define _''')
+        _v = VFFSL(SL,"id",True) # u'${id}' on line 37, col 10
+        if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 37, col 10.
+        write(u'''_ncomponents ''')
+        _v = VFFSL(SL,"nComponents",True) # u'$nComponents' on line 37, col 28
+        if _v is not None: write(_filter(_v, rawExpr=u'$nComponents')) # from line 37, col 28.
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def globals at line 44, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(VectorElement, self).globals()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''// vector ''')
+        _v = VFFSL(SL,"name",True) # u'$name' on line 48, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$name')) # from line 48, col 11.
+        write(u''' globals
+size_t ''')
+        _v = VFFSL(SL,"allocSize",True) # u'${allocSize}' on line 49, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${allocSize}')) # from line 49, col 8.
+        write(u''' = 0;
+''')
+        _v = VFFSL(SL,"type",True) # u'$type' on line 50, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'$type')) # from line 50, col 1.
+        write(u'''* _''')
+        _v = VFFSL(SL,"id",True) # u'${id}' on line 50, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 50, col 9.
+        write(u''' = NULL;
+''')
+        _v = VFFSL(SL,"type",True) # u'$type' on line 51, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'$type')) # from line 51, col 1.
+        write(u'''* _active_''')
+        _v = VFFSL(SL,"id",True) # u'${id}' on line 51, col 16
+        if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 51, col 16.
+        write(u''' = NULL;
+''')
+        for aliasName in VFFSL(SL,"aliases",True): # generated from line 52, col 3
+            _v = VFFSL(SL,"type",True) # u'$type' on line 53, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'$type')) # from line 53, col 1.
+            write(u'''* ''')
+            _v = VFFSL(SL,"aliasName",True) # u'${aliasName}' on line 53, col 8
+            if _v is not None: write(_filter(_v, rawExpr=u'${aliasName}')) # from line 53, col 8.
+            write(u''' = NULL;
+''')
+        # 
+        if VFFSL(SL,"needsTransforms",True): # generated from line 56, col 3
+            write(u'''
+ptrdiff_t _''')
+            _v = VFFSL(SL,"id",True) # u'${id}' on line 58, col 12
+            if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 58, col 12.
+            write(u'''_basis = -1;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def initialiseFunctionContents(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def initialiseFunctionContents($function) at line 66, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        if VFFSL(SL,"integratingComponents",True): # generated from line 68, col 3
+            write(u"""// Because we're integrating over dimensions, we need to set the vector to zero.
+bzero(_active_""")
+            _v = VFFSL(SL,"id",True) # u'${id}' on line 70, col 15
+            if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 70, col 15.
+            write(u''', sizeof(''')
+            _v = VFFSL(SL,"type",True) # u'${type}' on line 70, col 29
+            if _v is not None: write(_filter(_v, rawExpr=u'${type}')) # from line 70, col 29.
+            write(u''') * ''')
+            _v = VFFSL(SL,"allocSize",True) # u'${allocSize}' on line 70, col 40
+            if _v is not None: write(_filter(_v, rawExpr=u'${allocSize}')) # from line 70, col 40.
+            write(u''');
+''')
+        if VFFSL(SL,"initialiser",True): # generated from line 72, col 3
+            write(u'''
+''')
+            _v = VFFSL(SL,"initialiser.initialiseVector",True) # u'${initialiser.initialiseVector}' on line 74, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${initialiser.initialiseVector}')) # from line 74, col 1.
+        if VFFSL(SL,"needsTransforms",True): # generated from line 76, col 3
+            write(u'''
+_''')
+            _v = VFFSL(SL,"id",True) # u'${id}' on line 78, col 2
+            if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 78, col 2.
+            write(u'''_basis = ''')
+            _v = VFFSL(SL,"basisIndexForBasis",False)(self.initialBasis) # u'$basisIndexForBasis(self.initialBasis)' on line 78, col 16
+            if _v is not None: write(_filter(_v, rawExpr=u'$basisIndexForBasis(self.initialBasis)')) # from line 78, col 16.
+            write(u''';
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def basisTransformFunctionContents(self, function, **KWS):
+
+
+
+        ## CHEETAH: generated from @def basisTransformFunctionContents($function) at line 83, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        featureOrdering = ['TransformMultiplexer']
+        dict = {'function': function}
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('basisTransformFunctionContentsBegin', featureOrdering, dict) # u"${insertCodeForFeatures('basisTransformFunctionContentsBegin', featureOrdering, dict)}" on line 87, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('basisTransformFunctionContentsBegin', featureOrdering, dict)}")) # from line 87, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def initialise(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def initialise at line 94, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        if VFFSL(SL,"needsInitialisation",True): # generated from line 96, col 3
+            for aliasName in VFFSL(SL,"aliases",True): # generated from line 97, col 5
+                write(u'''_active_''')
+                _v = VFFSL(SL,"id",True) # u'${id}' on line 98, col 9
+                if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 98, col 9.
+                write(u''' = ''')
+                _v = VFFSL(SL,"aliasName",True) # u'$aliasName' on line 98, col 17
+                if _v is not None: write(_filter(_v, rawExpr=u'$aliasName')) # from line 98, col 17.
+                write(u''';
+''')
+                _v = VFN(VFFSL(SL,"functions",True)['initialise'],"call",False)() # u"${functions['initialise'].call()}" on line 99, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u"${functions['initialise'].call()}")) # from line 99, col 1.
+                write(u'''
+''')
+            write(u'''_active_''')
+            _v = VFFSL(SL,"id",True) # u'${id}' on line 101, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 101, col 9.
+            write(u''' = _''')
+            _v = VFFSL(SL,"id",True) # u'${id}' on line 101, col 18
+            if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 101, col 18.
+            write(u''';
+''')
+            _v = VFN(VFFSL(SL,"functions",True)['initialise'],"call",False)() # u"${functions['initialise'].call()}" on line 102, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u"${functions['initialise'].call()}")) # from line 102, col 1.
+            write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def allocate(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def allocate at line 110, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''
+_''')
+        _v = VFFSL(SL,"id",True) # u'${id}' on line 112, col 2
+        if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 112, col 2.
+        write(u''' = (''')
+        _v = VFFSL(SL,"type",True) # u'$type' on line 112, col 11
+        if _v is not None: write(_filter(_v, rawExpr=u'$type')) # from line 112, col 11.
+        write(u'''*) xmds_malloc(sizeof(''')
+        _v = VFFSL(SL,"type",True) # u'${type}' on line 112, col 38
+        if _v is not None: write(_filter(_v, rawExpr=u'${type}')) # from line 112, col 38.
+        write(u''') * MAX(''')
+        _v = VFFSL(SL,"allocSize",True) # u'${allocSize}' on line 112, col 53
+        if _v is not None: write(_filter(_v, rawExpr=u'${allocSize}')) # from line 112, col 53.
+        write(u''',1));
+_active_''')
+        _v = VFFSL(SL,"id",True) # u'${id}' on line 113, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 113, col 9.
+        write(u''' = _''')
+        _v = VFFSL(SL,"id",True) # u'${id}' on line 113, col 18
+        if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 113, col 18.
+        write(u''';
+''')
+        for aliasName in VFFSL(SL,"aliases",True): # generated from line 114, col 3
+            _v = VFFSL(SL,"aliasName",True) # u'$aliasName' on line 115, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'$aliasName')) # from line 115, col 1.
+            write(u''' = (''')
+            _v = VFFSL(SL,"type",True) # u'$type' on line 115, col 15
+            if _v is not None: write(_filter(_v, rawExpr=u'$type')) # from line 115, col 15.
+            write(u'''*) xmds_malloc(sizeof(''')
+            _v = VFFSL(SL,"type",True) # u'${type}' on line 115, col 42
+            if _v is not None: write(_filter(_v, rawExpr=u'${type}')) # from line 115, col 42.
+            write(u''') * MAX(''')
+            _v = VFFSL(SL,"allocSize",True) # u'${allocSize}' on line 115, col 57
+            if _v is not None: write(_filter(_v, rawExpr=u'${allocSize}')) # from line 115, col 57.
+            write(u''',1)); // alias for _''')
+            _v = VFFSL(SL,"id",True) # u'${id}' on line 115, col 89
+            if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 115, col 89.
+            write(u'''
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def free(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def free at line 119, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''
+xmds_free(_''')
+        _v = VFFSL(SL,"id",True) # u'${id}' on line 121, col 12
+        if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 121, col 12.
+        write(u''');
+_active_''')
+        _v = VFFSL(SL,"id",True) # u'${id}' on line 122, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 122, col 9.
+        write(u''' = _''')
+        _v = VFFSL(SL,"id",True) # u'${id}' on line 122, col 18
+        if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 122, col 18.
+        write(u''' = NULL;
+''')
+        for aliasName in VFFSL(SL,"aliases",True): # generated from line 123, col 3
+            write(u'''xmds_free(''')
+            _v = VFFSL(SL,"aliasName",True) # u'$aliasName' on line 124, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'$aliasName')) # from line 124, col 11.
+            write(u'''); // alias for _''')
+            _v = VFFSL(SL,"id",True) # u'${id}' on line 124, col 38
+            if _v is not None: write(_filter(_v, rawExpr=u'${id}')) # from line 124, col 38.
+            write(u'''
+''')
+            _v = VFFSL(SL,"aliasName",True) # u'${aliasName}' on line 125, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${aliasName}')) # from line 125, col 1.
+            write(u''' = NULL;
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def findMaximum(self, variableName, basis=None, **KWS):
+
+
+
+        ## CHEETAH: generated from @def findMaximum($variableName, $basis = None) at line 129, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''real ''')
+        _v = VFFSL(SL,"variableName",True) # u'${variableName}' on line 130, col 6
+        if _v is not None: write(_filter(_v, rawExpr=u'${variableName}')) # from line 130, col 6.
+        write(u''' = 0.0;
+
+''')
+        if VFFSL(SL,"type",True) == 'real': # generated from line 132, col 3
+            modFunction = 'abs'
+        else: # generated from line 134, col 3
+            modFunction = 'mod2'
+        ## START CAPTURE REGION: _54047541 loopContents at line 137, col 3 in the source.
+        _orig_trans_54047541 = trans
+        _wasBuffering_54047541 = self._CHEETAH__isBuffering
+        self._CHEETAH__isBuffering = True
+        trans = _captureCollector_54047541 = DummyTransaction()
+        write = _captureCollector_54047541.response().write
+        write(u'''real _current_size = ''')
+        _v = VFFSL(SL,"modFunction",True) # u'${modFunction}' on line 138, col 22
+        if _v is not None: write(_filter(_v, rawExpr=u'${modFunction}')) # from line 138, col 22.
+        write(u'''(_active_${vector.id}[${index}]);
+if (_current_size > ''')
+        _v = VFFSL(SL,"variableName",True) # u'$variableName' on line 139, col 21
+        if _v is not None: write(_filter(_v, rawExpr=u'$variableName')) # from line 139, col 21.
+        write(u''') // UNVECTORISABLE
+  ''')
+        _v = VFFSL(SL,"variableName",True) # u'${variableName}' on line 140, col 3
+        if _v is not None: write(_filter(_v, rawExpr=u'${variableName}')) # from line 140, col 3.
+        write(u''' = _current_size;
+''')
+        trans = _orig_trans_54047541
+        write = trans.response().write
+        self._CHEETAH__isBuffering = _wasBuffering_54047541 
+        loopContents = _captureCollector_54047541.response().getvalue()
+        del _orig_trans_54047541
+        del _captureCollector_54047541
+        del _wasBuffering_54047541
+        _v = VFFSL(SL,"loopOverVectorsWithInnerContentTemplate",False)([self], loopContents, basis = basis) # u'${loopOverVectorsWithInnerContentTemplate([self], loopContents, basis = basis)}' on line 142, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${loopOverVectorsWithInnerContentTemplate([self], loopContents, basis = basis)}')) # from line 142, col 1.
+        if VFFSL(SL,"type",True) == 'complex': # generated from line 143, col 3
+            _v = VFFSL(SL,"variableName",True) # u'${variableName}' on line 144, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${variableName}')) # from line 144, col 1.
+            write(u''' = sqrt(''')
+            _v = VFFSL(SL,"variableName",True) # u'${variableName}' on line 144, col 24
+            if _v is not None: write(_filter(_v, rawExpr=u'${variableName}')) # from line 144, col 24.
+            write(u'''); // Take the square root to find the modulus.
+''')
+        _v = VFFSL(SL,"insertCodeForFeatures",False)('findMax', ['Driver'], {'variable': ''.join([u'&',str(VFFSL(SL,"variableName",True))]), 'count': '1'}) # u"${insertCodeForFeatures('findMax', ['Driver'], {'variable': c'&${variableName}', 'count': '1'})}" on line 146, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"${insertCodeForFeatures('findMax', ['Driver'], {'variable': c'&${variableName}', 'count': '1'})}")) # from line 146, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # VectorElement.tmpl
+        # 
+        # Created by Graham Dennis on 2007-08-28.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+''')
+        # 
+        #   Description of template
+        write(u'''
+''')
+        # 
+        #   Defines needed at the start of the simulation
+        write(u'''
+''')
+        # 
+        #   Globals needed at the start of the simulation
+        write(u'''
+''')
+        # 
+        #   Write the vector initialisation routine
+        write(u'''
+
+''')
+        # 
+        #   Initialise vector (called from segment 0)
+        write(u'''
+''')
+        # 
+        #   Allocate (and initialise active pointers) (called from main)
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_VectorElement= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(VectorElement, '_initCheetahAttributes'):
+    templateAPIClass = getattr(VectorElement, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(VectorElement)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=VectorElement()).run()
+
+
diff --git a/xpdeint/Vectors/VectorElement.tmpl b/xpdeint/Vectors/VectorElement.tmpl
new file mode 100644
index 0000000..ea9ac6a
--- /dev/null
+++ b/xpdeint/Vectors/VectorElement.tmpl
@@ -0,0 +1,148 @@
+@*
+VectorElement.tmpl
+
+Created by Graham Dennis on 2007-08-28.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Vectors._VectorElement
+
+@*
+  Description of template
+*@
+ at def description: vector $name
+
+@*
+  Defines needed at the start of the simulation
+*@
+ at def defines
+  @#
+  @super
+  @#
+// vector $name defines
+#define _${id}_ncomponents $nComponents
+  @#
+ at end def
+
+@*
+  Globals needed at the start of the simulation
+*@
+ at def globals
+  @#
+  @super
+  @#
+// vector $name globals
+size_t ${allocSize} = 0;
+$type* _${id} = NULL;
+$type* _active_${id} = NULL;
+  @for aliasName in $aliases
+$type* ${aliasName} = NULL;
+  @end for
+  @#
+  @if $needsTransforms
+
+ptrdiff_t _${id}_basis = -1;
+  @end if
+  @#
+ at end def
+
+@*
+  Write the vector initialisation routine
+*@
+ at def initialiseFunctionContents($function)
+  @#
+  @if $integratingComponents
+// Because we're integrating over dimensions, we need to set the vector to zero.
+bzero(_active_${id}, sizeof(${type}) * ${allocSize});
+  @end if
+  @if $initialiser
+
+${initialiser.initialiseVector}@slurp
+  @end if
+  @if $needsTransforms
+
+_${id}_basis = $basisIndexForBasis(self.initialBasis);
+  @end if
+  @#
+ at end def
+
+ at def basisTransformFunctionContents($function)
+  @#
+  @set $featureOrdering = ['TransformMultiplexer']
+  @set $dict = {'function': function}
+${insertCodeForFeatures('basisTransformFunctionContentsBegin', featureOrdering, dict)}@slurp
+  @#
+ at end def
+
+@*
+  Initialise vector (called from segment 0)
+*@
+ at def initialise
+  @#
+  @if $needsInitialisation
+    @for aliasName in $aliases
+_active_${id} = $aliasName;
+${functions['initialise'].call()}
+    @end for
+_active_${id} = _${id};
+${functions['initialise'].call()}
+  @end if
+  @#
+ at end def
+
+@*
+  Allocate (and initialise active pointers) (called from main)
+*@
+ at def allocate
+
+_${id} = ($type*) xmds_malloc(sizeof(${type}) * MAX(${allocSize},1));
+_active_${id} = _${id};
+  @for aliasName in $aliases
+$aliasName = ($type*) xmds_malloc(sizeof(${type}) * MAX(${allocSize},1)); // alias for _${id}
+  @end for
+ at end def
+
+ at def free
+
+xmds_free(_${id});
+_active_${id} = _${id} = NULL;
+  @for aliasName in $aliases
+xmds_free($aliasName); // alias for _${id}
+${aliasName} = NULL;
+  @end for
+ at end def
+
+ at def findMaximum($variableName, $basis = None)
+real ${variableName} = 0.0;
+
+  @if $type == 'real'
+    @set $modFunction = 'abs'
+  @else
+    @set $modFunction = 'mod2'
+  @end if
+  @capture loopContents
+real _current_size = ${modFunction}(_active_\${vector.id}[\${index}]);
+if (_current_size > $variableName) // UNVECTORISABLE
+  ${variableName} = _current_size;
+  @end capture
+${loopOverVectorsWithInnerContentTemplate([self], loopContents, basis = basis)}@slurp
+  @if $type == 'complex'
+${variableName} = sqrt(${variableName}); // Take the square root to find the modulus.
+  @end if
+${insertCodeForFeatures('findMax', ['Driver'], {'variable': c'&${variableName}', 'count': '1'})}@slurp
+  @#
+ at end def
diff --git a/xpdeint/Vectors/VectorInitialisation.py b/xpdeint/Vectors/VectorInitialisation.py
new file mode 100644
index 0000000..e9a6720
--- /dev/null
+++ b/xpdeint/Vectors/VectorInitialisation.py
@@ -0,0 +1,253 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.ScriptElement import ScriptElement
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.620831
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Vectors/VectorInitialisation.tmpl'
+__CHEETAH_srcLastModified__ = 'Fri May 25 16:30:07 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class VectorInitialisation(ScriptElement):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(VectorInitialisation, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Vector initialisation to zero at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Vector initialisation to zero''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @property
+    def field(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def field at line 31, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        return VFFSL(SL,"vector.field",True)
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def initialiseVector(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def initialiseVector at line 39, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''bzero(_active_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 40, col 15
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 40, col 15.
+        write(u''', sizeof(''')
+        _v = VFFSL(SL,"vector.type",True) # u'${vector.type}' on line 40, col 36
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.type}')) # from line 40, col 36.
+        write(u''') * ''')
+        _v = VFFSL(SL,"vector.allocSize",True) # u'${vector.allocSize}' on line 40, col 54
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.allocSize}')) # from line 40, col 54.
+        write(u''');
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # VectorInitialisation.tmpl
+        # 
+        # Created by Graham Dennis on 2007-08-29.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        # 
+        #   
+        #   Description of initialisation method
+        write(u'''
+''')
+        #  Property to define the field that this initialisation will occur in
+        write(u'''
+''')
+        # 
+        # 
+        #   Initialise a vector
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_VectorInitialisation= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(VectorInitialisation, '_initCheetahAttributes'):
+    templateAPIClass = getattr(VectorInitialisation, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(VectorInitialisation)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=VectorInitialisation()).run()
+
+
diff --git a/xpdeint/Vectors/VectorInitialisation.tmpl b/xpdeint/Vectors/VectorInitialisation.tmpl
new file mode 100644
index 0000000..d136984
--- /dev/null
+++ b/xpdeint/Vectors/VectorInitialisation.tmpl
@@ -0,0 +1,41 @@
+@*
+VectorInitialisation.tmpl
+
+Created by Graham Dennis on 2007-08-29.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.ScriptElement
+@*
+  
+  Description of initialisation method
+*@
+ at def description: Vector initialisation to zero
+
+@# Property to define the field that this initialisation will occur in
+@@property
+ at def field
+  @return $vector.field
+ at end def
+
+@*
+
+  Initialise a vector
+*@
+ at def initialiseVector
+bzero(_active_${vector.id}, sizeof(${vector.type}) * ${vector.allocSize});
+ at end def
diff --git a/xpdeint/Vectors/VectorInitialisationFromCDATA.py b/xpdeint/Vectors/VectorInitialisationFromCDATA.py
new file mode 100644
index 0000000..c56e5fb
--- /dev/null
+++ b/xpdeint/Vectors/VectorInitialisationFromCDATA.py
@@ -0,0 +1,271 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Vectors.VectorInitialisation import VectorInitialisation
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.612134
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Vectors/VectorInitialisationFromCDATA.tmpl'
+__CHEETAH_srcLastModified__ = 'Fri May 25 16:17:13 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class VectorInitialisationFromCDATA(VectorInitialisation):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(VectorInitialisationFromCDATA, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Vector initialisation from CDATA at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Vector initialisation from CDATA''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def initialiseVector(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def initialiseVector at line 33, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        vectorOverrides = []
+        if VFFSL(SL,"vector.integratingComponents",True): # generated from line 36, col 2
+            vectorOverrides.append(VFFSL(SL,"vector",True))
+        _v = VFN(VFFSL(SL,"codeBlocks",True)['initialisation'],"loop",False)(self.insideInitialisationLoops, vectorOverrides=vectorOverrides) # u"$codeBlocks['initialisation'].loop(self.insideInitialisationLoops, vectorOverrides=vectorOverrides)" on line 39, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u"$codeBlocks['initialisation'].loop(self.insideInitialisationLoops, vectorOverrides=vectorOverrides)")) # from line 39, col 1.
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideInitialisationLoops(self, codeString, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideInitialisationLoops($codeString) at line 44, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u"""// The purpose of the following define is to give a (somewhat helpful) compile-time error
+// if the user has attempted to use the propagation dimension variable in the initialisation
+// block of a <vector> element. If they're trying to do this, what they really want is a 
+// <computed_vector> instead.
+#define """)
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 49, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 49, col 9.
+        write(u''' Dont_use_propagation_dimension_''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 49, col 64
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 49, col 64.
+        write(u'''_in_vector_element_CDATA_block___Use_a_computed_vector_instead
+
+// ********** Initialisation code ***************
+''')
+        _v = VFFSL(SL,"codeString",True) # u'${codeString}' on line 52, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${codeString}')) # from line 52, col 1.
+        write(u'''// **********************************************
+#undef ''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 54, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 54, col 8.
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # VectorInitialisationFromCDATA.tmpl
+        # 
+        # Created by Graham Dennis on 2007-08-29.
+        # 
+        # Copyright (c) 2007-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+''')
+        # 
+        #   Description of initialisation method
+        write(u'''
+
+''')
+        # 
+        #   Initialise a vector
+        write(u'''
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_VectorInitialisationFromCDATA= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(VectorInitialisationFromCDATA, '_initCheetahAttributes'):
+    templateAPIClass = getattr(VectorInitialisationFromCDATA, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(VectorInitialisationFromCDATA)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=VectorInitialisationFromCDATA()).run()
+
+
diff --git a/xpdeint/Vectors/VectorInitialisationFromCDATA.tmpl b/xpdeint/Vectors/VectorInitialisationFromCDATA.tmpl
new file mode 100644
index 0000000..852da70
--- /dev/null
+++ b/xpdeint/Vectors/VectorInitialisationFromCDATA.tmpl
@@ -0,0 +1,56 @@
+@*
+VectorInitialisationFromCDATA.tmpl
+
+Created by Graham Dennis on 2007-08-29.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Vectors.VectorInitialisation
+
+@*
+  Description of initialisation method
+*@
+ at def description: Vector initialisation from CDATA
+
+
+@*
+  Initialise a vector
+*@
+ at def initialiseVector
+ @#
+ @set $vectorOverrides = []
+ @if $vector.integratingComponents
+   @silent vectorOverrides.append($vector)
+ @end if
+$codeBlocks['initialisation'].loop(self.insideInitialisationLoops, vectorOverrides=vectorOverrides)@slurp
+ @#
+ at end def
+
+
+ at def insideInitialisationLoops($codeString)
+// The purpose of the following define is to give a (somewhat helpful) compile-time error
+// if the user has attempted to use the propagation dimension variable in the initialisation
+// block of a <vector> element. If they're trying to do this, what they really want is a 
+// <computed_vector> instead.
+#define ${propagationDimension} Dont_use_propagation_dimension_${propagationDimension}_in_vector_element_CDATA_block___Use_a_computed_vector_instead
+
+// ********** Initialisation code ***************
+${codeString}@slurp
+// **********************************************
+#undef ${propagationDimension}
+
+ at end def
diff --git a/xpdeint/Vectors/VectorInitialisationFromHDF5.py b/xpdeint/Vectors/VectorInitialisationFromHDF5.py
new file mode 100644
index 0000000..f0e8969
--- /dev/null
+++ b/xpdeint/Vectors/VectorInitialisationFromHDF5.py
@@ -0,0 +1,768 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Vectors._VectorInitialisationFromHDF5 import _VectorInitialisationFromHDF5
+from xpdeint.Geometry.SplitUniformDimensionRepresentation import SplitUniformDimensionRepresentation
+from xpdeint.Geometry.NonUniformDimensionRepresentation import NonUniformDimensionRepresentation
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.868601
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Vectors/VectorInitialisationFromHDF5.tmpl'
+__CHEETAH_srcLastModified__ = 'Fri May 25 16:17:13 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class VectorInitialisationFromHDF5(_VectorInitialisationFromHDF5):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(VectorInitialisationFromHDF5, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Vector initialisation from a HDF5 file at line 27, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Vector initialisation from a HDF5 file''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def initialiseVector(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def initialiseVector at line 29, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        basis = VFFSL(SL,"vector.initialBasis",True)
+        field = VFFSL(SL,"vector.field",True)
+        dimensionOffsets = {}
+        # 
+        initialisationCodeBlock = VFFSL(SL,"codeBlocks",True)['initialisation']
+        write(u'''// HDF5 initialisation has three stages.
+// 1. Initialise the vector to zero.
+// 2. Execute any CDATA code if there is any.
+// 3. Read data from the HDF5 file.
+
+{
+  // Stage 1 of initialisation
+  bzero(_active_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 43, col 17
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 43, col 17.
+        write(u''', sizeof(''')
+        _v = VFFSL(SL,"vector.type",True) # u'${vector.type}' on line 43, col 38
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.type}')) # from line 43, col 38.
+        write(u''') * ''')
+        _v = VFFSL(SL,"vector.allocSize",True) # u'${vector.allocSize}' on line 43, col 56
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.allocSize}')) # from line 43, col 56.
+        write(u''');
+''')
+        if VFN(VFFSL(SL,"initialisationCodeBlock.codeString",True),"isspace",False)(): # generated from line 44, col 3
+            write(u'''  // There is no stage 2
+''')
+        else: # generated from line 46, col 3
+            vectorOverrides = []
+            if VFFSL(SL,"vector.integratingComponents",True): # generated from line 48, col 5
+                vectorOverrides.append(VFFSL(SL,"vector",True))
+            write(u'''  // Stage 2 of initialisation
+  ''')
+            _v = VFN(VFFSL(SL,"initialisationCodeBlock",True),"loop",False)(self.insideInitialisationLoops, vectorOverrides=vectorOverrides) # u'${initialisationCodeBlock.loop(self.insideInitialisationLoops, vectorOverrides=vectorOverrides), autoIndent=True}' on line 52, col 3
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${initialisationCodeBlock.loop(self.insideInitialisationLoops, vectorOverrides=vectorOverrides), autoIndent=True}')) # from line 52, col 3.
+        write(u'''}
+
+htri_t result;
+hid_t hdf5_file = H5Fopen("''')
+        _v = VFFSL(SL,"filename",True) # u'${filename}' on line 57, col 28
+        if _v is not None: write(_filter(_v, rawExpr=u'${filename}')) # from line 57, col 28.
+        write(u'''", H5F_ACC_RDONLY, H5P_DEFAULT);
+if (hdf5_file < 0) {
+  _LOG(_ERROR_LOG_LEVEL, "Unable to open input HDF5 file \'''')
+        _v = VFFSL(SL,"filename",True) # u'${filename}' on line 59, col 59
+        if _v is not None: write(_filter(_v, rawExpr=u'${filename}')) # from line 59, col 59.
+        write(u'''\'. Does it exist?\\n");
+}
+hid_t hdf5_parent = 0;
+''')
+        if VFFSL(SL,"groupName",True): # generated from line 62, col 3
+            write(u'''if ((result = H5Lexists(hdf5_file, "''')
+            _v = VFFSL(SL,"groupName",True) # u'${groupName}' on line 63, col 37
+            if _v is not None: write(_filter(_v, rawExpr=u'${groupName}')) # from line 63, col 37.
+            write(u'''", H5P_DEFAULT)) > 0) {
+  hdf5_parent = H5Gopen(hdf5_file, "''')
+            _v = VFFSL(SL,"groupName",True) # u'${groupName}' on line 64, col 37
+            if _v is not None: write(_filter(_v, rawExpr=u'${groupName}')) # from line 64, col 37.
+            write(u'''");
+} else if (!result) {
+  _LOG(_ERROR_LOG_LEVEL, "Unable to find group \'''')
+            _v = VFFSL(SL,"groupName",True) # u'${groupName}' on line 66, col 49
+            if _v is not None: write(_filter(_v, rawExpr=u'${groupName}')) # from line 66, col 49.
+            write(u"""' in HDF5 file '""")
+            _v = VFFSL(SL,"filename",True) # u'${filename}' on line 66, col 77
+            if _v is not None: write(_filter(_v, rawExpr=u'${filename}')) # from line 66, col 77.
+            write(u'''\'.\\n");
+} else {
+  _LOG(_ERROR_LOG_LEVEL, "Unable to determine if group \'''')
+            _v = VFFSL(SL,"groupName",True) # u'${groupName}' on line 68, col 57
+            if _v is not None: write(_filter(_v, rawExpr=u'${groupName}')) # from line 68, col 57.
+            write(u"""' exists in HDF5 file '""")
+            _v = VFFSL(SL,"filename",True) # u'${filename}' on line 68, col 92
+            if _v is not None: write(_filter(_v, rawExpr=u'${filename}')) # from line 68, col 92.
+            write(u'''\'. Is the file corrupt?\\n");
+}
+''')
+        else: # generated from line 70, col 3
+            write(u'''if ((result = H5Lexists(hdf5_file, "/1", H5P_DEFAULT)) > 0) {
+  hdf5_parent = H5Gopen(hdf5_file, "/1");
+} else if (!result) {
+  hdf5_parent = hdf5_file;
+} else {
+  _LOG(_ERROR_LOG_LEVEL, "Unable to determine if group \'/1\' exists in HDF5 file \'''')
+            _v = VFFSL(SL,"filename",True) # u'${filename}' on line 76, col 82
+            if _v is not None: write(_filter(_v, rawExpr=u'${filename}')) # from line 76, col 82.
+            write(u'''\'. Is the file corrupt?\\n");
+}
+''')
+        write(u'''
+''')
+        dimCount = len(field.dimensions)
+        write(u'''hsize_t file_dims[''')
+        _v = VFFSL(SL,"dimCount",True) # u'${dimCount}' on line 81, col 19
+        if _v is not None: write(_filter(_v, rawExpr=u'${dimCount}')) # from line 81, col 19.
+        write(u'''];
+
+''')
+        for dimNum, dim in enumerate(field.dimensions): # generated from line 83, col 3
+            dimRep = dim.inBasis(VFFSL(SL,"vector.initialBasis",True))
+            write(u'''hid_t dataset_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 85, col 15
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 85, col 15.
+            write(u''';
+if ((result = H5Lexists(hdf5_parent, "''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 86, col 39
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 86, col 39.
+            write(u'''", H5P_DEFAULT))>0)
+  dataset_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 87, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 87, col 11.
+            write(u''' = H5Dopen(hdf5_parent, "''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 87, col 50
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 87, col 50.
+            write(u'''");
+else if (!result)
+  _LOG(_ERROR_LOG_LEVEL, "Error: Unable to find dimension \'''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 89, col 60
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 89, col 60.
+            write(u'''\' in HDF5 file.\\n");
+else
+  _LOG(_ERROR_LOG_LEVEL, "Error: Unable to determine if dimension \'''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 91, col 68
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 91, col 68.
+            write(u'''\' exists in HDF5 file. Is the file corrupt?\\n");
+hid_t dataspace_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 92, col 17
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 92, col 17.
+            write(u''' = H5Dget_space(dataset_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 92, col 55
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 92, col 55.
+            write(u''');
+file_dims[''')
+            _v = VFFSL(SL,"dimNum",True) # u'$dimNum' on line 93, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'$dimNum')) # from line 93, col 11.
+            write(u'''] = H5Sget_simple_extent_npoints(dataspace_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 93, col 61
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 93, col 61.
+            write(u''');
+''')
+            _v = VFFSL(SL,"dimRep.type",True) # u'${dimRep.type}' on line 94, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.type}')) # from line 94, col 1.
+            write(u'''* ''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 94, col 17
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 94, col 17.
+            write(u'''_inputdata = (''')
+            _v = VFFSL(SL,"dimRep.type",True) # u'${dimRep.type}' on line 94, col 45
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.type}')) # from line 94, col 45.
+            write(u'''*)xmds_malloc(file_dims[''')
+            _v = VFFSL(SL,"dimNum",True) # u'${dimNum}' on line 94, col 83
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimNum}')) # from line 94, col 83.
+            write(u'''] * sizeof(''')
+            _v = VFFSL(SL,"dimRep.type",True) # u'${dimRep.type}' on line 94, col 103
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.type}')) # from line 94, col 103.
+            write(u'''));
+''')
+            dataType = {'real': 'H5T_NATIVE_REAL', 'long': 'H5T_NATIVE_LONG'}[VFFSL(SL,"dimRep.type",True)]
+            write(u'''H5Dread(dataset_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 96, col 17
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 96, col 17.
+            write(u''', ''')
+            _v = VFFSL(SL,"dataType",True) # u'$dataType' on line 96, col 33
+            if _v is not None: write(_filter(_v, rawExpr=u'$dataType')) # from line 96, col 33.
+            write(u''', H5S_ALL, H5S_ALL, H5P_DEFAULT, ''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 96, col 75
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 96, col 75.
+            write(u'''_inputdata);
+''')
+            if isinstance(dimRep, SplitUniformDimensionRepresentation): # generated from line 97, col 5
+                dimArrayName = ''.join([str(VFFSL(SL,"dimRep.name",True)),u'_data'])
+                _v = VFFSL(SL,"dimRep.type",True) # u'${dimRep.type}' on line 99, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.type}')) # from line 99, col 1.
+                write(u'''* ''')
+                _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 99, col 17
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 99, col 17.
+                write(u''' = (''')
+                _v = VFFSL(SL,"dimRep.type",True) # u'${dimRep.type}' on line 99, col 36
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.type}')) # from line 99, col 36.
+                write(u'''*)xmds_malloc(''')
+                _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 99, col 64
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 99, col 64.
+                write(u''' * sizeof(''')
+                _v = VFFSL(SL,"dimRep.type",True) # u'${dimRep.type}' on line 99, col 97
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.type}')) # from line 99, col 97.
+                write(u'''));
+for (long _i0 = 0; _i0 < ''')
+                _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 100, col 26
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 100, col 26.
+                write(u'''; _i0++) {
+  ''')
+                _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 101, col 3
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 101, col 3.
+                write(u'''[_i0] = ''')
+                _v = VFFSL(SL,"dimRep.arrayName",True) # u'${dimRep.arrayName}' on line 101, col 26
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.arrayName}')) # from line 101, col 26.
+                write(u'''[(_i0 + (''')
+                _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 101, col 54
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 101, col 54.
+                write(u'''+1)/2) % ''')
+                _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 101, col 86
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 101, col 86.
+                write(u'''];
+}
+''')
+            else: # generated from line 103, col 5
+                dimArrayName = dimRep.arrayName
+            if VFFSL(SL,"geometryMatchingMode",True) == 'strict' or isinstance(dimRep, NonUniformDimensionRepresentation): # generated from line 106, col 5
+                write(u'''for (long _i0 = 0; _i0 < ''')
+                _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 107, col 26
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 107, col 26.
+                write(u'''-1; _i0++) {
+  real step = ''')
+                _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 108, col 15
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 108, col 15.
+                write(u'''[_i0+1] - ''')
+                _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 108, col 40
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 108, col 40.
+                write(u'''[_i0];
+  if (abs(''')
+                _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 109, col 11
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 109, col 11.
+                write(u'''[_i0] - ''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 109, col 34
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 109, col 34.
+                write(u'''_inputdata[_i0]) > 0.01 * step) {
+    // _LOG will cause the simulation to exit
+    _LOG(_ERROR_LOG_LEVEL, "Geometry matching mode is strict for dimension \'''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 111, col 77
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 111, col 77.
+                write(u'''\'.\\n"
+                           "This means that the coordinates must be the same as for the input grid.\\n"
+                           "The problem was found at input_''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 113, col 60
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 113, col 60.
+                write(u''': %e, simulation_''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 113, col 91
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 113, col 91.
+                write(u''': %e, difference: %e\\n",
+                           (real)''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 114, col 34
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 114, col 34.
+                write(u'''_inputdata[_i0], (real)''')
+                _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 114, col 71
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 114, col 71.
+                write(u'''[_i0], (real)''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 114, col 99
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 114, col 99.
+                write(u'''_inputdata[_i0] - ''')
+                _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 114, col 131
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 114, col 131.
+                write(u'''[_i0]);
+  }
+}
+''')
+            else: # generated from line 117, col 5
+                #  Here we implement any checks required for 'loose' geometryMatchingMode
+                #  We know that the dimension is uniform, therefore we should first check the deltas.
+                write(u'''// Check that the deltas are the same to within 0.1%
+real ''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 121, col 6
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 121, col 6.
+                write(u'''_step = ''')
+                _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 121, col 28
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 121, col 28.
+                write(u'''[1] - ''')
+                _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 121, col 49
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 121, col 49.
+                write(u'''[0];
+real ''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 122, col 6
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 122, col 6.
+                write(u'''_inputdata_step = ''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 122, col 38
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 122, col 38.
+                write(u'''_inputdata[1] - ''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 122, col 68
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 122, col 68.
+                write(u'''_inputdata[0];
+if (abs(''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 123, col 9
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 123, col 9.
+                write(u'''_step - ''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 123, col 31
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 123, col 31.
+                write(u'''_inputdata_step) > 1e-3*''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 123, col 69
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 123, col 69.
+                write(u'''_step) {
+  // _LOG will cause the simulation to exit
+  _LOG(_ERROR_LOG_LEVEL, "The step size in the \'''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 125, col 49
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 125, col 49.
+                write(u'''\' dimension of the input data and simulation grid do not match.\\n"
+                         "The step size in the \'''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 126, col 49
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 126, col 49.
+                write(u'''\' dimension was %e, while the input data had step size %e.\\n",
+                         (real)''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 127, col 32
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 127, col 32.
+                write(u'''_step, (real)''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 127, col 59
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 127, col 59.
+                write(u'''_inputdata_step);
+}
+// Check the input and simulation grids overlap
+if ((''')
+                _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 130, col 6
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 130, col 6.
+                write(u'''[0] > ''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 130, col 27
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 130, col 27.
+                write(u'''_inputdata[file_dims[''')
+                _v = VFFSL(SL,"dimNum",True) # u'${dimNum}' on line 130, col 62
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimNum}')) # from line 130, col 62.
+                write(u''']-1]) || (''')
+                _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 130, col 81
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 130, col 81.
+                write(u'''[''')
+                _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 130, col 97
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 130, col 97.
+                write(u'''-1] < ''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 130, col 126
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 130, col 126.
+                write(u'''_inputdata[0])) {
+  // _LOG will cause the simulation to exit
+  _LOG(_ERROR_LOG_LEVEL, "The input and simulation grids do not overlap!\\n"
+                         "The simulation grid runs from %e to %e, but the input grid runs from %e to %e.\\n",
+                         (real)''')
+                _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 134, col 32
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 134, col 32.
+                write(u'''[0], (real)''')
+                _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 134, col 58
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 134, col 58.
+                write(u'''[''')
+                _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 134, col 74
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 134, col 74.
+                write(u'''-1],
+                         (real)''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 135, col 32
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 135, col 32.
+                write(u'''_inputdata[0], (real)''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 135, col 67
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 135, col 67.
+                write(u'''_inputdata[file_dims[''')
+                _v = VFFSL(SL,"dimNum",True) # u'${dimNum}' on line 135, col 102
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimNum}')) # from line 135, col 102.
+                write(u''']-1]);
+}
+real ''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 137, col 6
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 137, col 6.
+                write(u'''_fileOffsetR = (''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 137, col 36
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 137, col 36.
+                write(u'''_inputdata[0]-''')
+                _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 137, col 64
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 137, col 64.
+                write(u'''[0])/''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 137, col 84
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 137, col 84.
+                write(u'''_step;
+if (remainder(''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 138, col 15
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 138, col 15.
+                write(u'''_inputdata[0]-''')
+                _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 138, col 43
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 138, col 43.
+                write(u'''[0], ''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 138, col 63
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 138, col 63.
+                write(u'''_step) > 0.01*''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 138, col 91
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 138, col 91.
+                write(u'''_step) {
+  _LOG(_ERROR_LOG_LEVEL, "The input and simulation grids do not overlap sufficiently!\\n"
+                         "The calculated offset for the input grid from the simulation grid in the \'''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 140, col 101
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 140, col 101.
+                write(u'''\' dimension is %f, and it should be integral!\\n",
+                         (''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 141, col 27
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 141, col 27.
+                write(u'''_inputdata[0]-''')
+                _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 141, col 55
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 141, col 55.
+                write(u'''[0])/''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 141, col 75
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 141, col 75.
+                write(u'''_step);
+}
+long ''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 143, col 6
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 143, col 6.
+                write(u'''_fileOffset = lround((''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 143, col 42
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 143, col 42.
+                write(u'''_inputdata[0]-''')
+                _v = VFFSL(SL,"dimArrayName",True) # u'${dimArrayName}' on line 143, col 70
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimArrayName}')) # from line 143, col 70.
+                write(u'''[0])/''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 143, col 90
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 143, col 90.
+                write(u'''_step);
+''')
+                dimensionOffsets[dimRep.name] = ''.join([str(VFFSL(SL,"dimRep.name",True)),u'_fileOffset'])
+        write(u'''
+''')
+        processingDict = {'field': field, 'operation': 'read', 'basis': basis, 'dimensionOffsets': dimensionOffsets}
+        variables = [{'vector': VFFSL(SL,"vector",True), 'arrayName': ''.join([u'_active_',str(VFFSL(SL,"vector.id",True))]), 'components': VFFSL(SL,"vector.components",True)}]
+        write(u'''hid_t file_dataspace;
+file_dataspace = H5Screate_simple(''')
+        _v = VFFSL(SL,"len",False)(field.dimensions) # u'${len(field.dimensions)}' on line 151, col 35
+        if _v is not None: write(_filter(_v, rawExpr=u'${len(field.dimensions)}')) # from line 151, col 35.
+        write(u''', file_dims, NULL);
+''')
+        for variable in variables: # generated from line 152, col 3
+            if VFFSL(SL,"variable.vector.type",True) == 'real': # generated from line 153, col 5
+                variable['separatedComponents'] = list(enumerate(VFFSL(SL,"variable.components",True)))
+            else: # generated from line 155, col 5
+                components = []
+                variable['separatedComponents'] = components
+                for offset, componentName in enumerate(VFFSL(SL,"variable.components",True)): # generated from line 158, col 7
+                    components.extend([(2*offset, componentName + 'R'), (2*offset+1, componentName + 'I')])
+            write(u'''bool _variablesFound = false;
+''')
+            for offset, componentName in VFFSL(SL,"variable.separatedComponents",True): # generated from line 163, col 5
+                write(u'''hid_t dataset_''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 164, col 15
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 164, col 15.
+                write(u''' = 0;
+if ((result = H5Lexists(hdf5_parent, "''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 165, col 39
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 165, col 39.
+                write(u'''", H5P_DEFAULT))>0) {
+  dataset_''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 166, col 11
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 166, col 11.
+                write(u''' = H5Dopen(hdf5_parent, "''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 166, col 52
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 166, col 52.
+                write(u'''");
+  _variablesFound = true;
+} else if (!result)
+  _LOG(_WARNING_LOG_LEVEL, "Warning: Unable to find variable name \'''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 169, col 68
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 169, col 68.
+                write(u'''\' in HDF5 file.\\n");
+else
+  _LOG(_WARNING_LOG_LEVEL, "Warning: Unable to determine if variable \'''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 171, col 71
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 171, col 71.
+                write(u'''\' exists in HDF5 file. Is the file corrupt?\\n");
+''')
+        write(u'''
+if (!_variablesFound) {
+  // We haven\'t found anything. There\'s a problem with the input file.
+  _LOG(_ERROR_LOG_LEVEL, "Error: None of the variables were found in the HDF5 file. Please check the file.\\n");
+}
+''')
+        processingDict['variables'] = variables
+        _v = VFFSL(SL,"processData",False)(processingDict) # u'${processData(processingDict)}' on line 180, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${processData(processingDict)}')) # from line 180, col 1.
+        write(u'''
+
+''')
+        for variable in variables: # generated from line 183, col 3
+            for offset, componentName in VFFSL(SL,"variable.separatedComponents",True): # generated from line 184, col 5
+                write(u'''if (dataset_''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 185, col 13
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 185, col 13.
+                write(u''') H5Dclose(dataset_''')
+                _v = VFFSL(SL,"componentName",True) # u'${componentName}' on line 185, col 48
+                if _v is not None: write(_filter(_v, rawExpr=u'${componentName}')) # from line 185, col 48.
+                write(u''');
+''')
+        write(u'''H5Sclose(file_dataspace);
+
+''')
+        for dim in VFFSL(SL,"vector.field.dimensions",True): # generated from line 190, col 3
+            dimRep = dim.inBasis(VFFSL(SL,"vector.initialBasis",True))
+            if isinstance(dimRep, SplitUniformDimensionRepresentation): # generated from line 192, col 5
+                write(u'''xmds_free(''')
+                _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 193, col 11
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 193, col 11.
+                write(u'''_data);
+''')
+            write(u'''xmds_free(''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 195, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 195, col 11.
+            write(u'''_inputdata);
+H5Sclose(dataspace_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 196, col 20
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 196, col 20.
+            write(u''');
+H5Dclose(dataset_''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 197, col 18
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 197, col 18.
+            write(u''');
+''')
+        write(u'''if (hdf5_parent != hdf5_file)
+  H5Gclose(hdf5_parent);
+H5Fclose(hdf5_file);
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideInitialisationLoops(self, codeString, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideInitialisationLoops($codeString) at line 205, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u"""// Stage 2 of initialisation
+
+// The purpose of the following define is to give a (somewhat helpful) compile-time error
+// if the user has attempted to use the propagation dimension variable in the initialisation
+// block of a <vector> element. If they're trying to do this, what they really want is a 
+// <computed_vector> instead.
+#define """)
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 213, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 213, col 9.
+        write(u''' Dont_use_propagation_dimension_''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 213, col 64
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 213, col 64.
+        write(u'''_in_vector_element_CDATA_block___Use_a_computed_vector_instead
+
+// ********** Initialisation code ***************
+''')
+        _v = VFFSL(SL,"codeString",True) # u'${codeString}' on line 216, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${codeString}')) # from line 216, col 1.
+        write(u'''// **********************************************
+#undef ''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 218, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 218, col 8.
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # VectorInitialisationFromHDF5.tmpl
+        # 
+        # Created by Graham Dennis on 2009-01-29.
+        # 
+        # Copyright (c) 2009-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    _mainCheetahMethod_for_VectorInitialisationFromHDF5= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(VectorInitialisationFromHDF5, '_initCheetahAttributes'):
+    templateAPIClass = getattr(VectorInitialisationFromHDF5, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(VectorInitialisationFromHDF5)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=VectorInitialisationFromHDF5()).run()
+
+
diff --git a/xpdeint/Vectors/VectorInitialisationFromHDF5.tmpl b/xpdeint/Vectors/VectorInitialisationFromHDF5.tmpl
new file mode 100644
index 0000000..c1983a5
--- /dev/null
+++ b/xpdeint/Vectors/VectorInitialisationFromHDF5.tmpl
@@ -0,0 +1,221 @@
+@*
+VectorInitialisationFromHDF5.tmpl
+
+Created by Graham Dennis on 2009-01-29.
+
+Copyright (c) 2009-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Vectors._VectorInitialisationFromHDF5
+
+ at from xpdeint.Geometry.SplitUniformDimensionRepresentation import SplitUniformDimensionRepresentation
+ at from xpdeint.Geometry.NonUniformDimensionRepresentation import NonUniformDimensionRepresentation
+
+ at def description: Vector initialisation from a HDF5 file
+
+ at def initialiseVector
+  @#
+  @set $basis = $vector.initialBasis
+  @set $field = $vector.field
+  @set $dimensionOffsets = {}
+  @#
+  @set $initialisationCodeBlock = $codeBlocks['initialisation']
+// HDF5 initialisation has three stages.
+// 1. Initialise the vector to zero.
+// 2. Execute any CDATA code if there is any.
+// 3. Read data from the HDF5 file.
+
+{
+  // Stage 1 of initialisation
+  bzero(_active_${vector.id}, sizeof(${vector.type}) * ${vector.allocSize});
+  @if $initialisationCodeBlock.codeString.isspace()
+  // There is no stage 2
+  @else
+    @set $vectorOverrides = []
+    @if $vector.integratingComponents
+      @silent vectorOverrides.append($vector)
+    @end if
+  // Stage 2 of initialisation
+  ${initialisationCodeBlock.loop(self.insideInitialisationLoops, vectorOverrides=vectorOverrides), autoIndent=True}@slurp
+  @end if
+}
+
+htri_t result;
+hid_t hdf5_file = H5Fopen("${filename}", H5F_ACC_RDONLY, H5P_DEFAULT);
+if (hdf5_file < 0) {
+  _LOG(_ERROR_LOG_LEVEL, "Unable to open input HDF5 file '${filename}'. Does it exist?\n");
+}
+hid_t hdf5_parent = 0;
+  @if $groupName
+if ((result = H5Lexists(hdf5_file, "${groupName}", H5P_DEFAULT)) > 0) {
+  hdf5_parent = H5Gopen(hdf5_file, "${groupName}");
+} else if (!result) {
+  _LOG(_ERROR_LOG_LEVEL, "Unable to find group '${groupName}' in HDF5 file '${filename}'.\n");
+} else {
+  _LOG(_ERROR_LOG_LEVEL, "Unable to determine if group '${groupName}' exists in HDF5 file '${filename}'. Is the file corrupt?\n");
+}
+  @else
+if ((result = H5Lexists(hdf5_file, "/1", H5P_DEFAULT)) > 0) {
+  hdf5_parent = H5Gopen(hdf5_file, "/1");
+} else if (!result) {
+  hdf5_parent = hdf5_file;
+} else {
+  _LOG(_ERROR_LOG_LEVEL, "Unable to determine if group '/1' exists in HDF5 file '${filename}'. Is the file corrupt?\n");
+}
+  @end if
+
+  @set $dimCount = len(field.dimensions)
+hsize_t file_dims[${dimCount}];
+
+  @for dimNum, dim in enumerate(field.dimensions)
+    @set $dimRep = dim.inBasis($vector.initialBasis)
+hid_t dataset_${dimRep.name};
+if ((result = H5Lexists(hdf5_parent, "${dimRep.name}", H5P_DEFAULT))>0)
+  dataset_${dimRep.name} = H5Dopen(hdf5_parent, "${dimRep.name}");
+else if (!result)
+  _LOG(_ERROR_LOG_LEVEL, "Error: Unable to find dimension '${dimRep.name}' in HDF5 file.\n");
+else
+  _LOG(_ERROR_LOG_LEVEL, "Error: Unable to determine if dimension '${dimRep.name}' exists in HDF5 file. Is the file corrupt?\n");
+hid_t dataspace_${dimRep.name} = H5Dget_space(dataset_${dimRep.name});
+file_dims[$dimNum] = H5Sget_simple_extent_npoints(dataspace_${dimRep.name});
+${dimRep.type}* ${dimRep.name}_inputdata = (${dimRep.type}*)xmds_malloc(file_dims[${dimNum}] * sizeof(${dimRep.type}));
+    @set $dataType = {'real': 'H5T_NATIVE_REAL', 'long': 'H5T_NATIVE_LONG'}[$dimRep.type]
+H5Dread(dataset_${dimRep.name}, $dataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, ${dimRep.name}_inputdata);
+    @if isinstance(dimRep, SplitUniformDimensionRepresentation)
+      @set $dimArrayName = c'${dimRep.name}_data'
+${dimRep.type}* ${dimArrayName} = (${dimRep.type}*)xmds_malloc(${dimRep.globalLattice} * sizeof(${dimRep.type}));
+for (long _i0 = 0; _i0 < ${dimRep.globalLattice}; _i0++) {
+  ${dimArrayName}[_i0] = ${dimRep.arrayName}[(_i0 + (${dimRep.globalLattice}+1)/2) % ${dimRep.globalLattice}];
+}
+    @else
+      @set $dimArrayName = dimRep.arrayName
+    @end if
+    @if $geometryMatchingMode == 'strict' or isinstance(dimRep, NonUniformDimensionRepresentation)
+for (long _i0 = 0; _i0 < ${dimRep.globalLattice}-1; _i0++) {
+  real step = ${dimArrayName}[_i0+1] - ${dimArrayName}[_i0];
+  if (abs(${dimArrayName}[_i0] - ${dimRep.name}_inputdata[_i0]) > 0.01 * step) {
+    // _LOG will cause the simulation to exit
+    _LOG(_ERROR_LOG_LEVEL, "Geometry matching mode is strict for dimension '${dimRep.name}'.\n"
+                           "This means that the coordinates must be the same as for the input grid.\n"
+                           "The problem was found at input_${dimRep.name}: %e, simulation_${dimRep.name}: %e, difference: %e\n",
+                           (real)${dimRep.name}_inputdata[_i0], (real)${dimArrayName}[_i0], (real)${dimRep.name}_inputdata[_i0] - ${dimArrayName}[_i0]);
+  }
+}
+    @else
+      @# Here we implement any checks required for 'loose' geometryMatchingMode
+      @# We know that the dimension is uniform, therefore we should first check the deltas.
+// Check that the deltas are the same to within 0.1%
+real ${dimRep.name}_step = ${dimArrayName}[1] - ${dimArrayName}[0];
+real ${dimRep.name}_inputdata_step = ${dimRep.name}_inputdata[1] - ${dimRep.name}_inputdata[0];
+if (abs(${dimRep.name}_step - ${dimRep.name}_inputdata_step) > 1e-3*${dimRep.name}_step) {
+  // _LOG will cause the simulation to exit
+  _LOG(_ERROR_LOG_LEVEL, "The step size in the '${dimRep.name}' dimension of the input data and simulation grid do not match.\n"
+                         "The step size in the '${dimRep.name}' dimension was %e, while the input data had step size %e.\n",
+                         (real)${dimRep.name}_step, (real)${dimRep.name}_inputdata_step);
+}
+// Check the input and simulation grids overlap
+if ((${dimArrayName}[0] > ${dimRep.name}_inputdata[file_dims[${dimNum}]-1]) || (${dimArrayName}[${dimRep.globalLattice}-1] < ${dimRep.name}_inputdata[0])) {
+  // _LOG will cause the simulation to exit
+  _LOG(_ERROR_LOG_LEVEL, "The input and simulation grids do not overlap!\n"
+                         "The simulation grid runs from %e to %e, but the input grid runs from %e to %e.\n",
+                         (real)${dimArrayName}[0], (real)${dimArrayName}[${dimRep.globalLattice}-1],
+                         (real)${dimRep.name}_inputdata[0], (real)${dimRep.name}_inputdata[file_dims[${dimNum}]-1]);
+}
+real ${dimRep.name}_fileOffsetR = (${dimRep.name}_inputdata[0]-${dimArrayName}[0])/${dimRep.name}_step;
+if (remainder(${dimRep.name}_inputdata[0]-${dimArrayName}[0], ${dimRep.name}_step) > 0.01*${dimRep.name}_step) {
+  _LOG(_ERROR_LOG_LEVEL, "The input and simulation grids do not overlap sufficiently!\n"
+                         "The calculated offset for the input grid from the simulation grid in the '${dimRep.name}' dimension is %f, and it should be integral!\n",
+                         (${dimRep.name}_inputdata[0]-${dimArrayName}[0])/${dimRep.name}_step);
+}
+long ${dimRep.name}_fileOffset = lround((${dimRep.name}_inputdata[0]-${dimArrayName}[0])/${dimRep.name}_step);
+      @silent dimensionOffsets[dimRep.name] = c'${dimRep.name}_fileOffset'
+    @end if
+  @end for
+
+  @set $processingDict = {'field': field, 'operation': 'read', 'basis': basis, 'dimensionOffsets': dimensionOffsets}
+  @set $variables = [{'vector': $vector, 'arrayName': c'_active_${vector.id}', 'components': $vector.components}]
+hid_t file_dataspace;
+file_dataspace = H5Screate_simple(${len(field.dimensions)}, file_dims, NULL);
+  @for variable in variables
+    @if $variable.vector.type == 'real'
+      @set $variable['separatedComponents'] = list(enumerate($variable.components))
+    @else
+      @set $components = []
+      @set variable['separatedComponents'] = components
+      @for offset, componentName in enumerate($variable.components)
+        @silent components.extend([(2*offset, componentName + 'R'), (2*offset+1, componentName + 'I')])
+      @end for
+    @end if
+bool _variablesFound = false;
+    @for offset, componentName in $variable.separatedComponents
+hid_t dataset_${componentName} = 0;
+if ((result = H5Lexists(hdf5_parent, "${componentName}", H5P_DEFAULT))>0) {
+  dataset_${componentName} = H5Dopen(hdf5_parent, "${componentName}");
+  _variablesFound = true;
+} else if (!result)
+  _LOG(_WARNING_LOG_LEVEL, "Warning: Unable to find variable name '${componentName}' in HDF5 file.\n");
+else
+  _LOG(_WARNING_LOG_LEVEL, "Warning: Unable to determine if variable '${componentName}' exists in HDF5 file. Is the file corrupt?\n");
+    @end for
+  @end for
+
+if (!_variablesFound) {
+  // We haven't found anything. There's a problem with the input file.
+  _LOG(_ERROR_LOG_LEVEL, "Error: None of the variables were found in the HDF5 file. Please check the file.\n");
+}
+  @silent processingDict['variables'] = variables
+${processData(processingDict)}@slurp
+
+
+  @for variable in variables
+    @for offset, componentName in $variable.separatedComponents
+if (dataset_${componentName}) H5Dclose(dataset_${componentName});
+    @end for
+  @end for
+H5Sclose(file_dataspace);
+
+  @for dim in $vector.field.dimensions
+    @set $dimRep = dim.inBasis($vector.initialBasis)
+    @if isinstance(dimRep, SplitUniformDimensionRepresentation)
+xmds_free(${dimRep.name}_data);
+    @end if
+xmds_free(${dimRep.name}_inputdata);
+H5Sclose(dataspace_${dimRep.name});
+H5Dclose(dataset_${dimRep.name});
+  @end for
+if (hdf5_parent != hdf5_file)
+  H5Gclose(hdf5_parent);
+H5Fclose(hdf5_file);
+  @#
+ at end def
+
+ at def insideInitialisationLoops($codeString)
+  @#
+// Stage 2 of initialisation
+
+// The purpose of the following define is to give a (somewhat helpful) compile-time error
+// if the user has attempted to use the propagation dimension variable in the initialisation
+// block of a <vector> element. If they're trying to do this, what they really want is a 
+// <computed_vector> instead.
+#define ${propagationDimension} Dont_use_propagation_dimension_${propagationDimension}_in_vector_element_CDATA_block___Use_a_computed_vector_instead
+
+// ********** Initialisation code ***************
+${codeString}@slurp
+// **********************************************
+#undef ${propagationDimension}
+  @#
+ at end def
+
diff --git a/xpdeint/Vectors/VectorInitialisationFromXSIL.py b/xpdeint/Vectors/VectorInitialisationFromXSIL.py
new file mode 100644
index 0000000..e24dd4c
--- /dev/null
+++ b/xpdeint/Vectors/VectorInitialisationFromXSIL.py
@@ -0,0 +1,1045 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+from xpdeint.Vectors.VectorInitialisation import VectorInitialisation
+from xpdeint.CallOnceGuards import callOnceGuard
+from xpdeint.Geometry.UniformDimensionRepresentation import UniformDimensionRepresentation
+from xpdeint.Geometry.SplitUniformDimensionRepresentation import SplitUniformDimensionRepresentation
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.885613
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/Vectors/VectorInitialisationFromXSIL.tmpl'
+__CHEETAH_srcLastModified__ = 'Fri May 25 16:17:13 2012'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class VectorInitialisationFromXSIL(VectorInitialisation):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(VectorInitialisationFromXSIL, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Vector initialisation from an XSIL file at line 30, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Vector initialisation from an XSIL file''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOnceGuard
+    def static_functionPrototypes(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def static_functionPrototypes at line 33, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(VectorInitialisationFromXSIL, self).static_functionPrototypes()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''inline uint32_t XMDSSwapInt32(uint32_t __arg);
+inline uint64_t XMDSSwapInt64(uint64_t __arg);
+inline float XMDSSwapFloat(float __in);
+inline double XMDSSwapDouble(double __in);
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOnceGuard
+    def globals(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def globals at line 45, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        _v = super(VectorInitialisationFromXSIL, self).globals()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''// This stuff is here because libxmds requires it.
+// That is because we need the XML parser in order to be able
+// to load XSIL files to initialise fields
+bool debugFlag = false;
+bool xmlDebugFlag =  false;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    @callOnceGuard
+    def static_functionImplementations(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def static_functionImplementations at line 57, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        _v = super(VectorInitialisationFromXSIL, self).static_functionImplementations()
+        if _v is not None: write(_filter(_v))
+        # 
+        write(u'''// The following code is imported from CFByteOrder.h, and is used subject to the APSL v2
+// The license is at: http://www.opensource.apple.com/apsl
+
+// These functions have been renamed to avoid conflicts with the actual functions if an XMDS simulation
+// is ever linked against the CoreFoundation framework
+
+// 32-bit byte swapper
+inline uint32_t XMDSSwapInt32(uint32_t __arg)
+{
+#if defined(__i386__) && defined(__GNUC__)
+  __asm__("bswap %0" : "+r" (__arg));
+  return __arg;
+#elif defined(__ppc__) && defined(__GNUC__)
+  uint32_t __result;
+  __asm__("lwbrx %0, 0, %1" : "=r" (__result) : "r" (&__arg), "m" (__arg));
+  return __result;
+#else
+  uint32_t __result;
+  __result = ((__arg & 0xFF) << 24) | ((__arg & 0xFF00) << 8) | ((__arg >> 8) & 0xFF00) | ((__arg >> 24) & 0xFF);
+  return __result;
+#endif
+}
+
+// 64-bit byte-swapper
+inline uint64_t XMDSSwapInt64(uint64_t __arg)
+{
+  union XMDSSwap {
+    uint64_t __sv;
+    uint32_t __ul[2];
+    } __tmp, __result;
+  __tmp.__sv = __arg;
+  __result.__ul[0] = XMDSSwapInt32(__tmp.__ul[1]);
+  __result.__ul[1] = XMDSSwapInt32(__tmp.__ul[0]);
+  return __result.__sv;
+}
+
+inline float XMDSSwapFloat(float __in)
+{
+  union XMDSSwap {
+    float __f;
+    uint32_t __ul;
+  } __tmp;
+  __tmp.__f = __in;
+  __tmp.__ul = XMDSSwapInt32(__tmp.__ul);
+  return __tmp.__f;
+}
+
+inline double XMDSSwapDouble(double __in)
+{
+  union XMDSSwap {
+    double __d;
+    uint64_t __ull;
+  } __tmp;
+  __tmp.__d = __in;
+  __tmp.__ull = XMDSSwapInt64(__tmp.__ull);
+  return __tmp.__d;
+}
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def initialiseVector(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def initialiseVector at line 125, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        initialisationCodeBlock = VFFSL(SL,"codeBlocks",True)['initialisation']
+        write(u'''// XSIL initialisation has three stages.
+// 1. Initialise the vector to zero.
+// 2. Execute any CDATA code if there is any.
+// 3. Read data from the XSIL file.
+
+{
+  // Stage 1 of initialisation
+  bzero(_active_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 135, col 17
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 135, col 17.
+        write(u''', sizeof(''')
+        _v = VFFSL(SL,"vector.type",True) # u'${vector.type}' on line 135, col 38
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.type}')) # from line 135, col 38.
+        write(u''') * ''')
+        _v = VFFSL(SL,"vector.allocSize",True) # u'${vector.allocSize}' on line 135, col 56
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.allocSize}')) # from line 135, col 56.
+        write(u''');
+''')
+        if VFN(VFFSL(SL,"initialisationCodeBlock.codeString",True),"isspace",False)(): # generated from line 136, col 3
+            write(u'''  // There is no stage 2
+''')
+        else: # generated from line 138, col 3
+            vectorOverrides = []
+            if VFFSL(SL,"vector.integratingComponents",True): # generated from line 140, col 5
+                vectorOverrides.append(VFFSL(SL,"vector",True))
+            write(u'''  // Stage 2 of initialisation
+  ''')
+            _v = VFN(VFFSL(SL,"initialisationCodeBlock",True),"loop",False)(self.insideInitialisationLoops, vectorOverrides=vectorOverrides) # u'${initialisationCodeBlock.loop(self.insideInitialisationLoops, vectorOverrides=vectorOverrides), autoIndent=True}' on line 144, col 3
+            if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${initialisationCodeBlock.loop(self.insideInitialisationLoops, vectorOverrides=vectorOverrides), autoIndent=True}')) # from line 144, col 3.
+        write(u'''}
+
+char **_dimNames  = new char* [_''')
+        _v = VFFSL(SL,"vector.field.name",True) # u'${vector.field.name}' on line 148, col 33
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.field.name}')) # from line 148, col 33.
+        write(u'''_ndims];
+double *_dimDelta = new double[_''')
+        _v = VFFSL(SL,"vector.field.name",True) # u'${vector.field.name}' on line 149, col 33
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.field.name}')) # from line 149, col 33.
+        write(u'''_ndims];
+double *_dimMin   = new double[_''')
+        _v = VFFSL(SL,"vector.field.name",True) # u'${vector.field.name}' on line 150, col 33
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.field.name}')) # from line 150, col 33.
+        write(u'''_ndims];
+unsigned long *_dimLattice = new unsigned long[_''')
+        _v = VFFSL(SL,"vector.field.name",True) # u'${vector.field.name}' on line 151, col 49
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.field.name}')) # from line 151, col 49.
+        write(u'''_ndims];
+
+''')
+        for dimensionNumber, dimension in enumerate(VFFSL(SL,"vector.field.dimensions",True)): # generated from line 153, col 3
+            dimRep = dimension.inBasis(VFFSL(SL,"vector.initialBasis",True))
+            write(u'''_dimNames[''')
+            _v = VFFSL(SL,"dimensionNumber",True) # u'$dimensionNumber' on line 155, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'$dimensionNumber')) # from line 155, col 11.
+            write(u''']   = "''')
+            _v = VFFSL(SL,"dimRep.name",True) # u'${dimRep.name}' on line 155, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.name}')) # from line 155, col 34.
+            write(u'''";
+_dimDelta[''')
+            _v = VFFSL(SL,"dimensionNumber",True) # u'$dimensionNumber' on line 156, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'$dimensionNumber')) # from line 156, col 11.
+            write(u''']   = ''')
+            _v = VFFSL(SL,"dimRep.stepSize",True) # u'${dimRep.stepSize}' on line 156, col 33
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.stepSize}')) # from line 156, col 33.
+            write(u''';
+_dimMin[''')
+            _v = VFFSL(SL,"dimensionNumber",True) # u'$dimensionNumber' on line 157, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'$dimensionNumber')) # from line 157, col 9.
+            write(u''']     = ''')
+            _v = VFFSL(SL,"dimRep.minimum",True) # u'${dimRep.minimum}' on line 157, col 33
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.minimum}')) # from line 157, col 33.
+            write(u''';
+_dimLattice[''')
+            _v = VFFSL(SL,"dimensionNumber",True) # u'$dimensionNumber' on line 158, col 13
+            if _v is not None: write(_filter(_v, rawExpr=u'$dimensionNumber')) # from line 158, col 13.
+            write(u'''] = ''')
+            _v = VFFSL(SL,"dimRep.globalLattice",True) # u'${dimRep.globalLattice}' on line 158, col 33
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.globalLattice}')) # from line 158, col 33.
+            write(u''';
+
+''')
+        # 
+        componentNameSizePrefix = ''
+        if VFFSL(SL,"vector.type",True) == 'complex': # generated from line 163, col 3
+            componentNameSizePrefix = '2 * '
+        write(u'''char **_componentNames = new char*[''')
+        _v = VFFSL(SL,"componentNameSizePrefix",True) # u'${componentNameSizePrefix}' on line 166, col 36
+        if _v is not None: write(_filter(_v, rawExpr=u'${componentNameSizePrefix}')) # from line 166, col 36.
+        write(u'''_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 166, col 63
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 166, col 63.
+        write(u'''_ncomponents + 1];
+int *_componentFieldIndices = new int[''')
+        _v = VFFSL(SL,"componentNameSizePrefix",True) # u'${componentNameSizePrefix}' on line 167, col 39
+        if _v is not None: write(_filter(_v, rawExpr=u'${componentNameSizePrefix}')) # from line 167, col 39.
+        write(u'''_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 167, col 66
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 167, col 66.
+        write(u'''_ncomponents];
+
+''')
+        componentNameIndex = 0
+        for component in VFFSL(SL,"vector.components",True): # generated from line 170, col 3
+            write(u'''_componentNames[''')
+            _v = VFFSL(SL,"componentNameIndex",True) # u'$componentNameIndex' on line 171, col 17
+            if _v is not None: write(_filter(_v, rawExpr=u'$componentNameIndex')) # from line 171, col 17.
+            write(u'''] = "''')
+            _v = VFFSL(SL,"component",True) # u'${component}' on line 171, col 41
+            if _v is not None: write(_filter(_v, rawExpr=u'${component}')) # from line 171, col 41.
+            write(u'''R";
+''')
+            componentNameIndex += 1
+            # 
+            if VFFSL(SL,"vector.type",True) == 'complex': # generated from line 174, col 5
+                write(u'''_componentNames[''')
+                _v = VFFSL(SL,"componentNameIndex",True) # u'$componentNameIndex' on line 175, col 17
+                if _v is not None: write(_filter(_v, rawExpr=u'$componentNameIndex')) # from line 175, col 17.
+                write(u'''] = "''')
+                _v = VFFSL(SL,"component",True) # u'${component}' on line 175, col 41
+                if _v is not None: write(_filter(_v, rawExpr=u'${component}')) # from line 175, col 41.
+                write(u'''I";
+''')
+                componentNameIndex += 1
+            write(u'''
+''')
+        write(u'''_componentNames[''')
+        _v = VFFSL(SL,"componentNameIndex",True) # u'$componentNameIndex' on line 180, col 17
+        if _v is not None: write(_filter(_v, rawExpr=u'$componentNameIndex')) # from line 180, col 17.
+        write(u'''] = NULL;
+
+char *_binaryDataFilename;
+int _unsignedLongSize;
+bool _dataEncodingIsNative;
+bool _isPrecisionDouble;
+unsigned long _nDataComponents;
+unsigned long *_inputLattice;
+int *_componentInputIndices;
+
+if (!initialiseFieldFromXSILFile("''')
+        _v = VFFSL(SL,"filename",True) # u'${filename}' on line 190, col 35
+        if _v is not None: write(_filter(_v, rawExpr=u'${filename}')) # from line 190, col 35.
+        write(u'''", "''')
+        _v = VFFSL(SL,"momentGroupName",True) # u'${momentGroupName}' on line 190, col 50
+        if _v is not None: write(_filter(_v, rawExpr=u'${momentGroupName}')) # from line 190, col 50.
+        write(u'''", _''')
+        _v = VFFSL(SL,"vector.field.name",True) # u'${vector.field.name}' on line 190, col 72
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.field.name}')) # from line 190, col 72.
+        write(u'''_ndims, _dimNames, _componentNames, 
+                                 // output variables
+                                 &_binaryDataFilename, &_unsignedLongSize, &_dataEncodingIsNative, &_isPrecisionDouble,
+                                 &_nDataComponents, &_inputLattice, &_componentInputIndices))
+  _LOG(_ERROR_LOG_LEVEL, "Unable to load data from ''')
+        _v = VFFSL(SL,"filename",True) # u'${filename}' on line 194, col 52
+        if _v is not None: write(_filter(_v, rawExpr=u'${filename}')) # from line 194, col 52.
+        write(u'''\\nExiting.\\n");
+
+FILE *_inputFile = fopen(_binaryDataFilename, "rb");
+if (_inputFile == NULL)
+  _LOG(_ERROR_LOG_LEVEL, "Unable to open binary input file %s\\n", _binaryDataFilename);
+
+typedef union {
+  float *_floatPtr;
+  double *_doublePtr;
+} _GenericRealNumberPtr;
+
+typedef union {
+  unsigned long _ulong;
+  uint32_t _uint32;
+  uint64_t _uint64;
+} _GenericUnsignedLong;
+
+_GenericUnsignedLong _size;
+_GenericRealNumberPtr *_inputData = new _GenericRealNumberPtr[_''')
+        _v = VFFSL(SL,"vector.field.name",True) # u'${vector.field.name}' on line 212, col 64
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.field.name}')) # from line 212, col 64.
+        write(u'''_ndims];
+
+// loop over the dimensions in the binary file
+for (int __i = 0; __i < _''')
+        _v = VFFSL(SL,"vector.field.name",True) # u'${vector.field.name}' on line 215, col 26
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.field.name}')) # from line 215, col 26.
+        write(u'''_ndims; __i++) {
+  uint64_t _sizeValue;
+  switch(_unsignedLongSize) {
+''')
+        for unsignedLongSize, unionElement, typeName, swapFunctionName in [('0', '_ulong',  'unsigned long', 'XMDSSwapInt32'),                                                                      ('4', '_uint32', 'uint32_t',      'XMDSSwapInt32'),                                                                      ('8', '_uint64', 'uint64_t',      'XMDSSwapInt64')]: # generated from line 218, col 3
+            write(u'''    case ''')
+            _v = VFFSL(SL,"unsignedLongSize",True) # u'${unsignedLongSize}' on line 221, col 10
+            if _v is not None: write(_filter(_v, rawExpr=u'${unsignedLongSize}')) # from line 221, col 10.
+            write(u''':
+      fread(&_size.''')
+            _v = VFFSL(SL,"unionElement",True) # u'${unionElement}' on line 222, col 20
+            if _v is not None: write(_filter(_v, rawExpr=u'${unionElement}')) # from line 222, col 20.
+            write(u''', sizeof(''')
+            _v = VFFSL(SL,"typeName",True) # u'${typeName}' on line 222, col 44
+            if _v is not None: write(_filter(_v, rawExpr=u'${typeName}')) # from line 222, col 44.
+            write(u'''), 1, _inputFile);
+      if (_dataEncodingIsNative)
+        _sizeValue = _size.''')
+            _v = VFFSL(SL,"unionElement",True) # u'${unionElement}' on line 224, col 28
+            if _v is not None: write(_filter(_v, rawExpr=u'${unionElement}')) # from line 224, col 28.
+            write(u''';
+      else
+        _sizeValue = ''')
+            _v = VFFSL(SL,"swapFunctionName",True) # u'${swapFunctionName}' on line 226, col 22
+            if _v is not None: write(_filter(_v, rawExpr=u'${swapFunctionName}')) # from line 226, col 22.
+            write(u'''(_size.''')
+            _v = VFFSL(SL,"unionElement",True) # u'${unionElement}' on line 226, col 48
+            if _v is not None: write(_filter(_v, rawExpr=u'${unionElement}')) # from line 226, col 48.
+            write(u''');
+      _unsignedLongSize = sizeof(''')
+            _v = VFFSL(SL,"typeName",True) # u'${typeName}' on line 227, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'${typeName}')) # from line 227, col 34.
+            write(u''');
+      break;
+    
+''')
+        write(u'''    default:
+      _LOG(_ERROR_LOG_LEVEL, "Unexpected unsigned long size in input XSIL file. Was expecting \'4\' or \'8\', instead got \'%i\'\\n", _unsignedLongSize);
+  }
+  
+  // Read in the data (in either single or double precision)
+  if (_isPrecisionDouble) {
+    _inputData[__i]._doublePtr = new double[_sizeValue];
+    fread(_inputData[__i]._doublePtr, sizeof(double), _sizeValue, _inputFile);
+    if (!_dataEncodingIsNative) {
+      for (unsigned int __j = 0; __j < _sizeValue; __j++)
+        _inputData[__i]._doublePtr[__j] = XMDSSwapDouble(_inputData[__i]._doublePtr[__j]);
+    }
+  } else {
+    _inputData[__i]._floatPtr = new float[_sizeValue];
+    fread(_inputData[__i]._floatPtr, sizeof(float), _sizeValue, _inputFile);
+    if (!_dataEncodingIsNative) {
+      for (unsigned int __j = 0; __j < _sizeValue; __j++)
+        _inputData[__i]._floatPtr[__j] = XMDSSwapFloat(_inputData[__i]._floatPtr[__j]);
+    }
+  }
+  
+  double _difference;
+  if (_isPrecisionDouble)
+    _difference = _inputData[__i]._doublePtr[1] - _inputData[__i]._doublePtr[0];
+  else
+    _difference = _inputData[__i]._floatPtr[1]  - _inputData[__i]._floatPtr[0];
+  
+  // Assert that the deltas are the same to within 1%
+  if (abs(_dimDelta[__i] - _difference) > 0.01 * _dimDelta[__i])
+    // _LOG will cause the simulation to exit
+    _LOG(_ERROR_LOG_LEVEL, "The step size in the \'%s\' dimension of the input data and the simulation grid do not match.\\n"
+                           "The step size in the \'%s\' dimension was %e, while the input data had a step size of %e.\\n",
+                           _dimNames[__i], _dimNames[__i], _dimDelta[__i], _difference);
+''')
+        # 
+        if VFFSL(SL,"geometryMatchingMode",True) == 'strict': # generated from line 265, col 3
+            write(u'''  
+  // STRICT MODE: assert that the start point is the same to within 10% of one delta,
+  //              and that the number of lattice points is the same.
+  double _start;
+  if (_isPrecisionDouble)
+    _start = _inputData[__i]._doublePtr[0];
+  else
+    _start = _inputData[__i]._floatPtr[0];
+  
+  if (abs(_dimMin[__i] - _start) > 0.1*_dimDelta[__i])
+    // _LOG will cause the simulation to exit
+    _LOG(_ERROR_LOG_LEVEL, "Geometry matching mode is strict, so the starting coordinate of each dimension in the field\\n"
+                           "must be the same as in the input grid.\\n"
+                           "The problem is with dimension \'%s\'.\\n", _dimNames[__i]);
+  
+  if (_dimLattice[__i] != _inputLattice[__i])
+    // _LOG will cause the simulation to exit
+    _LOG(_ERROR_LOG_LEVEL, "Geometry matching mode is strict, so the number of lattice points in each dimension of the field\\n"
+                           "must be the same as in the input grid.\\n"
+                           "The problem is with dimension \'%s\'.\\n", _dimNames[__i]);
+''')
+        write(u'''}
+
+long _binaryFileBaseOffset = ftell(_inputFile);
+long _realNumberSize = _isPrecisionDouble ? sizeof(double) : sizeof(float);
+off_t _vectorFieldSize = _unsignedLongSize + _realNumberSize''')
+        _v = ''.join([''.join([u' * _inputLattice[',str(VFFSL(SL,"i",True)),u']']) for i in range(len(VFFSL(SL,"vector.field.dimensions",True)))]) # u"${''.join([c' * _inputLattice[$i]' for i in range(len($vector.field.dimensions))])}" on line 291, col 61
+        if _v is not None: write(_filter(_v, rawExpr=u"${''.join([c' * _inputLattice[$i]' for i in range(len($vector.field.dimensions))])}")) # from line 291, col 61.
+        write(u''';
+
+// Create minimum value variables for dimensions not in fourier space
+''')
+        for dimensionNumber, dimension in enumerate(VFFSL(SL,"vector.field.dimensions",True)): # generated from line 294, col 3
+            write(u'''double _inputfield_min_''')
+            _v = VFFSL(SL,"dimension.name",True) # u'${dimension.name}' on line 295, col 24
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimension.name}')) # from line 295, col 24.
+            write(u''';
+if (_isPrecisionDouble)
+  _inputfield_min_''')
+            _v = VFFSL(SL,"dimension.name",True) # u'${dimension.name}' on line 297, col 19
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimension.name}')) # from line 297, col 19.
+            write(u''' = _inputData[''')
+            _v = VFFSL(SL,"dimensionNumber",True) # u'${dimensionNumber}' on line 297, col 50
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimensionNumber}')) # from line 297, col 50.
+            write(u''']._doublePtr[0];
+else
+  _inputfield_min_''')
+            _v = VFFSL(SL,"dimension.name",True) # u'${dimension.name}' on line 299, col 19
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimension.name}')) # from line 299, col 19.
+            write(u''' = _inputData[''')
+            _v = VFFSL(SL,"dimensionNumber",True) # u'${dimensionNumber}' on line 299, col 50
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimensionNumber}')) # from line 299, col 50.
+            write(u''']._floatPtr[0];
+''')
+        write(u'''
+''')
+        if len(VFFSL(SL,"vector.field.dimensions",True)): # generated from line 302, col 3
+            write(u'''// Create inputfield index variables
+long ''')
+            _v = ', '.join([''.join([u'_inputfield',str(VFN(VFN(VFFSL(SL,"dim",True),"inBasis",False)(VFFSL(SL,"vector.initialBasis",True)),"loopIndex",True))]) for dim in VFFSL(SL,"vector.field.dimensions",True)]) # u"${', '.join([c'_inputfield${dim.inBasis($vector.initialBasis).loopIndex}' for dim in $vector.field.dimensions])}" on line 304, col 6
+            if _v is not None: write(_filter(_v, rawExpr=u"${', '.join([c'_inputfield${dim.inBasis($vector.initialBasis).loopIndex}' for dim in $vector.field.dimensions])}")) # from line 304, col 6.
+            write(u''';
+''')
+        write(u'''
+// Index pointer into the input array (new and old)
+off_t _inputfield_index_pointer, _inputfield_old_index_pointer;
+for (unsigned int _component = 0; _component < ''')
+        _v = VFFSL(SL,"componentNameSizePrefix",True) # u'${componentNameSizePrefix}' on line 309, col 48
+        if _v is not None: write(_filter(_v, rawExpr=u'${componentNameSizePrefix}')) # from line 309, col 48.
+        write(u'''_''')
+        _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 309, col 75
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 309, col 75.
+        write(u"""_ncomponents; _component++) {
+  if (_componentInputIndices[_component] == -1)
+    // This just means that this component doesn't exist in the XSIL file
+    continue;
+  _inputfield_index_pointer = -42; // Just so that we always seek the first time
+  
+""")
+        loopingVectors = VFN(VFFSL(SL,"initialisationCodeBlock.dependencies",True),"copy",False)()
+        loopingVectors.add(VFFSL(SL,"vector",True))
+        write(u'''  
+  ''')
+        _v = VFFSL(SL,"loopOverFieldInBasisWithVectorsAndInnerContent",False)(VFFSL(SL,"initialisationCodeBlock.field",True),
+                                                   VFFSL(SL,"initialisationCodeBlock.basis",True),
+                                                   VFFSL(SL,"loopingVectors",True),
+                                                   VFFSL(SL,"insideDataLoops",True))
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${loopOverFieldInBasisWithVectorsAndInnerContent($initialisationCodeBlock.field,\n                                                   $initialisationCodeBlock.basis,\n                                                   $loopingVectors,\n                                                   $insideDataLoops), autoIndent=True}')) # from line 318, col 3.
+        write(u'''  
+} // end the loop over components
+
+fclose(_inputFile);
+delete [] _dimNames;
+delete [] _componentNames;
+free(_binaryDataFilename);
+delete [] _inputLattice;
+delete [] _componentInputIndices;
+for (int __i = 0; __i < _''')
+        _v = VFFSL(SL,"vector.field.name",True) # u'${vector.field.name}' on line 331, col 26
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.field.name}')) # from line 331, col 26.
+        write(u'''_ndims; __i++) {
+  if (_isPrecisionDouble)
+    delete [] _inputData[__i]._doublePtr;
+  else
+    delete [] _inputData[__i]._floatPtr;
+}
+delete [] _inputData;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideInitialisationLoops(self, codeString, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideInitialisationLoops($codeString) at line 341, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u"""// Stage 2 of initialisation
+
+// The purpose of the following define is to give a (somewhat helpful) compile-time error
+// if the user has attempted to use the propagation dimension variable in the initialisation
+// block of a <vector> element. If they're trying to do this, what they really want is a 
+// <computed_vector> instead.
+#define """)
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 349, col 9
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 349, col 9.
+        write(u''' Dont_use_propagation_dimension_''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 349, col 64
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 349, col 64.
+        write(u'''_in_vector_element_CDATA_block___Use_a_computed_vector_instead
+
+// ********** Initialisation code ***************
+''')
+        _v = VFFSL(SL,"codeString",True) # u'${codeString}' on line 352, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${codeString}')) # from line 352, col 1.
+        write(u'''// **********************************************
+#undef ''')
+        _v = VFFSL(SL,"propagationDimension",True) # u'${propagationDimension}' on line 354, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${propagationDimension}')) # from line 354, col 8.
+        write(u'''
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def insideDataLoops(self, **KWS):
+
+
+
+        ## CHEETAH: generated from @def insideDataLoops at line 358, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        basis = VFFSL(SL,"vector.initialBasis",True)
+        write(u'''// Save the old initialisation pointer, and clear the new one
+_inputfield_old_index_pointer = _inputfield_index_pointer;
+_inputfield_index_pointer = 0;
+
+''')
+        for dimensionNumber, dimension in enumerate(VFFSL(SL,"vector.field.dimensions",True)): # generated from line 365, col 3
+            dimRep = dimension.inBasis(basis)
+            dimName = dimRep.name
+            write(u'''_inputfield''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 368, col 12
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 368, col 12.
+            write(u''' = ''')
+            #  FIXME: Consider moving this to the dimension representations
+            if isinstance(dimRep, UniformDimensionRepresentation): # generated from line 370, col 5
+                write(u'''lround((''')
+                _v = VFFSL(SL,"dimName",True) # u'${dimName}' on line 371, col 9
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimName}')) # from line 371, col 9.
+                write(u''' - _inputfield_min_''')
+                _v = VFFSL(SL,"dimName",True) # u'${dimName}' on line 371, col 38
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimName}')) # from line 371, col 38.
+                write(u''')/_dimDelta[''')
+                _v = VFFSL(SL,"dimensionNumber",True) # u'${dimensionNumber}' on line 371, col 60
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimensionNumber}')) # from line 371, col 60.
+                write(u''']);
+''')
+            elif isinstance(dimRep, SplitUniformDimensionRepresentation): # generated from line 372, col 5
+                write(u'''lround(''')
+                _v = VFFSL(SL,"dimName",True) # u'${dimName}' on line 373, col 8
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimName}')) # from line 373, col 8.
+                write(u'''/_dimDelta[''')
+                _v = VFFSL(SL,"dimensionNumber",True) # u'${dimensionNumber}' on line 373, col 29
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimensionNumber}')) # from line 373, col 29.
+                write(u''']) + (_inputLattice[''')
+                _v = VFFSL(SL,"dimensionNumber",True) # u'${dimensionNumber}' on line 373, col 67
+                if _v is not None: write(_filter(_v, rawExpr=u'${dimensionNumber}')) # from line 373, col 67.
+                write(u''']/2);
+''')
+            else: # generated from line 374, col 5
+                assert False, "XSIL Loading does not support loading data for dimensions that aren't uniformly spaced. The problem is with %s" % dimName
+            write(u'''
+// Check if the input grid has this coordinate value
+if (_inputfield''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 379, col 16
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 379, col 16.
+            write(u''' < 0 || _inputfield''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 379, col 54
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 379, col 54.
+            write(u''' >= _inputLattice[''')
+            _v = VFFSL(SL,"dimensionNumber",True) # u'${dimensionNumber}' on line 379, col 91
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimensionNumber}')) # from line 379, col 91.
+            write(u"""])
+  // The input grid doesn't cover this point.
+  goto _ENDLOOP;
+
+// check that the input coordinate matches up with a field coordinate
+{
+  double _inputfield_""")
+            _v = VFFSL(SL,"dimName",True) # u'${dimName}' on line 385, col 22
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimName}')) # from line 385, col 22.
+            write(u''';
+  if (_isPrecisionDouble)
+    _inputfield_''')
+            _v = VFFSL(SL,"dimName",True) # u'${dimName}' on line 387, col 17
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimName}')) # from line 387, col 17.
+            write(u''' = _inputData[''')
+            _v = VFFSL(SL,"dimensionNumber",True) # u'${dimensionNumber}' on line 387, col 41
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimensionNumber}')) # from line 387, col 41.
+            write(u''']._doublePtr[_inputfield''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 387, col 83
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 387, col 83.
+            write(u'''];
+  else
+    _inputfield_''')
+            _v = VFFSL(SL,"dimName",True) # u'${dimName}' on line 389, col 17
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimName}')) # from line 389, col 17.
+            write(u''' = _inputData[''')
+            _v = VFFSL(SL,"dimensionNumber",True) # u'${dimensionNumber}' on line 389, col 41
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimensionNumber}')) # from line 389, col 41.
+            write(u''']._floatPtr[_inputfield''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 389, col 82
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 389, col 82.
+            write(u'''];
+  
+  if (abs(_inputfield_''')
+            _v = VFFSL(SL,"dimName",True) # u'${dimName}' on line 391, col 23
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimName}')) # from line 391, col 23.
+            write(u''' - ''')
+            _v = VFFSL(SL,"dimName",True) # u'${dimName}' on line 391, col 36
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimName}')) # from line 391, col 36.
+            write(u''') > 0.1*_dimDelta[''')
+            _v = VFFSL(SL,"dimensionNumber",True) # u'${dimensionNumber}' on line 391, col 64
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimensionNumber}')) # from line 391, col 64.
+            write(u'''])
+    // This only happens if your input field grid does not exactly match up with the simulation grid.
+    // _LOG will cause the simulation to exit
+''')
+            dimRepTypeFormat = {'real': 'e', 'long': 'li'}[dimRep.type]
+            write(u'''    _LOG(_ERROR_LOG_LEVEL, "The input field coordinate in the \'''')
+            _v = VFFSL(SL,"dimName",True) # u'$dimName' on line 395, col 64
+            if _v is not None: write(_filter(_v, rawExpr=u'$dimName')) # from line 395, col 64.
+            write(u'''\' dimension does not match up with the field coordinate.\\n"
+                           "''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 396, col 29
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 396, col 29.
+            write(u''': %li, ''')
+            _v = VFFSL(SL,"dimName",True) # u'${dimName}' on line 396, col 55
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimName}')) # from line 396, col 55.
+            write(u''': %''')
+            _v = VFFSL(SL,"dimRepTypeFormat",True) # u'${dimRepTypeFormat}' on line 396, col 68
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRepTypeFormat}')) # from line 396, col 68.
+            write(u''', _inputfield''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 396, col 100
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 396, col 100.
+            write(u''': %li, "
+                           "_inputfield_''')
+            _v = VFFSL(SL,"dimName",True) # u'${dimName}' on line 397, col 41
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimName}')) # from line 397, col 41.
+            write(u''': %e, d''')
+            _v = VFFSL(SL,"dimName",True) # u'${dimName}' on line 397, col 58
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimName}')) # from line 397, col 58.
+            write(u''': %''')
+            _v = VFFSL(SL,"dimRepTypeFormat",True) # u'${dimRepTypeFormat}' on line 397, col 71
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRepTypeFormat}')) # from line 397, col 71.
+            write(u''', diff/Delta: %e\\n",
+                           ''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 398, col 28
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 398, col 28.
+            write(u''', ''')
+            _v = VFFSL(SL,"dimName",True) # u'${dimName}' on line 398, col 49
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimName}')) # from line 398, col 49.
+            write(u''', _inputfield''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 398, col 72
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 398, col 72.
+            write(u''',
+                           _inputfield_''')
+            _v = VFFSL(SL,"dimName",True) # u'${dimName}' on line 399, col 40
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimName}')) # from line 399, col 40.
+            write(u''', d''')
+            _v = VFFSL(SL,"dimName",True) # u'${dimName}' on line 399, col 53
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimName}')) # from line 399, col 53.
+            write(u''', abs(_inputfield_''')
+            _v = VFFSL(SL,"dimName",True) # u'${dimName}' on line 399, col 81
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimName}')) # from line 399, col 81.
+            write(u''' - ''')
+            _v = VFFSL(SL,"dimName",True) # u'${dimName}' on line 399, col 94
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimName}')) # from line 399, col 94.
+            write(u''')/_dimDelta[''')
+            _v = VFFSL(SL,"dimensionNumber",True) # u'$dimensionNumber' on line 399, col 116
+            if _v is not None: write(_filter(_v, rawExpr=u'$dimensionNumber')) # from line 399, col 116.
+            write(u''']);
+}
+
+_inputfield_index_pointer += _inputfield''')
+            _v = VFFSL(SL,"dimRep.loopIndex",True) # u'${dimRep.loopIndex}' on line 402, col 41
+            if _v is not None: write(_filter(_v, rawExpr=u'${dimRep.loopIndex}')) # from line 402, col 41.
+            _v = ''.join([''.join([u' * _inputLattice[',str(VFFSL(SL,"i",True)),u']']) for i in range(dimensionNumber + 1, len(VFFSL(SL,"vector.field.dimensions",True)))]) # u"${''.join([c' * _inputLattice[$i]' for i in range(dimensionNumber + 1, len($vector.field.dimensions))])}" on line 402, col 60
+            if _v is not None: write(_filter(_v, rawExpr=u"${''.join([c' * _inputLattice[$i]' for i in range(dimensionNumber + 1, len($vector.field.dimensions))])}")) # from line 402, col 60.
+            write(u''';
+
+''')
+        write(u'''
+
+double _value;
+if (_inputfield_index_pointer != _inputfield_old_index_pointer + 1)
+  fseeko(_inputFile, _binaryFileBaseOffset + (_componentInputIndices[_component] - _''')
+        _v = VFFSL(SL,"vector.field.name",True) # u'${vector.field.name}' on line 409, col 85
+        if _v is not None: write(_filter(_v, rawExpr=u'${vector.field.name}')) # from line 409, col 85.
+        write(u'''_ndims) * _vectorFieldSize
+                     + _unsignedLongSize + _inputfield_index_pointer * _realNumberSize, SEEK_SET);
+
+if (_isPrecisionDouble) {
+  fread(&_value, sizeof(double), 1, _inputFile);
+  if (!_dataEncodingIsNative)
+    _value = XMDSSwapDouble(_value);
+} else {
+  float _temp;
+  fread(&_temp, sizeof(float), 1, _inputFile);
+  if (!_dataEncodingIsNative)
+    _temp = XMDSSwapFloat(_temp);
+  _value = (double)_temp;
+}
+
+''')
+        if VFFSL(SL,"vector.type",True) == 'real': # generated from line 424, col 3
+            write(u'''_active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 425, col 9
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 425, col 9.
+            write(u'''[_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 425, col 23
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 425, col 23.
+            write(u'''_index_pointer + _component] = (real)_value;
+''')
+        else: # generated from line 426, col 3
+            write(u'''if (_component & 1)
+  _active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 428, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 428, col 11.
+            write(u'''[_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 428, col 25
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 428, col 25.
+            write(u'''_index_pointer + _component/2].Im() = (real)_value;
+else
+  _active_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 430, col 11
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 430, col 11.
+            write(u'''[_''')
+            _v = VFFSL(SL,"vector.id",True) # u'${vector.id}' on line 430, col 25
+            if _v is not None: write(_filter(_v, rawExpr=u'${vector.id}')) # from line 430, col 25.
+            write(u'''_index_pointer + _component/2].Re() = (real)_value;
+''')
+        write(u'''  
+_ENDLOOP:;
+''')
+        # 
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def writeBody(self, **KWS):
+
+
+
+        ## CHEETAH: main method generated for this template
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # VectorInitialisationFromXSIL.tmpl
+        # 
+        # Created by Graham Dennis on 2008-03-14.
+        # 
+        # Copyright (c) 2008-2012, Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+''')
+        # 
+        #   Initialise a vector
+        write(u'''
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    uselib = ['xmds']
+
+    _mainCheetahMethod_for_VectorInitialisationFromXSIL= 'writeBody'
+
+## END CLASS DEFINITION
+
+if not hasattr(VectorInitialisationFromXSIL, '_initCheetahAttributes'):
+    templateAPIClass = getattr(VectorInitialisationFromXSIL, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(VectorInitialisationFromXSIL)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=VectorInitialisationFromXSIL()).run()
+
+
diff --git a/xpdeint/Vectors/VectorInitialisationFromXSIL.tmpl b/xpdeint/Vectors/VectorInitialisationFromXSIL.tmpl
new file mode 100644
index 0000000..0dd126f
--- /dev/null
+++ b/xpdeint/Vectors/VectorInitialisationFromXSIL.tmpl
@@ -0,0 +1,436 @@
+@*
+VectorInitialisationFromXSIL.tmpl
+
+Created by Graham Dennis on 2008-03-14.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+ at extends xpdeint.Vectors.VectorInitialisation
+
+ at from xpdeint.CallOnceGuards import callOnceGuard
+ at from xpdeint.Geometry.UniformDimensionRepresentation import UniformDimensionRepresentation
+ at from xpdeint.Geometry.SplitUniformDimensionRepresentation import SplitUniformDimensionRepresentation
+
+ at attr $uselib = ['xmds']
+
+ at def description: Vector initialisation from an XSIL file
+
+@@callOnceGuard
+ at def static_functionPrototypes
+  @#
+  @super
+  @#
+inline uint32_t XMDSSwapInt32(uint32_t __arg);
+inline uint64_t XMDSSwapInt64(uint64_t __arg);
+inline float XMDSSwapFloat(float __in);
+inline double XMDSSwapDouble(double __in);
+  @#
+ at end def
+
+@@callOnceGuard
+ at def globals
+  @super
+  @#
+// This stuff is here because libxmds requires it.
+// That is because we need the XML parser in order to be able
+// to load XSIL files to initialise fields
+bool debugFlag = false;
+bool xmlDebugFlag =  false;
+  @#
+ at end def
+
+@@callOnceGuard
+ at def static_functionImplementations
+  @#
+  @super
+  @#
+// The following code is imported from CFByteOrder.h, and is used subject to the APSL v2
+// The license is at: http://www.opensource.apple.com/apsl
+
+// These functions have been renamed to avoid conflicts with the actual functions if an XMDS simulation
+// is ever linked against the CoreFoundation framework
+
+// 32-bit byte swapper
+inline uint32_t XMDSSwapInt32(uint32_t __arg)
+{
+#if defined(__i386__) && defined(__GNUC__)
+  __asm__("bswap %0" : "+r" (__arg));
+  return __arg;
+#elif defined(__ppc__) && defined(__GNUC__)
+  uint32_t __result;
+  __asm__("lwbrx %0, 0, %1" : "=r" (__result) : "r" (&__arg), "m" (__arg));
+  return __result;
+#else
+  uint32_t __result;
+  __result = ((__arg & 0xFF) << 24) | ((__arg & 0xFF00) << 8) | ((__arg >> 8) & 0xFF00) | ((__arg >> 24) & 0xFF);
+  return __result;
+#endif
+}
+
+// 64-bit byte-swapper
+inline uint64_t XMDSSwapInt64(uint64_t __arg)
+{
+  union XMDSSwap {
+    uint64_t __sv;
+    uint32_t __ul[2];
+    } __tmp, __result;
+  __tmp.__sv = __arg;
+  __result.__ul[0] = XMDSSwapInt32(__tmp.__ul[1]);
+  __result.__ul[1] = XMDSSwapInt32(__tmp.__ul[0]);
+  return __result.__sv;
+}
+
+inline float XMDSSwapFloat(float __in)
+{
+  union XMDSSwap {
+    float __f;
+    uint32_t __ul;
+  } __tmp;
+  __tmp.__f = __in;
+  __tmp.__ul = XMDSSwapInt32(__tmp.__ul);
+  return __tmp.__f;
+}
+
+inline double XMDSSwapDouble(double __in)
+{
+  union XMDSSwap {
+    double __d;
+    uint64_t __ull;
+  } __tmp;
+  __tmp.__d = __in;
+  __tmp.__ull = XMDSSwapInt64(__tmp.__ull);
+  return __tmp.__d;
+}
+  @#
+ at end def
+
+
+@*
+  Initialise a vector
+*@
+ at def initialiseVector
+  @#
+  @set $initialisationCodeBlock = $codeBlocks['initialisation']
+// XSIL initialisation has three stages.
+// 1. Initialise the vector to zero.
+// 2. Execute any CDATA code if there is any.
+// 3. Read data from the XSIL file.
+
+{
+  // Stage 1 of initialisation
+  bzero(_active_${vector.id}, sizeof(${vector.type}) * ${vector.allocSize});
+  @if $initialisationCodeBlock.codeString.isspace()
+  // There is no stage 2
+  @else
+    @set $vectorOverrides = []
+    @if $vector.integratingComponents
+      @silent vectorOverrides.append($vector)
+    @end if
+  // Stage 2 of initialisation
+  ${initialisationCodeBlock.loop(self.insideInitialisationLoops, vectorOverrides=vectorOverrides), autoIndent=True}@slurp
+  @end if
+}
+
+char **_dimNames  = new char* [_${vector.field.name}_ndims];
+double *_dimDelta = new double[_${vector.field.name}_ndims];
+double *_dimMin   = new double[_${vector.field.name}_ndims];
+unsigned long *_dimLattice = new unsigned long[_${vector.field.name}_ndims];
+
+  @for dimensionNumber, dimension in enumerate($vector.field.dimensions)
+    @set $dimRep = dimension.inBasis($vector.initialBasis)
+_dimNames[$dimensionNumber]   = "${dimRep.name}";
+_dimDelta[$dimensionNumber]   = ${dimRep.stepSize};
+_dimMin[$dimensionNumber]     = ${dimRep.minimum};
+_dimLattice[$dimensionNumber] = ${dimRep.globalLattice};
+
+  @end for
+  @#
+  @set $componentNameSizePrefix = ''
+  @if $vector.type == 'complex'
+    @set $componentNameSizePrefix = '2 * '
+  @end if
+char **_componentNames = new char*[${componentNameSizePrefix}_${vector.id}_ncomponents + 1];
+int *_componentFieldIndices = new int[${componentNameSizePrefix}_${vector.id}_ncomponents];
+
+  @set $componentNameIndex = 0
+  @for component in $vector.components
+_componentNames[$componentNameIndex] = "${component}R";
+    @set $componentNameIndex += 1
+    @#
+    @if $vector.type == 'complex'
+_componentNames[$componentNameIndex] = "${component}I";
+      @set $componentNameIndex += 1
+    @end if
+
+  @end for
+_componentNames[$componentNameIndex] = NULL;
+
+char *_binaryDataFilename;
+int _unsignedLongSize;
+bool _dataEncodingIsNative;
+bool _isPrecisionDouble;
+unsigned long _nDataComponents;
+unsigned long *_inputLattice;
+int *_componentInputIndices;
+
+if (!initialiseFieldFromXSILFile("${filename}", "${momentGroupName}", _${vector.field.name}_ndims, _dimNames, _componentNames, 
+                                 // output variables
+                                 &_binaryDataFilename, &_unsignedLongSize, &_dataEncodingIsNative, &_isPrecisionDouble,
+                                 &_nDataComponents, &_inputLattice, &_componentInputIndices))
+  _LOG(_ERROR_LOG_LEVEL, "Unable to load data from ${filename}\nExiting.\n");
+
+FILE *_inputFile = fopen(_binaryDataFilename, "rb");
+if (_inputFile == NULL)
+  _LOG(_ERROR_LOG_LEVEL, "Unable to open binary input file %s\n", _binaryDataFilename);
+
+typedef union {
+  float *_floatPtr;
+  double *_doublePtr;
+} _GenericRealNumberPtr;
+
+typedef union {
+  unsigned long _ulong;
+  uint32_t _uint32;
+  uint64_t _uint64;
+} _GenericUnsignedLong;
+
+_GenericUnsignedLong _size;
+_GenericRealNumberPtr *_inputData = new _GenericRealNumberPtr[_${vector.field.name}_ndims];
+
+// loop over the dimensions in the binary file
+for (int __i = 0; __i < _${vector.field.name}_ndims; __i++) {
+  uint64_t _sizeValue;
+  switch(_unsignedLongSize) {
+  @for unsignedLongSize, unionElement, typeName, swapFunctionName in [('0', '_ulong',  'unsigned long', 'XMDSSwapInt32'),
+                                                                      ('4', '_uint32', 'uint32_t',      'XMDSSwapInt32'),
+                                                                      ('8', '_uint64', 'uint64_t',      'XMDSSwapInt64')]
+    case ${unsignedLongSize}:
+      fread(&_size.${unionElement}, sizeof(${typeName}), 1, _inputFile);
+      if (_dataEncodingIsNative)
+        _sizeValue = _size.${unionElement};
+      else
+        _sizeValue = ${swapFunctionName}(_size.${unionElement});
+      _unsignedLongSize = sizeof(${typeName});
+      break;
+    
+  @end for
+    default:
+      _LOG(_ERROR_LOG_LEVEL, "Unexpected unsigned long size in input XSIL file. Was expecting '4' or '8', instead got '%i'\n", _unsignedLongSize);
+  }
+  
+  // Read in the data (in either single or double precision)
+  if (_isPrecisionDouble) {
+    _inputData[__i]._doublePtr = new double[_sizeValue];
+    fread(_inputData[__i]._doublePtr, sizeof(double), _sizeValue, _inputFile);
+    if (!_dataEncodingIsNative) {
+      for (unsigned int __j = 0; __j < _sizeValue; __j++)
+        _inputData[__i]._doublePtr[__j] = XMDSSwapDouble(_inputData[__i]._doublePtr[__j]);
+    }
+  } else {
+    _inputData[__i]._floatPtr = new float[_sizeValue];
+    fread(_inputData[__i]._floatPtr, sizeof(float), _sizeValue, _inputFile);
+    if (!_dataEncodingIsNative) {
+      for (unsigned int __j = 0; __j < _sizeValue; __j++)
+        _inputData[__i]._floatPtr[__j] = XMDSSwapFloat(_inputData[__i]._floatPtr[__j]);
+    }
+  }
+  
+  double _difference;
+  if (_isPrecisionDouble)
+    _difference = _inputData[__i]._doublePtr[1] - _inputData[__i]._doublePtr[0];
+  else
+    _difference = _inputData[__i]._floatPtr[1]  - _inputData[__i]._floatPtr[0];
+  
+  // Assert that the deltas are the same to within 1%
+  if (abs(_dimDelta[__i] - _difference) > 0.01 * _dimDelta[__i])
+    // _LOG will cause the simulation to exit
+    _LOG(_ERROR_LOG_LEVEL, "The step size in the '%s' dimension of the input data and the simulation grid do not match.\n"
+                           "The step size in the '%s' dimension was %e, while the input data had a step size of %e.\n",
+                           _dimNames[__i], _dimNames[__i], _dimDelta[__i], _difference);
+  @#
+  @if $geometryMatchingMode == 'strict'
+  
+  // STRICT MODE: assert that the start point is the same to within 10% of one delta,
+  //              and that the number of lattice points is the same.
+  double _start;
+  if (_isPrecisionDouble)
+    _start = _inputData[__i]._doublePtr[0];
+  else
+    _start = _inputData[__i]._floatPtr[0];
+  
+  if (abs(_dimMin[__i] - _start) > 0.1*_dimDelta[__i])
+    // _LOG will cause the simulation to exit
+    _LOG(_ERROR_LOG_LEVEL, "Geometry matching mode is strict, so the starting coordinate of each dimension in the field\n"
+                           "must be the same as in the input grid.\n"
+                           "The problem is with dimension '%s'.\n", _dimNames[__i]);
+  
+  if (_dimLattice[__i] != _inputLattice[__i])
+    // _LOG will cause the simulation to exit
+    _LOG(_ERROR_LOG_LEVEL, "Geometry matching mode is strict, so the number of lattice points in each dimension of the field\n"
+                           "must be the same as in the input grid.\n"
+                           "The problem is with dimension '%s'.\n", _dimNames[__i]);
+  @end if
+}
+
+long _binaryFileBaseOffset = ftell(_inputFile);
+long _realNumberSize = _isPrecisionDouble ? sizeof(double) : sizeof(float);
+off_t _vectorFieldSize = _unsignedLongSize + _realNumberSize${''.join([c' * _inputLattice[$i]' for i in range(len($vector.field.dimensions))])};
+
+// Create minimum value variables for dimensions not in fourier space
+  @for dimensionNumber, dimension in enumerate($vector.field.dimensions)
+double _inputfield_min_${dimension.name};
+if (_isPrecisionDouble)
+  _inputfield_min_${dimension.name} = _inputData[${dimensionNumber}]._doublePtr[0];
+else
+  _inputfield_min_${dimension.name} = _inputData[${dimensionNumber}]._floatPtr[0];
+  @end for
+
+  @if len($vector.field.dimensions)
+// Create inputfield index variables
+long ${', '.join([c'_inputfield${dim.inBasis($vector.initialBasis).loopIndex}' for dim in $vector.field.dimensions])};
+  @end if
+
+// Index pointer into the input array (new and old)
+off_t _inputfield_index_pointer, _inputfield_old_index_pointer;
+for (unsigned int _component = 0; _component < ${componentNameSizePrefix}_${vector.id}_ncomponents; _component++) {
+  if (_componentInputIndices[_component] == -1)
+    // This just means that this component doesn't exist in the XSIL file
+    continue;
+  _inputfield_index_pointer = -42; // Just so that we always seek the first time
+  
+  @set $loopingVectors = $initialisationCodeBlock.dependencies.copy()
+  @silent loopingVectors.add($vector)
+  
+  ${loopOverFieldInBasisWithVectorsAndInnerContent($initialisationCodeBlock.field,
+                                                   $initialisationCodeBlock.basis,
+                                                   $loopingVectors,
+                                                   $insideDataLoops), autoIndent=True}@slurp
+  
+} // end the loop over components
+
+fclose(_inputFile);
+delete [] _dimNames;
+delete [] _componentNames;
+free(_binaryDataFilename);
+delete [] _inputLattice;
+delete [] _componentInputIndices;
+for (int __i = 0; __i < _${vector.field.name}_ndims; __i++) {
+  if (_isPrecisionDouble)
+    delete [] _inputData[__i]._doublePtr;
+  else
+    delete [] _inputData[__i]._floatPtr;
+}
+delete [] _inputData;
+  @#
+ at end def
+
+ at def insideInitialisationLoops($codeString)
+  @#
+// Stage 2 of initialisation
+
+// The purpose of the following define is to give a (somewhat helpful) compile-time error
+// if the user has attempted to use the propagation dimension variable in the initialisation
+// block of a <vector> element. If they're trying to do this, what they really want is a 
+// <computed_vector> instead.
+#define ${propagationDimension} Dont_use_propagation_dimension_${propagationDimension}_in_vector_element_CDATA_block___Use_a_computed_vector_instead
+
+// ********** Initialisation code ***************
+${codeString}@slurp
+// **********************************************
+#undef ${propagationDimension}
+  @#
+ at end def
+
+ at def insideDataLoops
+  @#
+  @set $basis = $vector.initialBasis
+// Save the old initialisation pointer, and clear the new one
+_inputfield_old_index_pointer = _inputfield_index_pointer;
+_inputfield_index_pointer = 0;
+
+  @for dimensionNumber, dimension in enumerate($vector.field.dimensions)
+    @set dimRep = dimension.inBasis(basis)
+    @set dimName = dimRep.name
+_inputfield${dimRep.loopIndex} = @slurp
+    @# FIXME: Consider moving this to the dimension representations
+    @if isinstance(dimRep, UniformDimensionRepresentation)
+lround((${dimName} - _inputfield_min_${dimName})/_dimDelta[${dimensionNumber}]);
+    @elif isinstance(dimRep, SplitUniformDimensionRepresentation)
+lround(${dimName}/_dimDelta[${dimensionNumber}]) + (_inputLattice[${dimensionNumber}]/2);
+    @else
+      @assert False, "XSIL Loading does not support loading data for dimensions that aren't uniformly spaced. The problem is with %s" % dimName
+    @end if
+
+// Check if the input grid has this coordinate value
+if (_inputfield${dimRep.loopIndex} < 0 || _inputfield${dimRep.loopIndex} >= _inputLattice[${dimensionNumber}])
+  // The input grid doesn't cover this point.
+  goto _ENDLOOP;
+
+// check that the input coordinate matches up with a field coordinate
+{
+  double _inputfield_${dimName};
+  if (_isPrecisionDouble)
+    _inputfield_${dimName} = _inputData[${dimensionNumber}]._doublePtr[_inputfield${dimRep.loopIndex}];
+  else
+    _inputfield_${dimName} = _inputData[${dimensionNumber}]._floatPtr[_inputfield${dimRep.loopIndex}];
+  
+  if (abs(_inputfield_${dimName} - ${dimName}) > 0.1*_dimDelta[${dimensionNumber}])
+    // This only happens if your input field grid does not exactly match up with the simulation grid.
+    // _LOG will cause the simulation to exit
+    @set dimRepTypeFormat = {'real': 'e', 'long': 'li'}[dimRep.type]
+    _LOG(_ERROR_LOG_LEVEL, "The input field coordinate in the '$dimName' dimension does not match up with the field coordinate.\n"
+                           "${dimRep.loopIndex}: %li, ${dimName}: %${dimRepTypeFormat}, _inputfield${dimRep.loopIndex}: %li, "
+                           "_inputfield_${dimName}: %e, d${dimName}: %${dimRepTypeFormat}, diff/Delta: %e\n",
+                           ${dimRep.loopIndex}, ${dimName}, _inputfield${dimRep.loopIndex},
+                           _inputfield_${dimName}, d${dimName}, abs(_inputfield_${dimName} - ${dimName})/_dimDelta[$dimensionNumber]);
+}
+
+_inputfield_index_pointer += _inputfield${dimRep.loopIndex}${''.join([c' * _inputLattice[$i]' for i in range(dimensionNumber + 1, len($vector.field.dimensions))])};
+
+  @end for
+
+
+double _value;
+if (_inputfield_index_pointer != _inputfield_old_index_pointer + 1)
+  fseeko(_inputFile, _binaryFileBaseOffset + (_componentInputIndices[_component] - _${vector.field.name}_ndims) * _vectorFieldSize
+                     + _unsignedLongSize + _inputfield_index_pointer * _realNumberSize, SEEK_SET);
+
+if (_isPrecisionDouble) {
+  fread(&_value, sizeof(double), 1, _inputFile);
+  if (!_dataEncodingIsNative)
+    _value = XMDSSwapDouble(_value);
+} else {
+  float _temp;
+  fread(&_temp, sizeof(float), 1, _inputFile);
+  if (!_dataEncodingIsNative)
+    _temp = XMDSSwapFloat(_temp);
+  _value = (double)_temp;
+}
+
+  @if $vector.type == 'real'
+_active_${vector.id}[_${vector.id}_index_pointer + _component] = (real)_value;
+  @else
+if (_component & 1)
+  _active_${vector.id}[_${vector.id}_index_pointer + _component/2].Im() = (real)_value;
+else
+  _active_${vector.id}[_${vector.id}_index_pointer + _component/2].Re() = (real)_value;
+  @end if
+  
+_ENDLOOP:;
+  @#
+ at end def
+
diff --git a/xpdeint/Vectors/_ComputedVector.py b/xpdeint/Vectors/_ComputedVector.py
new file mode 100644
index 0000000..e5a2008
--- /dev/null
+++ b/xpdeint/Vectors/_ComputedVector.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_ComputedVector.py
+
+This contains all the pure-python code for ComputedVector.tmpl
+
+Created by Graham Dennis on 2008-03-12.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Vectors.VectorElement import VectorElement
+
+from xpdeint.Function import Function
+from xpdeint.Utilities import lazy_property
+
+class _ComputedVector (VectorElement):
+  isComputed = True
+  
+  def __init__(self, *args, **KWs):
+    VectorElement.__init__(self, *args, **KWs)
+    
+    # Set default variables
+    
+    # Computed vectors don't need explicit initialisation.  If we're integrating over components, VectorElement will automatically set the vector to zero.
+    self._integratingComponents = False
+    self.initialiser = None
+    
+    evaluateFunctionName = ''.join(['_', self.id, '_evaluate'])
+    evaluateFunction = Function(name = evaluateFunctionName,
+                               args = [],
+                               implementation = self.evaluateFunctionContents)
+    self.functions['evaluate'] = evaluateFunction
+  
+  @property
+  def dependencies(self):
+    return self.codeBlocks['evaluation'].dependencies
+  
+  @property
+  def primaryCodeBlock(self):
+    return self.codeBlocks['evaluation']
+  
+
diff --git a/xpdeint/Vectors/_NoiseVector.py b/xpdeint/Vectors/_NoiseVector.py
new file mode 100755
index 0000000..bf81fa5
--- /dev/null
+++ b/xpdeint/Vectors/_NoiseVector.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_NoiseVector.py
+
+This contains all the pure-python code for NoiseVector.tmpl
+
+Created by Joe Hope on 2009-08-17.
+
+Copyright (c) 2009-2012, Joe Hope
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Vectors.VectorElement import VectorElement
+from xpdeint.Geometry.NonUniformDimensionRepresentation import NonUniformDimensionRepresentation
+
+from xpdeint.Function import Function
+
+class _NoiseVector (VectorElement):
+  isNoise = True
+  
+  def __init__(self, *args, **KWs):
+    localKWs = self.extractLocalKWs(['staticNoise'], KWs)
+    
+    VectorElement.__init__(self, *args, **KWs)
+    
+    self.static = localKWs['staticNoise']
+    
+    args = []
+    if not self.static:
+      args.append(('real', '_step'))
+    else:
+      self.isComputed = True
+    
+    evaluateFunctionName = ''.join(['_', self.id, '_evaluate'])
+    evaluateFunction = Function(
+      name = evaluateFunctionName,
+      args = args,
+      implementation = self.evaluateFunctionContents
+    )
+    self.functions['evaluate'] = evaluateFunction
+    
+    if not self.static:
+      splitFunctionName = ''.join(['_', self.id, '_split'])
+      splitFunction = Function(
+        name = splitFunctionName,
+        args = [('real', '_new_step'), ('real', '_old_step'), (self.type + '*', '_old_array')],
+        implementation = self.splitFunctionContents
+      )
+      self.functions['split'] = splitFunction
+    
+    self.basesNeeded.add(self.initialBasis)
+    
+    self.needsInitialisation = False
+  
+  @property
+  def spatiallyIndependentVolumeElement(self):
+    reps = self.field.inBasis(self.initialBasis)
+    result = []
+    for rep in reps:
+      if isinstance(rep, NonUniformDimensionRepresentation):
+        pass
+      elif rep.type == 'long':
+        pass # Integer step, so nothing interesting
+      elif rep.type == 'real':
+        result.append(rep.stepSize)
+        result.append(rep.volumePrefactor)
+      else:
+        assert False, "Unknown dimension representation type %s" % rep.type
+    if not result:
+      return '1.0'
+    return '(' + ' * '.join(result) + ')'
+  
+  @property
+  def nonUniformDimReps(self):
+    return [rep for rep in self.field.inBasis(self.initialBasis) if isinstance(rep, NonUniformDimensionRepresentation)]
+  
+  def initialiseGlobalSeeds(self):
+    return self.randomVariable.generator.initialiseGlobalSeeds()
+  
+  def initialiseLocalSeeds(self):
+    return self.randomVariable.generator.initialiseLocalSeeds()
diff --git a/xpdeint/Vectors/_VectorElement.py b/xpdeint/Vectors/_VectorElement.py
new file mode 100644
index 0000000..cd686a3
--- /dev/null
+++ b/xpdeint/Vectors/_VectorElement.py
@@ -0,0 +1,203 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_VectorElement.py
+
+This contains all the pure-python code for VectorElement.tmpl
+
+Created by Graham Dennis on 2007-10-17.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.ScriptElement import ScriptElement
+from xpdeint.Geometry.FieldElement import FieldElement
+from xpdeint.Vectors.VectorInitialisation import VectorInitialisation
+
+from xpdeint.Function import Function
+from xpdeint.Utilities import lazy_property
+
+class _VectorElement (ScriptElement):
+  isComputed = False
+  isNoise = False
+  
+  def __init__(self, *args, **KWs):
+    localKWs = self.extractLocalKWs(['name', 'field', 'initialBasis', 'type'], KWs)
+    field = localKWs['field']
+    self.name = localKWs['name']
+    self.field = field
+    if not 'parent' in KWs: KWs['parent'] = field
+    
+    if KWs['parent'] is field:
+      field.managedVectors.add(self)
+    else:
+      field.temporaryVectors.add(self)
+    
+    ScriptElement.__init__(self, *args, **KWs)
+    
+    # Set default variables
+    self.components = []
+    self._needsInitialisation = True
+    self._integratingComponents = False
+    self.type = localKWs['type']
+    self.aliases = set()
+    self.basesNeeded = set()
+    self.initialBasis = None
+    
+    if localKWs.get('initialBasis') is not None:
+      self.initialBasis = self.field.basisForBasis(localKWs['initialBasis'])
+      self.basesNeeded.add(self.initialBasis)
+    
+    # Set default initialisation to be the zero initialisation template
+    self.initialiser = VectorInitialisation(*args, **KWs)
+    self.initialiser.vector = self
+    
+    intialiseFunctionName = ''.join(['_', self.id, '_initialise'])
+    initialiseFunction = Function(name = intialiseFunctionName,
+                                  args = [],
+                                  implementation = self.initialiseFunctionContents,
+                                  description = 'initialisation for ' + self.description(),
+                                  predicate = lambda: self.needsInitialisation)
+    self.functions['initialise'] = initialiseFunction
+    
+    basisTransformFunctionName = ''.join(['_', self.id, '_basis_transform'])
+    basisTransformFunction = Function(name = basisTransformFunctionName,
+                               args = [('ptrdiff_t', 'new_basis')],
+                               implementation = self.basisTransformFunctionContents,
+                               predicate = lambda: self.needsTransforms)
+    self.functions['basisTransform'] = basisTransformFunction
+  
+  @property
+  def dependencies(self):
+    try:
+      return self.initialiser.codeBlocks['initialisation'].dependencies
+    except (AttributeError, KeyError), err:
+      return []
+  
+  @property
+  def needsTransforms(self):
+    return len(self.basesNeeded) > 1
+  
+  def __hash__(self):
+    """
+    Returns a hash of the vector element. This is used to ensure the ordering of vectors in sets remains the same between invocations.
+    """
+    return hash(self.id)
+  
+  @lazy_property
+  def id(self):
+    return ''.join([self.field.name, '_', self.name])
+  
+  @property
+  def children(self):
+    children = super(_VectorElement, self).children
+    if self.initialiser:
+      children.append(self.initialiser)
+    return children
+  
+  @lazy_property
+  def nComponents(self):
+    return len(self.components)
+  
+  def _getNeedsInitialisation(self):
+    return self._needsInitialisation
+  
+  def _setNeedsInitialisation(self, value):
+    self._needsInitialisation = value
+    if not value and self.initialiser:
+      self.initialiser.vector = None
+      self.initialiser.remove()
+      self.initialiser = None
+  
+  # Create a property for the class with the above getter and setter methods
+  needsInitialisation = property(_getNeedsInitialisation, _setNeedsInitialisation)
+  del _getNeedsInitialisation, _setNeedsInitialisation
+  
+  def _getIntegratingComponents(self):
+    return self._integratingComponents
+  
+  def _setIntegratingComponents(self, value):
+    self._integratingComponents = value
+    # The computed vector only needs initialisation to zero if we are integrating.
+    self.needsInitialisation = value
+  
+  integratingComponents = property(_getIntegratingComponents, _setIntegratingComponents)
+  del _getIntegratingComponents, _setIntegratingComponents
+  
+  
+  @lazy_property
+  def allocSize(self):
+    return '_' + self.id + '_alloc_size'
+  
+  def sizeInBasis(self, basis):
+    return self.field.sizeInBasis(basis) + ' * _' + self.id + '_ncomponents'
+  
+  def sizeInBasisInReals(self, basis):
+    if self.type == 'real':
+      return self.sizeInBasis(basis)
+    else:
+      return '2 * ' + self.sizeInBasis(basis)
+  
+  def isTransformableTo(self, basis):
+    return basis in self.transformMap['bases']
+  
+  def remove(self):
+    self.field.managedVectors.discard(self)
+    self.field.temporaryVectors.discard(self)
+    
+    super(_VectorElement, self).remove()
+  
+  @property
+  def primaryCodeBlock(self):
+    try:
+      return self.initialiser.codeBlocks['initialisation']
+    except (AttributeError, KeyError), err:
+      return None
+  
+  def preflight(self):
+    super(_VectorElement, self).preflight()
+    
+    codeBlock = self.primaryCodeBlock
+    if codeBlock:
+      loopingDimensionNames = set([dim.name for dim in self.field.dimensions])
+      for dependency in codeBlock.dependencies:
+        loopingDimensionNames.update([dim.name for dim in dependency.field.dimensions])
+    
+      codeBlock.field = FieldElement.sortedFieldWithDimensionNames(loopingDimensionNames)
+    
+      if codeBlock.dependenciesEntity and codeBlock.dependenciesEntity.xmlElement.hasAttribute('basis'):
+        dependenciesXMLElement = codeBlock.dependenciesEntity.xmlElement
+        codeBlock.basis = \
+          codeBlock.field.basisFromString(
+            dependenciesXMLElement.getAttribute('basis'),
+            xmlElement = dependenciesXMLElement
+          )
+      
+      # Because we have modified the codeBlock's field, we may also need to modify its basis.
+      # We will take any missing elements from the new field's defaultCoordinateBasis
+      codeBlock.basis = codeBlock.field.completedBasisForBasis(codeBlock.basis, codeBlock.field.defaultCoordinateBasis)
+      
+      self.initialBasis = self.field.basisForBasis(codeBlock.basis)
+      self.basesNeeded.add(self.initialBasis)
+    
+      # Our components are constructed by an integral if the looping field doesn't have the same
+      # dimensions as the field to which the computed vector belongs.
+      if not codeBlock.field.isEquivalentToField(self.field):
+        self.integratingComponents = True
+
+
+  
diff --git a/xpdeint/Vectors/_VectorInitialisationFromHDF5.py b/xpdeint/Vectors/_VectorInitialisationFromHDF5.py
new file mode 100644
index 0000000..3af68f5
--- /dev/null
+++ b/xpdeint/Vectors/_VectorInitialisationFromHDF5.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_VectorInitialisationFromHDF5.py
+
+Created by Graham Dennis on 2009-01-31.
+
+Copyright (c) 2009-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.Vectors.VectorInitialisation import VectorInitialisation
+from xpdeint.HDF5 import HDF5
+
+class _VectorInitialisationFromHDF5 (VectorInitialisation, HDF5):
+  def __init__(self, *args, **KWs):
+    VectorInitialisation.__init__(self, *args, **KWs)
+    HDF5.__init__(self, *args, **KWs)
+  
diff --git a/xpdeint/Vectors/__init__.py b/xpdeint/Vectors/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/xpdeint/Version.py b/xpdeint/Version.py
new file mode 100644
index 0000000..69280f8
--- /dev/null
+++ b/xpdeint/Version.py
@@ -0,0 +1,4 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""This is generated by the makefile via the shell program \'version.sh\'"""
+subversionRevisionString ="r2874"
diff --git a/xpdeint/XMDS2Parser.py b/xpdeint/XMDS2Parser.py
new file mode 100755
index 0000000..f84d124
--- /dev/null
+++ b/xpdeint/XMDS2Parser.py
@@ -0,0 +1,2292 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+XMDS2Parser.py
+
+Created by Graham Dennis on 2007-12-29.
+
+Copyright (c) 2007-2012, Graham Dennis and Joe Hope
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+import re
+from xpdeint.ScriptParser import ScriptParser
+from xpdeint.ParserException import ParserException, parserWarning
+from xpdeint.ParsedEntity import ParsedEntity
+from xml.dom import minidom
+from xpdeint import RegularExpressionStrings, Utilities
+
+from xpdeint._ScriptElement import _ScriptElement
+from xpdeint._UserCodeBlock import _UserCodeBlock
+from xpdeint._UserCodeBlock import _UserLoopCodeBlock
+
+from xpdeint.SimulationElement import SimulationElement as SimulationElementTemplate
+from xpdeint.Geometry.GeometryElement import GeometryElement as GeometryElementTemplate
+from xpdeint.Geometry.FieldElement import FieldElement as FieldElementTemplate
+from xpdeint.Geometry._Dimension import _Dimension as Dimension
+from xpdeint.Geometry.UniformDimensionRepresentation import UniformDimensionRepresentation
+from xpdeint.Geometry.NonUniformDimensionRepresentation import NonUniformDimensionRepresentation
+
+from xpdeint.Vectors.VectorElement import VectorElement as VectorElementTemplate
+from xpdeint.Vectors.ComputedVector import ComputedVector as ComputedVectorTemplate
+from xpdeint.Vectors.NoiseVector import NoiseVector as NoiseVectorTemplate
+from xpdeint.Stochastic.RandomVariables.GaussianBoxMuellerRandomVariable import GaussianBoxMuellerRandomVariable
+from xpdeint.Stochastic.RandomVariables.GaussianMKLRandomVariable import GaussianMKLRandomVariable
+from xpdeint.Stochastic.RandomVariables.GaussianSolirteRandomVariable import GaussianSolirteRandomVariable
+from xpdeint.Stochastic.RandomVariables.UniformRandomVariable import UniformRandomVariable
+from xpdeint.Stochastic.RandomVariables.PoissonianRandomVariable import PoissonianRandomVariable
+from xpdeint.Stochastic.Generators.POSIXGenerator import POSIXGenerator
+from xpdeint.Stochastic.Generators.MKLGenerator import MKLGenerator
+from xpdeint.Stochastic.Generators.DSFMTGenerator import DSFMTGenerator
+from xpdeint.Stochastic.Generators.SolirteGenerator import SolirteGenerator
+from xpdeint.Vectors.VectorInitialisation import VectorInitialisation as VectorInitialisationZeroTemplate
+from xpdeint.Vectors.VectorInitialisationFromCDATA import VectorInitialisationFromCDATA as VectorInitialisationFromCDATATemplate
+from xpdeint.Vectors.VectorInitialisationFromXSIL import VectorInitialisationFromXSIL as VectorInitialisationFromXSILTemplate
+from xpdeint.Vectors.VectorInitialisationFromHDF5 import VectorInitialisationFromHDF5 as VectorInitialisationFromHDF5Template
+
+
+from xpdeint.Segments.TopLevelSequenceElement import TopLevelSequenceElement as TopLevelSequenceElementTemplate
+from xpdeint.SimulationDrivers.SimulationDriver import SimulationDriver as SimulationDriverTemplate
+from xpdeint.SimulationDrivers.MultiPathDriver import MultiPathDriver as MultiPathDriverTemplate
+from xpdeint.SimulationDrivers.MPIMultiPathDriver import MPIMultiPathDriver as MPIMultiPathDriverTemplate
+from xpdeint.SimulationDrivers.DistributedMPIDriver import DistributedMPIDriver as DistributedMPIDriverTemplate
+
+from xpdeint.Segments import Integrators
+from xpdeint.Segments.FilterSegment import FilterSegment as FilterSegmentTemplate
+from xpdeint.Segments.BreakpointSegment import BreakpointSegment as BreakpointSegmentTemplate
+from xpdeint.Segments.SequenceSegment import SequenceSegment as SequenceSegmentTemplate
+
+from xpdeint.Operators.OperatorContainer import OperatorContainer as OperatorContainerTemplate
+
+from xpdeint.Operators.DeltaAOperator import DeltaAOperator as DeltaAOperatorTemplate
+from xpdeint.Operators.ConstantIPOperator import ConstantIPOperator as ConstantIPOperatorTemplate
+from xpdeint.Operators.NonConstantIPOperator import NonConstantIPOperator as NonConstantIPOperatorTemplate
+from xpdeint.Operators.ConstantEXOperator import ConstantEXOperator as ConstantEXOperatorTemplate
+from xpdeint.Operators.NonConstantEXOperator import NonConstantEXOperator as NonConstantEXOperatorTemplate
+from xpdeint.Operators.FilterOperator import FilterOperator as FilterOperatorTemplate
+from xpdeint.Operators.CrossPropagationOperator import CrossPropagationOperator as CrossPropagationOperatorTemplate
+from xpdeint.Operators.FunctionsOperator import FunctionsOperator as FunctionsOperatorTemplate
+
+
+from xpdeint.MomentGroupElement import MomentGroupElement as MomentGroupTemplate
+
+from xpdeint import Features
+
+from xpdeint.Features import Transforms
+
+# TODO: Must check that we are never sampling a temporary vector when it doesn't exist.
+# The way to do this is after the template tree has been built to iterate over all elements that can sample
+# and verifying that it isn't sampling a temporary vector that it didn't create (or is a child of the creator).
+
+
+class XMDS2Parser(ScriptParser):
+  @staticmethod
+  def canParseXMLDocument(xmlDocument):
+    simulationElement = xmlDocument.getChildElementByTagName("simulation")
+    if not simulationElement.hasAttribute('xmds-version') or simulationElement.getAttribute('xmds-version') != '2':
+      return False
+    return True
+  
+  def domainPairFromString(self, domainString, element):
+    """
+    Parse a string of the form ``(someNumber1, someNumber2)`` and return the two
+    strings corresponding to the numbers ``someNumber1`` and ``someNumber2`` 
+    """
+    
+    regex = re.compile(RegularExpressionStrings.domainPair)
+    result = regex.match(domainString)
+    if not result:
+      raise ParserException(element, "Could not understand '%(domainString)s' as a domain"
+                                     " of the form ( +/-someNumber, +/-someNumber)" % locals())
+    
+    minimumString = result.group(1)
+    maximumString = result.group(2)
+    
+    return minimumString, maximumString
+  
+  def parseXMLDocument(self, xmlDocument, globalNameSpace, filterClass):
+    self.argumentsToTemplateConstructors = {'searchList':[globalNameSpace], 'filter': filterClass}
+    self.globalNameSpace = globalNameSpace
+    
+    _ScriptElement.argumentsToTemplateConstructors = self.argumentsToTemplateConstructors
+    
+    simulationElement = xmlDocument.getChildElementByTagName("simulation")
+    
+    nameElement = simulationElement.getChildElementByTagName('name', optional=True)
+    if nameElement:
+        self.globalNameSpace['simulationName'] = nameElement.innerText()
+    
+    authorElement = simulationElement.getChildElementByTagName('author', optional=True)
+    if authorElement: author = authorElement.innerText()
+    else: author = ''
+    self.globalNameSpace['author'] = author
+    
+    
+    descriptionElement = simulationElement.getChildElementByTagName('description', optional=True)
+    if descriptionElement: description = descriptionElement.innerText()
+    else: description = ''
+    self.globalNameSpace['simulationDescription'] = description
+    
+    self.simulation = _ScriptElement.simulation
+    
+    simulationElementTemplate = SimulationElementTemplate(parent = self.simulation, **self.argumentsToTemplateConstructors)
+    
+    self.parseFeatures(simulationElement)
+    
+    self.parseDriverElement(simulationElement)
+    
+    self.parseGeometryElement(simulationElement)
+    
+    self.parseVectorElements(simulationElement)
+    
+    self.parseComputedVectorElements(simulationElement, None)
+    
+    self.parseNoiseVectorElements(simulationElement, None)
+    
+    self.parseTopLevelSequenceElement(simulationElement)
+    
+    self.parseOutputElement(simulationElement)
+    
+  
+  def parseDependencies(self, element, optional = False):
+    dependenciesElement = element.getChildElementByTagName('dependencies', optional)
+    dependencyVectorNames = []
+    if dependenciesElement:
+      dependencyVectorNames = Utilities.symbolsInString(dependenciesElement.innerText(), xmlElement = element)
+      return ParsedEntity(dependenciesElement, dependencyVectorNames)
+    else:
+      return None
+    
+  
+  def parseDriverElement(self, simulationElement):
+    driverClass = SimulationDriverTemplate
+    
+    driverAttributeDictionary = dict()
+    
+    driverElement = simulationElement.getChildElementByTagName('driver', optional=True)
+    if driverElement:
+      
+      driverName = driverElement.getAttribute('name').strip().lower()
+      
+      class UnknownDriverException(Exception):
+        pass
+
+      # Check to see if run-time validation has been selected
+      runTimeValidationSelected = False
+      validationFeature = None
+      if 'Validation' in self.globalNameSpace['features']:
+        validationFeature = self.globalNameSpace['features']['Validation']
+        if validationFeature.runValidationChecks == True:
+          runTimeValidationSelected = True
+        
+      try:
+        if 'multi-path' in driverName:
+          if driverName == 'multi-path':
+            driverClass = MultiPathDriverTemplate
+          elif driverName == 'mpi-multi-path':
+            driverClass = MPIMultiPathDriverTemplate
+          else:
+            raise UnknownDriverException()
+          
+          if not driverElement.hasAttribute('paths'):
+            raise ParserException(driverElement, "Missing 'paths' attribute for multi-path driver.")
+
+          pathCountString = driverElement.getAttribute('paths')
+          try:
+            pathCount = RegularExpressionStrings.integerInString(pathCountString)
+          except ValueError, err:
+            # If we didn't parse it, then we might be using the run-time validation feature
+            if runTimeValidationSelected:
+              validationFeature.validationChecks.append("""
+              if (%(pathCountString)s <= 0)
+                _LOG(_ERROR_LOG_LEVEL, "ERROR: The number of paths '%(pathCountString)s' must be greater than zero.\\n"
+                                       "pathCount = %%li\\n", (long)%(pathCountString)s);
+              """ % locals())
+              pathCount = pathCountString
+            else:
+              raise ParserException(driverElement, "Could not understand path count '%(pathCountString)s' as an integer. "
+                                                   """Use feature <validation kind="run-time"/> to allow arbitrary code.""")
+          driverAttributeDictionary['pathCount'] = pathCount
+        elif driverName == 'none':
+          pass
+        elif driverName == 'distributed-mpi':
+          driverClass = DistributedMPIDriverTemplate
+        else:
+          raise UnknownDriverException()
+      except UnknownDriverException, err:
+        raise ParserException(driverElement, "Unknown driver type '%(driverName)s'. "
+                                             "The options are 'none' (default), 'multi-path', 'mpi-multi-path' or 'distributed-mpi'." % locals())
+      
+      if driverClass == MultiPathDriverTemplate:
+        kindString = None
+        if driverElement.hasAttribute('kind'):
+          kindString = driverElement.getAttribute('kind').strip().lower()
+        if kindString in (None, 'single'):
+          pass
+        elif kindString == 'mpi':
+          driverClass = MPIMultiPathDriverTemplate
+        else:
+          raise ParserException(driverElement,
+                                "Unknown multi-path kind '%(kindString)s'. "
+                                "The options are 'single' (default), or 'mpi'." % locals())
+    
+    simulationDriver = driverClass(parent = self.simulation, xmlElement = driverElement,
+                                   **self.argumentsToTemplateConstructors)
+    self.applyAttributeDictionaryToObject(driverAttributeDictionary, simulationDriver)
+    return simulationDriver
+  
+  
+  def parseFeatures(self, simulationElement):
+    featuresParentElement = simulationElement.getChildElementByTagName('features', optional=True)
+    if not featuresParentElement:
+      featuresParentElement = simulationElement
+    
+    transformMultiplexer = Transforms.TransformMultiplexer.TransformMultiplexer(parent = self.simulation,
+                                                                                **self.argumentsToTemplateConstructors)
+    
+    def parseSimpleFeature(tagName, featureClass):
+      featureElement = featuresParentElement.getChildElementByTagName(tagName, optional=True)
+      feature = None
+      if featureElement:
+        if len(featureElement.innerText()) == 0 or featureElement.innerText().lower() == 'yes':
+          feature = featureClass(parent = self.simulation, xmlElement = featureElement,
+                                 **self.argumentsToTemplateConstructors)
+      return featureElement, feature
+    
+    
+    parseSimpleFeature('auto_vectorise', Features.AutoVectorise.AutoVectorise)
+    parseSimpleFeature('benchmark', Features.Benchmark.Benchmark)
+    parseSimpleFeature('error_check', Features.ErrorCheck.ErrorCheck)
+    parseSimpleFeature('bing', Features.Bing.Bing)
+    parseSimpleFeature('openmp', Features.OpenMP.OpenMP)
+    parseSimpleFeature('halt_non_finite', Features.HaltNonFinite.HaltNonFinite)
+    parseSimpleFeature('diagnostics', Features.Diagnostics.Diagnostics)
+    
+    openmpElement = featuresParentElement.getChildElementByTagName('openmp', optional=True)
+    if openmpElement:
+      threadCount = None
+      if openmpElement.hasAttribute('threads'):
+        try:
+          threadCountString = openmpElement.getAttribute('threads')
+          threadCount = int(threadCountString)
+        except ValueError, err:
+          raise ParserException(openmpElement, "Cannot understand '%(threadCountString)s' as an "
+                                               "integer number of threads." % locals())
+        
+        if threadCount <= 0:
+          raise ParserException(openmpElement, "The number of threads must be greater than 0.")
+      openmpFeature = Features.OpenMP.OpenMP(parent = self.simulation,
+                                             xmlElement = openmpElement,
+                                             **self.argumentsToTemplateConstructors)
+      openmpFeature.threadCount = threadCount
+    
+    precisionElement = featuresParentElement.getChildElementByTagName('precision', optional=True)
+    if precisionElement:
+      content = precisionElement.innerText().strip().lower()
+      if content:
+        if not content in ['single', 'double']:
+          raise ParserException(
+            precisionElement,
+            "Unrecognised precision '%s'. Options are 'single' or 'double' (default)." % content
+          )
+        self.globalNameSpace['precision'] = content
+    
+    chunkedOutputElement = featuresParentElement.getChildElementByTagName('chunked_output', optional=True)
+    if chunkedOutputElement:
+      sizeString = chunkedOutputElement.getAttribute('size').strip().lower()
+      match = re.match(r'(\d+)(b|kb|mb|gb|tb)', sizeString)
+      if not match:
+        raise ParserException(
+          chunkedOutputElement,
+          "The 'size' attribute of the 'chunked_output' tag must be an integer followed by one of the suffixes "
+          "'B' (bytes), 'kB' (kilobytes), 'MB' (megabytes), 'GB' (gigabytes) or 'TB' (terabytes)."
+        )
+      chunkSize = int(match.group(1))
+      chunkSize *= 1024 ** {'b': 0, 'kb': 1, 'mb': 2, 'gb': 3, 'tb': 4}[match.group(2)]
+      chunkedOutputFeature = Features.ChunkedOutput.ChunkedOutput(
+        parent = self.simulation,
+        chunkSize = chunkSize,
+        xmlElement = chunkedOutputElement,
+        **self.argumentsToTemplateConstructors
+      )
+
+    validationFeatureElement = featuresParentElement.getChildElementByTagName('validation', optional=True)
+    if validationFeatureElement and validationFeatureElement.hasAttribute('kind'):
+      kindString = validationFeatureElement.getAttribute('kind').strip().lower()
+      
+      if kindString in ('run-time', 'none'):
+        validationFeature = Features.Validation.Validation(
+          parent = self.simulation,
+          runValidationChecks = kindString == 'run-time',
+          xmlElement = validationFeatureElement,
+          **self.argumentsToTemplateConstructors
+        )
+      elif kindString == 'compile-time':
+        pass
+      else:
+        raise ParserException(validationFeatureElement, "The 'kind' attribute of the <validation> tag must be one of "
+                                                        "'compile-time', 'run-time' or 'none'.")
+      
+    # We want the Globals element to be parsed before the Arguments element so that the globals for globals
+    # appear in the generated source before the globals for Arguments.  This prevents anyone inadvertently using
+    # the arguments in the initialisation of the globals.  To achieve this, people should put code in the CDATA
+    # block for arguments.
+    
+    globalsElement = featuresParentElement.getChildElementByTagName('globals', optional=True)
+    if globalsElement:
+      globalsTemplate = Features.Globals.Globals(parent = self.simulation,
+                                                 **self.argumentsToTemplateConstructors)
+      globalsTemplate.codeBlocks['globalsCode'] = _UserCodeBlock(
+        parent = globalsTemplate, xmlElement = globalsElement,
+        **self.argumentsToTemplateConstructors
+      )
+
+    argumentsFeatureElement = featuresParentElement.getChildElementByTagName('arguments', optional=True)
+    
+    if argumentsFeatureElement:
+      argumentsFeature = Features.Arguments.Arguments(
+        parent = self.simulation, xmlElement = argumentsFeatureElement,
+        **self.argumentsToTemplateConstructors
+      )
+      
+      argumentElements = argumentsFeatureElement.getChildElementsByTagName('argument', optional=True)
+      
+      if argumentsFeatureElement.getAttribute('append_args_to_output_filename') == "yes":
+        argumentsFeature.appendArgsToOutputFilename = True
+      else:
+        argumentsFeature.appendArgsToOutputFilename = False
+
+      argumentsFeature.codeBlocks['postArgumentProcessing'] = _UserCodeBlock(
+        xmlElement = argumentsFeatureElement, parent = argumentsFeature,
+        **self.argumentsToTemplateConstructors
+      )
+      
+      argumentList = []
+      # Note that "h" is already taken as the "help" option 
+      shortOptionNames = set(['h'])
+      
+      for argumentElement in argumentElements:
+        name = argumentElement.getAttribute('name').strip()
+        type = argumentElement.getAttribute('type').strip().lower()
+        defaultValue = argumentElement.getAttribute('default_value').strip()
+        
+        # Determine the short name (i.e. single character) of the full option name
+        shortName = ""
+        additionalAllowedCharacters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
+        for character in name+additionalAllowedCharacters:
+          if character not in shortOptionNames:
+            shortName = character
+            shortOptionNames.add(character)
+            break
+        
+        if shortName == "":
+          raise ParserException(argumentElement, "Unable to find a short (single character) name for command line option")        
+        
+        if not type in ('int', 'integer', 'long', 'real', 'string'):
+          raise ParserException(argumentElement, "Invalid type name '%(type)s'. "
+                                                 "Valid options are 'integer', 'int', 'long', 'real' or 'string'." % locals())
+        
+        argumentAttributeDictionary = dict()
+        
+        argumentAttributeDictionary['name'] = name
+        argumentAttributeDictionary['shortName'] = shortName
+        argumentAttributeDictionary['type'] = type
+        argumentAttributeDictionary['defaultValue'] = defaultValue
+        
+        argumentList.append(argumentAttributeDictionary)
+      
+      argumentsFeature.argumentList = argumentList
+    
+    
+
+    
+    cflagsElement = featuresParentElement.getChildElementByTagName('cflags', optional=True)
+    if cflagsElement:
+      cflagsTemplate = Features.CFlags.CFlags(parent = self.simulation,
+                                              **self.argumentsToTemplateConstructors)
+      cflagsTemplate.cflagsString = cflagsElement.innerText().strip()
+    
+    fftwElement = featuresParentElement.getChildElementByTagName('fftw', optional=True)
+    
+    if fftwElement:
+      fourierTransformClass = Transforms.FourierTransformFFTW3.FourierTransformFFTW3
+      fftAttributeDictionary = dict()
+      
+      threadCount = 1
+      if fftwElement.hasAttribute('threads'):
+        try:
+          threadCountString = fftwElement.getAttribute('threads')
+          threadCount = int(threadCountString)
+        except ValueError, err:
+          raise ParserException(fftwElement, "Cannot understand '%(threadCountString)s' as an "
+                                             "integer number of threads." % locals())
+        
+        if threadCount <= 0:
+          raise ParserException(fftwElement, "The number of threads must be greater than 0.")
+      
+      planType = None
+      if not fftwElement.hasAttribute('plan'):
+        pass
+      else:
+        planType = {
+          'estimate': 'FFTW_ESTIMATE',
+          'measure': 'FFTW_MEASURE',
+          'patient': 'FFTW_PATIENT',
+          'exhaustive': 'FFTW_EXHAUSTIVE'
+        }.get(fftwElement.getAttribute('plan').strip().lower())
+        if not planType:
+          raise ParserException(fftwElement, "The plan attribute must be one of 'estimate', 'measure', 'patient' or 'exhaustive'.")
+      
+      if planType:
+        fftAttributeDictionary['planType'] = planType
+      
+      
+      if 'OpenMP' in self.globalNameSpace['features'] or threadCount > 1:
+        if fourierTransformClass == Transforms.FourierTransformFFTW3.FourierTransformFFTW3:
+          fourierTransformClass = Transforms.FourierTransformFFTW3Threads.FourierTransformFFTW3Threads
+          if 'OpenMP' in self.globalNameSpace['features']:
+            fourierTransformClass.fftwSuffix = 'omp'
+            threadCount = 'omp_get_max_threads()'
+        elif fourierTransformClass == Transforms._NoTransform._NoTransform:
+          raise ParserException(fftwElement, "Can't use threads with no fourier transforms.")
+        else:
+          # This shouldn't be reached because the fourierTransformClass should be one of the above options
+          raise ParserException(fftwElement, "Internal consistency error.")
+        
+        fftAttributeDictionary['threadCount'] = threadCount
+      
+      fourierTransform = fourierTransformClass(parent = self.simulation, **self.argumentsToTemplateConstructors)
+      
+      self.applyAttributeDictionaryToObject(fftAttributeDictionary, fourierTransform)
+  
+  def parseFeatureAttributes(self, someElement, someTemplate):
+    self.parseMaxIterationsAttribute(someElement, someTemplate)
+  
+  def parseMaxIterationsAttribute(self, someElement, someTemplate):
+    if not isinstance(someTemplate, Integrators.AdaptiveStep.AdaptiveStep):
+      return
+    
+    if not someElement.hasAttribute('max_iterations'):
+      return
+    
+    maxIterationsString = someElement.getAttribute('max_iterations').strip()
+    try:
+      maxIterations = int(maxIterationsString)
+      if not maxIterations >= 1:
+        raise ParserException(someElement, "max_iterations value must be a positive integer.")
+    except ValueError, err:
+      raise ParserException(someElement, "Unable to understand '%(maxIterationsString)s' as an integer for 'max_iterations'.")
+    
+    if not 'MaxIterations' in self.globalNameSpace['features']:
+      maxIterationsFeature = Features.MaxIterations.MaxIterations(**self.argumentsToTemplateConstructors)
+      maxIterationsFeature.maxIterationsDict = {}
+    else:
+      maxIterationsFeature = self.globalNameSpace['features']['MaxIterations']
+    
+    maxIterationsFeature.maxIterationsDict[someTemplate] = maxIterations
+  
+  def parseGeometryElement(self, simulationElement):
+    geometryElement = simulationElement.getChildElementByTagName('geometry')
+    
+    geometryTemplate = GeometryElementTemplate(parent = self.simulation, **self.argumentsToTemplateConstructors)
+    
+    ## First grab the propagation dimension name
+    
+    propagationDimensionElement = geometryElement.getChildElementByTagName('propagation_dimension')
+    if len(propagationDimensionElement.innerText()) == 0:
+      raise ParserException(propagationDimensionElement, "The propagation_dimension element must not be empty")
+    
+    propagationDimensionName = propagationDimensionElement.innerText()
+    self.globalNameSpace['globalPropagationDimension'] = propagationDimensionName
+    self.globalNameSpace['symbolNames'].add(propagationDimensionName)
+    
+    noTransform = self.globalNameSpace['features']['TransformMultiplexer'].transformWithName('none')
+    
+    propagationDimension = Dimension(name = propagationDimensionName,
+                                     transverse = False,
+                                     transform = noTransform,
+                                     parent = geometryTemplate,
+                                     **self.argumentsToTemplateConstructors)
+    
+    propagationDimension.addRepresentation(
+      NonUniformDimensionRepresentation(
+        name = propagationDimensionName,
+        type = 'real',
+        parent = propagationDimension,
+        xmlElement = propagationDimensionElement,
+        tag = NonUniformDimensionRepresentation.tagForName('coordinate'),
+        **self.argumentsToTemplateConstructors
+      )
+    )
+    
+    geometryTemplate.dimensions = [propagationDimension]
+    
+    ## Now grab and parse all of the transverse dimensions
+    
+    geometryTemplate.primaryTransverseDimensionNames = []
+    
+    transverseDimensionsElement = geometryElement.getChildElementByTagName('transverse_dimensions', optional=True)
+    if transverseDimensionsElement:
+      dimensionElements = transverseDimensionsElement.getChildElementsByTagName('dimension', optional=True)
+      
+      aliasDimensions = []
+      
+      for dimensionElement in dimensionElements:
+        def parseAttribute(attrName):
+          if not dimensionElement.hasAttribute(attrName) or len(dimensionElement.getAttribute(attrName)) == 0:
+            raise ParserException(dimensionElement, "Each dimension element must have a non-empty"
+                                                    " '%(attrName)s' attribute" % locals())
+          
+          return dimensionElement.getAttribute(attrName).strip()
+        
+        
+        ## Grab the name of the dimension
+        dimensionName = parseAttribute('name')
+        
+        try:
+          dimensionName = Utilities.symbolInString(dimensionName, xmlElement = dimensionElement)
+        except ValueError, err:
+          raise ParserException(dimensionElement, "'%(dimensionName)s is not a valid name for a dimension.\n"
+                                                  "It must not start with a number, and can only contain "
+                                                  "alphanumeric characters and underscores." % locals())
+        ## Make sure the name is unique
+        if dimensionName in self.globalNameSpace['symbolNames']:
+          raise ParserException(dimensionElement, "Dimension name %(dimensionName)s conflicts with "
+                                                  "previously-defined symbol of the same name." % locals())
+        
+        geometryTemplate.primaryTransverseDimensionNames.append(dimensionName)
+        
+        ## Now make sure no-one else steals it
+        self.globalNameSpace['symbolNames'].add(dimensionName)
+        
+        # Work out the type of the dimension
+        dimensionType = 'real'
+        if dimensionElement.hasAttribute('type') and dimensionElement.getAttribute('type'):
+          dimensionType = dimensionElement.getAttribute('type').strip().lower()
+          if dimensionType == 'real':
+            pass
+          elif dimensionType in ('long', 'int', 'integer'):
+            dimensionType = 'long'
+          else:
+            raise ParserException(dimensionElement, "'%(dimensionType)s' is not a valid type for a dimension.\n"
+                                                    "It must be one of 'real' (default) or "
+                                                    "'integer'/'int'/'long' (synonyms)." % locals())
+        
+        
+        transform = None
+        transformName = 'none'
+        transformMultiplexer = self.globalNameSpace['features']['TransformMultiplexer']
+        
+        if dimensionType == 'real' and dimensionElement.hasAttribute('transform'):
+          transformName = dimensionElement.getAttribute('transform').strip()
+          transform = transformMultiplexer.transformWithName(transformName.lower())
+          if not transform:
+            raise ParserException(dimensionElement, "Unknown transform of type '%(transformName)s'." % locals())
+        
+        if dimensionType == 'long':
+          transform = transformMultiplexer.transformWithName('none')
+        
+        if not transform:
+          # default to 'dft'
+          # FIXME: This is debatable. Perhaps a default of 'none' is more sensible.
+          transformName = 'dft'
+          transform = transformMultiplexer.transformWithName('dft')
+
+
+        if dimensionElement.hasAttribute('domain'):
+          ## Grab the domain strings
+          
+          domainString = parseAttribute('domain')
+          
+          ## Returns two strings for the end points
+          minimumString, maximumString = self.domainPairFromString(domainString, dimensionElement)
+        elif dimensionElement.hasAttribute('length_scale'):
+          minimumString = '0'
+          maximumString = dimensionElement.getAttribute('length_scale').strip()
+        else:
+          raise ParserException(dimensionElement, "Each dimension element must have a non-empty 'domain' attribute\n"
+                                                  "(or in the case of the 'hermite-gauss' transform a 'length_scale' attribute).")
+
+        # Check to see if run-time validation has been selected
+        runTimeValidationSelected = False
+        validationFeature = None
+        if 'Validation' in self.globalNameSpace['features']:
+          validationFeature = self.globalNameSpace['features']['Validation']
+          if validationFeature.runValidationChecks == True:
+            runTimeValidationSelected = True
+        
+        if dimensionType == 'real':
+          domainPairType = float
+        else:
+          domainPairType = int
+        ## Now we try make some sense of them
+        try:
+          minimumValue = domainPairType(minimumString)
+          maximumValue = domainPairType(maximumString)
+        except ValueError, err: # If not floats then we check the validation feature.
+          if runTimeValidationSelected:
+            validationFeature.validationChecks.append("""
+            if (%(minimumString)s >= %(maximumString)s)
+              _LOG(_ERROR_LOG_LEVEL, "ERROR: The end point of the dimension '%(maximumString)s' must be "
+                                     "greater than the start point.\\n"
+                                     "Start = %%e, End = %%e\\n", (real)%(minimumString)s, (real)%(maximumString)s);""" % locals())
+          else:
+            raise ParserException(dimensionElement, """Could not understand domain (%(minimumString)s, %(maximumString)s) as numbers.
+Use feature <validation kind="run-time"/> to allow for arbitrary code.""" % locals() )
+        else: # In this case we were given numbers and should check that they in the correct order here
+          if minimumValue >= maximumValue:
+            raise ParserException(dimensionElement, "The end point of the dimension, '%(maximumString)s', must be "
+                                                    "greater than the start point, '%(minimumString)s'." % locals())
+        
+
+        if dimensionType == 'real' or dimensionElement.hasAttribute('lattice'):
+          ## Grab the number of lattice points and make sure it's a positive integer
+          latticeString = parseAttribute('lattice')
+          if not latticeString.isdigit():
+            # This might be okay if the user has asked for run-time validation, so that
+            # the lattice value is actually a variable to be specified later.
+
+            # Real dimension, lattice attribute isn't a number, so is run-time validation on?
+            if runTimeValidationSelected == False:
+              # Not on, so barf
+              raise ParserException(dimensionElement, "Could not understand lattice value "
+                                                    "'%(latticeString)s' as a positive integer. "
+                                                    "If you want to specify the lattice value at runtime you need "
+                                                    "to add <validation kind=\"run-time\"/> to your features block."  % locals())
+
+            # For now only allow run-time lattice definition for 'none', 'dft', 'dct' and 'dst' transforms.
+            # This is because lattice points for Hermite-Gauss and Bessel transforms are not uniformly spaced,
+            # and currently the spacing is worked out in _MMT.py at parse time, which requires the number
+            # of lattice points to be known.            
+            if transformName not in ['dft', 'dct', 'dst', 'none']:
+              raise ParserException(dimensionElement, "Defining the lattice size at run time is currently only "
+                                                      "implemented for transform types 'dft', 'dct', 'dst' and 'none'. "
+                                                      "You are using transform type '%(transformName)s'. Aborting." % locals())
+
+            # All right, we have real dimension, run-time validation is on, an acceptable tranform is in
+            # use, so let's allow a non-numeric lattice value
+            lattice = latticeString
+          else:
+            # The lattice string a digit, so everything is cool
+            lattice = int(latticeString)
+            if dimensionType == 'long' and (not runTimeValidationSelected) and (maximumValue - minimumValue + 1) != lattice:
+              raise ParserException(dimensionElement, "The lattice value of '%(latticeString)s' doesn't match with the domain "
+                                                    "'%(domainString)s'." % locals())
+          
+          # If we are validating at run time, an explicit lattice has been provided, and we are a long dimension then we need to check that the lattice
+          # agrees with the minimum / maximum values of the dimension.
+          if runTimeValidationSelected and dimensionType == 'long':
+            validationFeature.validationChecks.append("""
+            if ((%(latticeString)s) != ((%(maximumString)s) - (%(minimumString)s) + 1))
+              _LOG(_ERROR_LOG_LEVEL, "ERROR: The lattice value of '%(latticeString)s'=%%li doesn't match with the domain "
+                                     "'%(minimumString)s'=%%li to '%(maximumString)s'=%%li (%%li lattice points).\\n",
+                                     long(%(latticeString)s), long(%(minimumString)s), long(%(maximumString)s), long((%(maximumString)s) - (%(minimumString)s)+1));
+            """ % locals())
+        else:
+          # Only for 'long' dimensions
+          if not runTimeValidationSelected:
+            lattice = maximumValue - minimumValue + 1
+          else:
+            lattice = "((%(maximumString)s) - (%(minimumString)s) + 1)" % locals()
+        
+        
+        aliasNames = []
+        if dimensionElement.hasAttribute('aliases'):
+          aliasNames.extend(Utilities.symbolsInString(dimensionElement.getAttribute('aliases'), xmlElement = dimensionElement))
+          for aliasName in aliasNames:
+            if aliasName in self.globalNameSpace['symbolNames']:
+              raise ParserException(dimensionElement, "Cannot use '%(aliasName)s' as an alias name for dimension '%(dimensionName)s\n"
+                                                      "This name is already in use." % locals())
+            self.globalNameSpace['symbolNames'].add(aliasName)
+        
+        aliasNames.insert(0, dimensionName)
+        
+        if dimensionElement.hasAttribute('spectral_lattice'):
+          spectralLattice = dimensionElement.getAttribute('spectral_lattice').strip()
+          if not spectralLattice.isdigit():
+            raise ParserException(dimensionElement, "Could not understand spectral_lattice value of '%(spectralLattice)s' as a positive integer." % locals())
+          spectralLattice = int(spectralLattice)
+          if spectralLattice > lattice:
+            raise ParserException(dimensionElement, "The size of the spectral lattice must be equal or less than the size of the spatial lattice.")
+        else:
+          spectralLattice = lattice
+        
+        volumePrefactor = None
+        if dimensionElement.hasAttribute('volume_prefactor'):
+            volumePrefactor = dimensionElement.getAttribute('volume_prefactor').strip()
+        
+        aliasNameSet = set(aliasNames)
+        
+        for aliasName in aliasNames:
+          dim = transform.newDimension(name = aliasName, lattice = lattice,
+                                       spectralLattice = spectralLattice, type = dimensionType,
+                                       minimum = minimumString, maximum = maximumString,
+                                       parent = geometryTemplate, transformName = transformName,
+                                       aliases = aliasNameSet, volumePrefactor = volumePrefactor,
+                                       xmlElement = dimensionElement)
+          if aliasName == dimensionName:
+            geometryTemplate.dimensions.append(dim)
+          else:
+            aliasDimensions.append(dim)
+      
+      # Alias dimensions come after normal dimensions so that we don't end up with a distributed-mpi set up over the first dimension and its alias
+      geometryTemplate.dimensions.extend(aliasDimensions)
+    
+    driver = self.globalNameSpace['features']['Driver']
+    if isinstance(driver, DistributedMPIDriverTemplate):
+      transverseDimensions = geometryTemplate.dimensions[1:]
+      mpiTransform = transverseDimensions[0].transform
+      if not mpiTransform.isMPICapable:
+        mpiTransform = transformMultiplexer.transformWithName('mpi')
+      mpiTransform.initialiseForMPIWithDimensions(transverseDimensions)
+    
+    return geometryTemplate
+  
+  def parseVectorElements(self, parentElement):
+    vectorElements = parentElement.getChildElementsByTagName('vector', optional=True)
+    for vectorElement in vectorElements:
+      vectorTemplate = self.parseVectorElement(vectorElement)
+  
+  def parseVectorElement(self, vectorElement):
+    if not vectorElement.hasAttribute('dimensions'):
+      dimensionNames = self.globalNameSpace['geometry'].primaryTransverseDimensionNames
+    elif len(vectorElement.getAttribute('dimensions').strip()) == 0:
+      # No dimensions
+      dimensionNames = []
+    else:
+      dimensionsString = vectorElement.getAttribute('dimensions').strip()
+      dimensionNames = Utilities.symbolsInString(dimensionsString, xmlElement = vectorElement)
+      if not dimensionNames:
+        raise ParserException(vectorElement, "Cannot understand '%(dimensionsString)s' as a "
+                                            "list of dimensions" % locals())
+        
+    
+    fieldTemplate = FieldElementTemplate.sortedFieldWithDimensionNames(dimensionNames, xmlElement = vectorElement)
+    
+    if not vectorElement.hasAttribute('name') or len(vectorElement.getAttribute('name')) == 0:
+      raise ParserException(vectorElement, "Each vector element must have a non-empty 'name' attribute")
+    
+    vectorName = vectorElement.getAttribute('name')
+    if not vectorName == Utilities.symbolInString(vectorName, xmlElement = vectorElement):
+      raise ParserException(vectorElement, "'%(vectorName)s' is not a valid name for a vector.\n"
+                                           "The name must not start with a number and can only contain letters, numbers and underscores." % locals())
+    
+    # Check that this vector name is unique
+    for field in self.globalNameSpace['fields']:
+      if len(filter(lambda x: x.name == vectorName, field.vectors)) > 0:
+        raise ParserException(vectorElement, "Vector name '%(vectorName)s' conflicts with a "
+                                             "previously defined vector of the same name" % locals())
+    
+    ## Check that the name isn't already taken
+    if vectorName in self.globalNameSpace['symbolNames']:
+      raise ParserException(vectorElement, "Vector name '%(vectorName)s' conflicts with previously "
+                                          "defined symbol of the same name." % locals())
+    
+    ## Make sure no-one else takes the name
+    self.globalNameSpace['symbolNames'].add(vectorName)
+    
+    # Backwards compatibility
+    if vectorElement.hasAttribute('initial_space'):
+      basis_string = vectorElement.getAttribute('initial_space')
+      vectorElement.setAttribute('initial_basis', basis_string)
+    
+    if vectorElement.hasAttribute('initial_basis'):
+      initialBasis = fieldTemplate.basisFromString(
+        vectorElement.getAttribute('initial_basis'),
+        xmlElement = vectorElement
+      )
+    else:
+      initialBasis = fieldTemplate.defaultCoordinateBasis
+    
+    typeString = None
+    if vectorElement.hasAttribute('type'):
+      typeString = vectorElement.getAttribute('type').lower()
+    
+    if typeString in (None, 'complex'):
+      typeString = 'complex'
+    elif typeString == 'real':
+      typeString = 'real'
+    else:
+      raise ParserException(
+        vectorElement,
+        "Unknown type '%(typeString)s'. "
+        "Options are 'complex' (default), or 'real'" % locals()
+      )
+    
+    vectorTemplate = VectorElementTemplate(
+      name = vectorName, field = fieldTemplate, initialBasis = initialBasis,
+      type = typeString, xmlElement = vectorElement,
+      **self.argumentsToTemplateConstructors
+    )
+    
+    self.globalNameSpace['simulationVectors'].append(vectorTemplate)
+    
+    componentsElement = vectorElement.getChildElementByTagName('components')
+    
+    componentsString = componentsElement.innerText()
+    if not componentsString:
+      raise ParserException(componentsElement, "The components element must not be empty")
+    
+    results = Utilities.symbolsInString(componentsString, componentsElement)
+    
+    if not results:
+      raise ParserException(componentsElement, "Could not extract component names from component string "
+                                               "'%(componentsString)s'." % locals())
+    
+    for componentName in results:
+      if componentName in self.globalNameSpace['symbolNames']:
+        raise ParserException(componentsElement, "Component name '%(componentName)s' conflicts with "
+                                                 "a previously-defined symbol of the same name." % locals())
+      self.globalNameSpace['symbolNames'].add(componentName)
+      
+      vectorTemplate.components.append(componentName)
+    
+    initialisationElement = vectorElement.getChildElementByTagName('initialisation', optional=True)
+    
+    if initialisationElement:
+      initialisationTemplate = vectorTemplate.initialiser
+      kindString = None
+      if initialisationElement.hasAttribute('kind'):
+        kindString = initialisationElement.getAttribute('kind').lower()
+      
+      def createInitialisationCodeBlock():
+        initialisationCodeBlock = _UserLoopCodeBlock(
+          field = vectorTemplate.field, xmlElement = initialisationElement,
+          basis = vectorTemplate.initialBasis, parent = initialisationTemplate,
+          **self.argumentsToTemplateConstructors)
+        initialisationCodeBlock.dependenciesEntity = self.parseDependencies(initialisationElement, optional=True)
+        initialisationCodeBlock.targetVector = vectorTemplate
+        return initialisationCodeBlock
+      
+      
+      if kindString in (None, 'code'):
+        initialisationTemplate = VectorInitialisationFromCDATATemplate(parent = vectorTemplate, xmlElement=initialisationElement,
+                                                                       **self.argumentsToTemplateConstructors)
+        initialisationCodeBlock = createInitialisationCodeBlock()
+        initialisationTemplate.codeBlocks['initialisation'] = initialisationCodeBlock
+        
+        if len(initialisationCodeBlock.codeString) == 0:
+          raise ParserException(initialisationElement, "Empty initialisation code in 'code' initialisation element.")
+      elif kindString == 'zero':
+        initialisationTemplate = vectorTemplate.initialiser
+      elif kindString in ['xsil', 'hdf5']:
+        if kindString == 'xsil':
+          initialisationTemplateClass = VectorInitialisationFromXSILTemplate
+        elif kindString == 'hdf5':
+          initialisationTemplateClass = VectorInitialisationFromHDF5Template
+        initialisationTemplate = initialisationTemplateClass(parent = vectorTemplate, xmlElement=initialisationElement,
+                                                             **self.argumentsToTemplateConstructors)
+        geometryMatchingMode = 'strict'
+        if initialisationElement.hasAttribute('geometry_matching_mode'):
+          geometryMatchingMode = initialisationElement.getAttribute('geometry_matching_mode').strip().lower()
+          if not geometryMatchingMode in ('strict', 'loose'):
+            raise ParserException(initialisationElement, "The geometry matching mode for XSIL/HDF5 import must either be 'strict' or 'loose'.")
+        initialisationTemplate.geometryMatchingMode = geometryMatchingMode
+        
+        filenameElement = initialisationElement.getChildElementByTagName('filename')
+
+        if kindString == 'xsil':
+          momentGroupName = 'NULL'
+          if filenameElement.hasAttribute('group'):
+            momentGroupName = 'moment_group_' + filenameElement.getAttribute('group').strip()
+          initialisationTemplate.momentGroupName = momentGroupName
+        elif kindString == 'hdf5':
+          groupName = None
+          if filenameElement.hasAttribute('group'):
+            groupName = filenameElement.getAttribute('group').strip()
+          initialisationTemplate.groupName = groupName
+        
+        initialisationTemplate.codeBlocks['initialisation'] = createInitialisationCodeBlock()
+        
+        filename = filenameElement.innerText()
+        if filename.isspace():
+          raise ParserException(filenameElement, "The contents of the filename tag must be non-empty.")
+        
+        initialisationTemplate.filename = filename
+        
+      else:
+        raise ParserException(initialisationElement, "Initialisation kind '%(kindString)s' is unrecognised.\n"
+                                                     "The options are 'code' (default), 'hdf5', 'xsil', or 'zero' "
+                                                     "(this is the same as having no initialisation element)." % locals())
+      
+      # Untie the old initialiser from the vector
+      # Probably not strictly necessary
+      if not vectorTemplate.initialiser == initialisationTemplate:
+        vectorTemplate.initialiser.vector = None
+        vectorTemplate.initialiser.remove()
+      initialisationTemplate.vector = vectorTemplate
+      vectorTemplate.initialiser = initialisationTemplate
+      
+      self.parseFeatureAttributes(initialisationElement, initialisationTemplate)
+    
+    return vectorTemplate
+  
+  def parseComputedVectorElements(self, parentElement, parentTemplate):
+    results = []
+    computedVectorElements = parentElement.getChildElementsByTagName('computed_vector', optional=True)
+    for computedVectorElement in computedVectorElements:
+      # Add the computed vector template to the results
+      results.append(self.parseComputedVectorElement(computedVectorElement, parentTemplate))
+    
+    return results
+  
+  def parseComputedVectorElement(self, computedVectorElement, parentTemplate):
+    if not computedVectorElement.hasAttribute('name') or len(computedVectorElement.getAttribute('name')) == 0:
+      raise ParserException(computedVectorElement, "Each computed vector element must have a non-empty 'name' attribute")
+    
+    vectorName = computedVectorElement.getAttribute('name')
+    
+    # Check that this vector name is unique
+    for field in self.globalNameSpace['fields']:
+      if len(filter(lambda x: x.name == vectorName, field.vectors)) > 0:
+        raise ParserException(computedVectorElement, "Computed vector name '%(vectorName)s' conflicts with a "
+                                                     "previously defined vector of the same name" % locals())
+    
+    ## Check that the name isn't already taken
+    if vectorName in self.globalNameSpace['symbolNames']:
+      raise ParserException(computedVectorElement, "Computed vector name '%(vectorName)s' conflicts with previously "
+                                                   "defined symbol of the same name." % locals())
+    
+    ## Make sure no-one else takes the name
+    self.globalNameSpace['symbolNames'].add(vectorName)
+    
+    if not computedVectorElement.hasAttribute('dimensions'):
+      dimensionNames = self.globalNameSpace['geometry'].primaryTransverseDimensionNames
+    elif len(computedVectorElement.getAttribute('dimensions').strip()) == 0:
+      # No dimensions
+      dimensionNames = []
+    else:
+      dimensionsString = computedVectorElement.getAttribute('dimensions').strip()
+      dimensionNames = Utilities.symbolsInString(dimensionsString, xmlElement = computedVectorElement)
+      if not dimensionNames:
+        raise ParserException(computedVectorElement, "Cannot understand '%(dimensionsString)s' as a "
+                                                     "list of dimensions" % locals())
+        
+    
+    fieldTemplate = FieldElementTemplate.sortedFieldWithDimensionNames(dimensionNames, xmlElement = computedVectorElement)
+    
+    typeString = None
+    if computedVectorElement.hasAttribute('type'):
+      typeString = computedVectorElement.getAttribute('type').lower()
+    
+    if typeString in (None, 'complex'):
+      typeString = 'complex'
+    elif typeString == 'real':
+      typeString = 'real'
+    else:
+      raise ParserException(
+        computedVectorElement,
+        "Unknown type '%(typeString)s'. "
+        "Options are 'complex' (default), or 'real'" % locals()
+      )
+    
+    if parentTemplate is None:
+      parentTemplate = fieldTemplate
+    # One way or another, we now have our fieldTemplate
+    # So we can now construct the computed vector template
+    vectorTemplate = ComputedVectorTemplate(name = vectorName, field = fieldTemplate,
+                                            parent = parentTemplate, type = typeString,
+                                            xmlElement = computedVectorElement,
+                                            **self.argumentsToTemplateConstructors)
+    
+    self.globalNameSpace['simulationVectors'].append(vectorTemplate)
+    
+    componentsElement = computedVectorElement.getChildElementByTagName('components')
+    
+    
+    componentsString = componentsElement.innerText()
+    if not componentsString:
+      raise ParserException(componentsElement, "The components element must not be empty")
+    
+    results = Utilities.symbolsInString(componentsString, componentsElement)
+    
+    if not results:
+      raise ParserException(componentsElement, "Could not extract component names from component string "
+                                               "'%(componentsString)s'." % locals())
+    
+    for componentName in results:
+      if componentName in self.globalNameSpace['symbolNames']:
+        raise ParserException(componentsElement, "Component name '%(componentName)s' conflicts with "
+                                                 "a previously-defined symbol of the same name." % locals())
+      self.globalNameSpace['symbolNames'].add(componentName)
+      
+      vectorTemplate.components.append(componentName)
+    
+    evaluationElement = computedVectorElement.getChildElementByTagName('evaluation')
+    evaluationCodeBlock = _UserLoopCodeBlock(field = None, xmlElement = evaluationElement,
+                                             parent = vectorTemplate, **self.argumentsToTemplateConstructors)
+    evaluationCodeBlock.dependenciesEntity = self.parseDependencies(evaluationElement, optional=True)
+    evaluationCodeBlock.targetVector = vectorTemplate
+    vectorTemplate.codeBlocks['evaluation'] = evaluationCodeBlock
+    
+    self.parseFeatureAttributes(evaluationElement, vectorTemplate)
+    
+    return vectorTemplate
+  
+  
+  def parseNoiseVectorElements(self, parentElement, parentTemplate):
+    results = []
+    noiseVectorElements = parentElement.getChildElementsByTagName('noise_vector', optional=True)
+    for noiseVectorElement in noiseVectorElements:
+      # Add the noise vector template to the results
+      results.append(self.parseNoiseVectorElement(noiseVectorElement, parentTemplate))
+    
+    if noiseVectorElements and not 'Stochastic' in self.globalNameSpace['features']:
+      Features.Stochastic.Stochastic(parent = self.simulation, **self.argumentsToTemplateConstructors)
+    
+    
+    return results
+  
+  def parseNoiseVectorElement(self, noiseVectorElement, parentTemplate):
+    if not noiseVectorElement.hasAttribute('name') or len(noiseVectorElement.getAttribute('name')) == 0:
+      raise ParserException(noiseVectorElement, "Each noise vector element must have a non-empty 'name' attribute")
+    
+    vectorName = noiseVectorElement.getAttribute('name')
+    
+    # Check that this vector name is unique
+    for field in self.globalNameSpace['fields']:
+      if len(filter(lambda x: x.name == vectorName, field.vectors)) > 0:
+        raise ParserException(noiseVectorElement, "Noise vector name '%(vectorName)s' conflicts with a "
+                                                     "previously defined vector of the same name" % locals())
+    
+    ## Check that the name isn't already taken
+    if vectorName in self.globalNameSpace['symbolNames']:
+      raise ParserException(noiseVectorElement, "Noise vector name '%(vectorName)s' conflicts with previously "
+                                                   "defined symbol of the same name." % locals())
+    
+    ## Make sure no-one else takes the name
+    self.globalNameSpace['symbolNames'].add(vectorName)
+    
+    if not noiseVectorElement.hasAttribute('dimensions'):
+      dimensionNames = self.globalNameSpace['geometry'].primaryTransverseDimensionNames
+    elif len(noiseVectorElement.getAttribute('dimensions').strip()) == 0:
+      # No dimensions
+      dimensionNames = []
+    else:
+      dimensionsString = noiseVectorElement.getAttribute('dimensions').strip()
+      dimensionNames = Utilities.symbolsInString(dimensionsString, xmlElement = noiseVectorElement)
+      if not dimensionNames:
+        raise ParserException(noiseVectorElement, "Cannot understand '%(dimensionsString)s' as a "
+                                                     "list of dimensions" % locals())
+    
+    
+    fieldTemplate = FieldElementTemplate.sortedFieldWithDimensionNames(dimensionNames, xmlElement = noiseVectorElement)
+
+    # Backwards compatibility
+    if noiseVectorElement.hasAttribute('initial_space'):
+      basis_string = noiseVectorElement.getAttribute('initial_space')
+      noiseVectorElement.setAttribute('initial_basis', basis_string)
+    
+    if noiseVectorElement.hasAttribute('initial_basis'):
+      initialBasis = fieldTemplate.basisFromString(
+          noiseVectorElement.getAttribute('initial_basis'),
+          xmlElement = noiseVectorElement
+      )
+    else:
+      initialBasis = fieldTemplate.defaultCoordinateBasis
+    
+    typeString = None
+    if noiseVectorElement.hasAttribute('type'):
+      typeString = noiseVectorElement.getAttribute('type').lower()
+    
+    if not noiseVectorElement.hasAttribute('kind') or len(noiseVectorElement.getAttribute('kind')) == 0:
+      raise ParserException(noiseVectorElement, "Each noise vector element must have a non-empty 'kind' attribute")
+    
+    vectorKind = noiseVectorElement.getAttribute('kind').strip().lower()
+    vectorMethod = None
+    if noiseVectorElement.hasAttribute('method'):
+      vectorMethod = noiseVectorElement.getAttribute('method').lower()
+    else:
+      vectorMethod = 'posix'
+    
+    randomVariableClass = None
+    generatorClass = None
+    static = None
+    randomVariableAttributeDictionary = dict()
+    
+    if vectorKind in ('gauss', 'gaussian', 'wiener'):
+      static = True
+      if vectorKind == 'wiener':
+        static = False
+      randomVariableClass, generatorClass = {
+        'mkl': (GaussianMKLRandomVariable, MKLGenerator),
+        'dsfmt': (GaussianBoxMuellerRandomVariable, DSFMTGenerator),
+        'posix': (GaussianBoxMuellerRandomVariable, POSIXGenerator),
+        'solirte': (GaussianSolirteRandomVariable, SolirteGenerator),
+      }.get(vectorMethod,(None,None))
+      if not generatorClass:
+        raise ParserException(noiseVectorElement, "Method '%(vectorMethod)s' for Gaussian noises is unknown.  Legal possibilities include 'mkl', 'dsfmt', 'posix' and 'solirte'." % locals())
+    
+    elif vectorKind == 'uniform':
+      static = True
+      randomVariableClass = UniformRandomVariable
+      generatorClass = {
+        'mkl': MKLGenerator,
+        'dsfmt': DSFMTGenerator,
+        'posix': POSIXGenerator,
+        'solirte': SolirteGenerator,
+      }.get(vectorMethod)
+      if not generatorClass:
+        raise ParserException(noiseVectorElement, "Method '%(vectorMethod)s' for uniform noises is unknown." % locals())
+    
+    elif vectorKind in ('poissonian','jump'):
+      if typeString == 'complex':
+        raise ParserException(noiseVectorElement, "Poissonian noises cannot be complex-valued.")        
+      randomVariableClass = PoissonianRandomVariable
+      if vectorKind == 'jump':
+        static = False
+        if noiseVectorElement.hasAttribute('mean-rate'):
+          meanRateString = noiseVectorElement.getAttribute('mean-rate')
+          meanRateAttributeName = 'mean-rate'
+        else:  
+          raise ParserException(noiseVectorElement, "Jump noises must specify a 'mean-rate' attribute.")
+      elif vectorKind == 'poissonian':
+        static = True
+        if noiseVectorElement.hasAttribute('mean-density'):
+          meanRateString = noiseVectorElement.getAttribute('mean-density')
+          meanRateAttributeName = 'mean-density'
+        elif noiseVectorElement.hasAttribute('mean'):
+          meanRateString = noiseVectorElement.getAttribute('mean')
+          meanRateAttributeName = 'mean'
+        else:  
+          raise ParserException(noiseVectorElement, "Poissonian noise must specify a 'mean-density' or 'mean' attribute.")
+          
+      if vectorMethod == 'posix': 
+        generatorClass = POSIXGenerator
+      elif vectorMethod == 'dsfmt':
+          generatorClass = DSFMTGenerator
+      else:
+        raise ParserException(noiseVectorElement, "Method '%(vectorMethod)s' for Poissonian and Jump noises is unknown." % locals())
+      
+      try:
+        meanRate = float(meanRateString) # Is it a simple number?
+        if meanRate < 0.0:               # Was the number positive?
+          raise ParserException(noiseVectorElement, "The %(meanRateAttributeName)s for Poissonian noises must be positive." % locals())
+      except ValueError, err:
+        # We could just barf now, but it could be valid code, and there's no way we can know.
+        # But we only accept code for this value when we have a validation element with a 
+        # run-time kind of validation check
+        if 'Validation' in self.globalNameSpace['features']:
+          validationFeature = self.globalNameSpace['features']['Validation']
+          validationFeature.validationChecks.append("""
+          if (%(meanRateString)s < 0.0)
+            _LOG(_ERROR_LOG_LEVEL, "ERROR: The %(meanRateAttributeName)s for Poissonian noise %(vectorName)s is not positive!\\n"
+                                   "Mean-rate = %%e\\n", %(meanRateString)s);""" % locals())
+        else:
+          raise ParserException(
+            noiseVectorElement,
+            "Unable to understand '%(meanRateString)s' as a positive real value. "
+            "Use the feature <validation kind=\"run-time\"/> to allow for arbitrary code." % locals()
+          )
+      randomVariableAttributeDictionary['noiseMeanRate'] = meanRateString
+    else:
+      raise ParserException(noiseVectorElement, "Unknown noise kind '%(kind)s'." % locals())
+    
+    if static is None:
+      raise ParserException(
+          noiseVectorElement, 
+          "Internal error: Noise type is not defined as static or dynamic. "
+          "Please report this error to %s." % self.globalNameSpace['bugReportAddress'])
+    
+    if typeString in (None, 'complex'):
+      typeString = 'complex'
+    elif typeString == 'real':
+      typeString = 'real'
+    else:
+      raise ParserException(noiseVectorElement,
+        "Unknown type '%(typeString)s'. "
+        "Options are 'complex' (default), or 'real'" % locals()
+      )
+    
+    if parentTemplate is None:
+      parentTemplate = fieldTemplate
+    # One way or another, we now have our fieldTemplate
+    # So we can now construct the noise vector template
+    vectorTemplate = NoiseVectorTemplate(
+      name = vectorName, field = fieldTemplate, staticNoise = static,
+      parent = parentTemplate, initialBasis = initialBasis,
+      type = typeString, xmlElement = noiseVectorElement,
+      **self.argumentsToTemplateConstructors
+    )
+    
+    self.globalNameSpace['simulationVectors'].append(vectorTemplate)
+    
+    
+    componentsElement = noiseVectorElement.getChildElementByTagName('components')
+    
+    componentsString = componentsElement.innerText()
+    if not componentsString:
+      raise ParserException(componentsElement, "The components element must not be empty")
+    
+    results = Utilities.symbolsInString(componentsString, componentsElement)
+    
+    if not results:
+      raise ParserException(componentsElement, "Could not extract component names from component string "
+                                               "'%(componentsString)s'." % locals())
+    
+    for componentName in results:
+      if componentName in self.globalNameSpace['symbolNames']:
+        raise ParserException(componentsElement, "Component name '%(componentName)s' conflicts with "
+                                                 "a previously-defined symbol of the same name." % locals())
+      self.globalNameSpace['symbolNames'].add(componentName)
+    
+      vectorTemplate.components.append(componentName)
+      
+    randomVariable = randomVariableClass(parent = vectorTemplate, **self.argumentsToTemplateConstructors)
+    vectorTemplate._children.append(randomVariable)
+    generator = generatorClass(parent = randomVariable, **self.argumentsToTemplateConstructors)
+    randomVariable._children.append(generator)
+    
+    self.applyAttributeDictionaryToObject(randomVariableAttributeDictionary, randomVariable)
+    
+    generator.seedArray = []
+    if noiseVectorElement.hasAttribute('seed'):
+      seedStringList = noiseVectorElement.getAttribute('seed').split()
+      for seedString in seedStringList:
+        try:
+          seedInt = int(seedString)
+          if seedInt < 0:
+            raise ParserException(noiseVectorElement, "Seeds must be positive integers." % locals())
+        except ValueError, err:
+          if 'Validation' in self.globalNameSpace['features']:
+            validationFeature = self.globalNameSpace['features']['Validation']
+            validationFeature.validationChecks.append("""
+            if (%(seedString)s < 0)
+              _LOG(_ERROR_LOG_LEVEL, "ERROR: The seed for this noise vector is not positive!\\n"
+              "Seed = %%d\\n", %(seedString)s);""" % locals())
+          else:
+            raise ParserException(noiseVectorElement, "Unable to understand seed '%(seedString)s' as a positive integer. Use the feature <validation kind=\"run-time\"/> to allow for arbitrary code." % locals())
+      generator.seedArray = seedStringList
+      
+    generator.generatorName = '_gen_'+vectorName
+    randomVariable.generator = generator
+      
+    vectorTemplate.randomVariable = randomVariable
+
+    return vectorTemplate
+
+
+  def parseTopLevelSequenceElement(self, simulationElement):
+    topLevelSequenceElement = simulationElement.getChildElementByTagName('sequence')
+    
+    topLevelSequenceElementTemplate = TopLevelSequenceElementTemplate(**self.argumentsToTemplateConstructors)
+    
+    self.parseSequenceElement(topLevelSequenceElement, topLevelSequenceElementTemplate)
+  
+  def parseSequenceElement(self, sequenceElement, sequenceTemplate):
+    if sequenceElement.hasAttribute('cycles'):
+      cyclesString = sequenceElement.getAttribute('cycles')
+      try:
+        cycles = int(cyclesString)
+      except ValueError, err:
+        raise ParserException(sequenceElement, "Unable to understand '%(cyclesString)s' as an integer.")
+      
+      if cycles <= 0:
+        raise ParserException(sequenceElement, "The number of cycles must be positive.")
+      
+      sequenceTemplate.localCycles = cycles
+    
+    for childNode in sequenceElement.childNodes:
+      if not childNode.nodeType == minidom.Node.ELEMENT_NODE:
+        continue
+      
+      tagName = childNode.tagName.lower()
+      
+      if tagName == 'integrate':
+        integrateTemplate = self.parseIntegrateElement(childNode)
+        sequenceTemplate.addSegment(integrateTemplate)
+      elif tagName == 'filter':
+        # Construct the filter segment
+        filterSegmentTemplate = FilterSegmentTemplate(xmlElement = childNode,
+                                                      **self.argumentsToTemplateConstructors)
+        # Add it to the sequence element as a child segment
+        sequenceTemplate.addSegment(filterSegmentTemplate)
+        # Create an operator container to house the filter operator
+        operatorContainer = OperatorContainerTemplate(parent = filterSegmentTemplate,
+                                                      **self.argumentsToTemplateConstructors)
+        # Add the operator container to the filter segment
+        filterSegmentTemplate.operatorContainers.append(operatorContainer)
+        # parse the filter operator
+        filterOperator = self.parseFilterOperator(childNode, operatorContainer)
+      elif tagName == 'breakpoint':
+        # Construct the breakpoint segment
+        breakpointSegmentTemplate = BreakpointSegmentTemplate(xmlElement = childNode,
+                                                              **self.argumentsToTemplateConstructors)
+        # Add it to the sequence element as a child segment
+        sequenceTemplate.addSegment(breakpointSegmentTemplate)
+        # parse a dependencies element
+        breakpointSegmentTemplate.dependenciesEntity = self.parseDependencies(childNode)
+        
+        if childNode.hasAttribute('filename'):
+          breakpointSegmentTemplate.filename = childNode.getAttribute('filename').strip()
+        else:
+          parserWarning(childNode, "Breakpoint names defaulting to the sequence 1.xsil, 2.xsil, etc.")
+        
+        if childNode.hasAttribute('format'):
+          formatString = childNode.getAttribute('format').strip().lower()
+          outputFormatClass = Features.OutputFormat.OutputFormat.outputFormatClasses.get(formatString)
+          if not outputFormatClass:
+            validFormats = ', '.join(["'%s'" % formatName for formatName in Features.OutputFormat.OutputFormat.outputFormatClasses.keys()])
+            raise ParserException(childNode, "Breakpoint format attribute '%(formatString)s' unknown.\n"
+                                             "The valid formats are %(validFormats)s." % locals())
+          outputFormat = outputFormatClass(parent = breakpointSegmentTemplate, **self.argumentsToTemplateConstructors)
+          
+          breakpointSegmentTemplate.outputFormat = outputFormat
+      
+      elif tagName == 'sequence':
+        # Construct the sequence segment
+        sequenceSegmentTemplate = SequenceSegmentTemplate(**self.argumentsToTemplateConstructors)
+        sequenceTemplate.addSegment(sequenceSegmentTemplate)
+        
+        self.parseSequenceElement(childNode, sequenceSegmentTemplate)
+      else:
+        raise ParserException(childNode, "Unknown child of sequence element. "
+                                         "Possible children include 'sequence', 'integrate', 'filter' or 'breakpoint' elements.")
+    
+  
+  def parseIntegrateElement(self, integrateElement):
+    if not integrateElement.hasAttribute('algorithm'):
+      raise ParserException(integrateElement, "Integration element must have an 'algorithm' attribute.")
+    
+    integratorTemplateClass = None
+    stepperTemplateClass = None
+    algorithmSpecificOptionsDict = dict()
+    
+    algorithmString = integrateElement.getAttribute('algorithm')
+    algorithmMap = {
+      'SI':    (Integrators.FixedStep.FixedStep,                   Integrators.SIStepper.SIStepper),
+      'RK4':   (Integrators.FixedStep.FixedStep,                   Integrators.RK4Stepper.RK4Stepper),
+      'RK9':   (Integrators.FixedStep.FixedStep,                   Integrators.RK9Stepper.RK9Stepper),
+      'RK45':  (Integrators.FixedStep.FixedStep,                   Integrators.RK45Stepper.RK45Stepper),
+      'RK89':  (Integrators.FixedStep.FixedStep,                   Integrators.RK89Stepper.RK89Stepper),
+      'ARK45': (Integrators.AdaptiveStep.AdaptiveStep,             Integrators.RK45Stepper.RK45Stepper),
+      'ARK89': (Integrators.AdaptiveStep.AdaptiveStep,             Integrators.RK89Stepper.RK89Stepper),
+      'SIC':   (Integrators.FixedStepWithCross.FixedStepWithCross, Integrators.SICStepper.SICStepper),
+    }
+    integratorTemplateClass, stepperTemplateClass = algorithmMap.get(algorithmString, (None, None))
+    
+    if not integratorTemplateClass:
+      raise ParserException(
+        integrateElement,
+        "Unknown algorithm '%s'. "
+        "Options are %s." % (algorithmString, ', '.join(algorithmMap.keys())))
+    
+    if algorithmString == 'RK45':
+      parserWarning(
+        integrateElement,
+        "RK45 is probably not the algorithm you want. RK45 is a 5th-order algorithm with embedded 4th-order "
+        "where the 4th-order results are just thrown away. Unless you know what you are doing, you probably meant RK4 or ARK45."
+      )
+    elif algorithmString == 'RK89':
+      parserWarning(
+        integrateElement,
+        "RK89 is probably not the algorithm you want. RK89 is a 9th-order algorithm with embedded 8th-order "
+        "where the 8th-order results are just thrown away. Unless you know what you are doing, you probably meant RK9 or ARK89."
+      )
+    elif algorithmString in ['SI','SIC']:
+      if integrateElement.hasAttribute('iterations'):
+        algorithmSpecificOptionsDict['iterations'] = RegularExpressionStrings.integerInString(integrateElement.getAttribute('iterations'))
+        if algorithmSpecificOptionsDict['iterations'] < 1:
+          raise ParserException(integrateElement, "Iterations element must be 1 or greater (default 3).")
+    
+    integratorTemplate = integratorTemplateClass(stepperClass = stepperTemplateClass, **self.argumentsToTemplateConstructors)
+    self.applyAttributeDictionaryToObject(algorithmSpecificOptionsDict, stepperTemplateClass)
+    
+    if integrateElement.hasAttribute('home_space'):
+      attributeValue = integrateElement.getAttribute('home_space').strip().lower()
+      if attributeValue == 'k':
+        integratorTemplate.homeBasis = self.globalNameSpace['geometry'].defaultSpectralBasis
+      elif attributeValue == 'x':
+        integratorTemplate.homeBasis = self.globalNameSpace['geometry'].defaultCoordinateBasis
+      else:
+        raise ParserException(integrateElement, "home_space must be either 'k' or 'x'.")
+    else:
+      integratorTemplate.homeBasis = self.globalNameSpace['geometry'].defaultCoordinateBasis
+    
+    if issubclass(integratorTemplateClass, Integrators.AdaptiveStep.AdaptiveStep):
+      if not integrateElement.hasAttribute('tolerance'):
+        raise ParserException(integrateElement, "Adaptive integrators need a 'tolerance' attribute.")
+      else:
+        toleranceString = integrateElement.getAttribute('tolerance').strip()
+        try:
+          tolerance = float(toleranceString)
+          if tolerance <= 0.0:
+            raise ParserException(integrateElement, "Tolerance must be positive.")
+          minTolerance = {'single': 2**-21, 'double': 2**-50}[self.globalNameSpace['precision']]
+          if 'ErrorCheck' in self.globalNameSpace['features']:
+            minTolerance *= 16
+          if tolerance < minTolerance:
+            raise ParserException(
+              integrateElement,
+              "Requested integration tolerance '%s' is smaller than the machine precision for %s precision arithmetic %.1e." % (toleranceString, self.globalNameSpace['precision'], minTolerance)
+            )
+        except ValueError, err:
+          raise ParserException(integrateElement, "Could not understand tolerance '%(toleranceString)s' "
+                                                  "as a number." % locals())
+        
+        integratorTemplate.tolerance = tolerance
+      
+      # FIXME: The adaptive integrators need both an absolute and a relative cutoff
+      if not integrateElement.hasAttribute('cutoff'):
+        pass
+      else:
+        cutoffString = integrateElement.getAttribute('cutoff').strip()
+        try:
+          cutoff = float(cutoffString)
+          if not 0.0 < cutoff <= 1.0:
+            raise ParserException(integrateElement, "Cutoff must be in the range (0.0, 1.0].")
+        except ValueError, err:
+          raise ParserException(integrateElement, "Could not understand cutoff '%(cutoffString)s' "
+                                                  "as a number." % locals())
+        integratorTemplate.cutoff = cutoff
+        
+    
+    if not integrateElement.hasAttribute('interval'):
+      raise ParserException(integrateElement, "Integrator needs 'interval' attribute.")
+    
+    intervalString = integrateElement.getAttribute('interval')
+    # Now check if the interval is a valid number or variable
+    try:
+      interval = float(intervalString) # Is it a simple number?
+      if interval <= 0.0:              # Was the number positive?
+        raise ParserException(integrateElement, "Interval must be positive.")
+    except ValueError, err:
+      # We could just barf now, but it could be valid code, and there's no way we can know.
+      # But we only accept code for this value when we have a validation element with a 
+      # run-time kind of validation check
+      if 'Validation' in self.globalNameSpace['features']:
+        validationFeature = self.globalNameSpace['features']['Validation']
+        segmentNumber = integratorTemplate.segmentNumber
+        validationFeature.validationChecks.append("""
+        if (%(intervalString)s <= 0.0)
+          _LOG(_ERROR_LOG_LEVEL, "ERROR: The interval for segment %(segmentNumber)i is not positive!\\n"
+                                 "Interval = %%e\\n", %(intervalString)s);""" % locals())
+      else:
+        raise ParserException(integrateElement, "Could not understand interval '%(intervalString)s' "
+                                                "as a number. Use the feature <validation kind=\"run-time\"/> to allow for arbitrary code." % locals())
+    
+    integratorTemplate.interval = intervalString
+    
+    if not integrateElement.hasAttribute('steps') and isinstance(integratorTemplate, Integrators.FixedStep.FixedStep):
+      raise ParserException(integrateElement, "Fixed-step integrators require a 'steps' attribute.")
+    
+    if integrateElement.hasAttribute('steps'):
+      stepsString = integrateElement.getAttribute('steps').strip()
+      if not stepsString.isdigit():
+        raise ParserException(integrateElement, "Could not understand steps '%(stepsString)s' "
+                                                "as a positive integer." % locals())
+      
+      steps = int(stepsString)
+      integratorTemplate.stepCount = steps
+    
+    samplesElement = integrateElement.getChildElementByTagName('samples', optional=True)
+    if samplesElement:
+        samplesString = samplesElement.innerText()
+    
+        results = RegularExpressionStrings.integersInString(samplesString)
+    
+        if not results:
+          raise ParserException(samplesElement, "Could not understand '%(samplesString)s' "
+                                                "as a list of integers" % locals())
+    
+        if filter(lambda x: x < 0, results):
+          raise ParserException(samplesElement, "All sample counts must be greater than zero.")
+    
+        integratorTemplate.samplesEntity = ParsedEntity(samplesElement, results)
+    
+    integratorTemplate.localVectors.update(self.parseComputedVectorElements(integrateElement, integratorTemplate))
+    
+    integratorTemplate.localVectors.update(self.parseNoiseVectorElements(integrateElement, integratorTemplate))
+    
+    self.parseOperatorsElements(integrateElement, integratorTemplate)
+    
+    self.parseFiltersElements(integrateElement, integratorTemplate)
+    
+    self.parseFeatureAttributes(integrateElement, integratorTemplate)
+    
+    return integratorTemplate
+  
+  def parseFiltersElements(self, integrateElement, integratorTemplate):
+    filtersElements = integrateElement.getChildElementsByTagName('filters', optional=True)
+    
+    for filtersElement in filtersElements:
+      filterOperatorContainer = self.parseFilterElements(filtersElement, parent=integratorTemplate)
+      
+      whereString = None
+      if filtersElement.hasAttribute('where'):
+        whereString = filtersElement.getAttribute('where').strip().lower()
+      if whereString in (None, 'step start'):
+        integratorTemplate.stepStartOperatorContainers.append(filterOperatorContainer)
+      elif whereString == 'step end':
+        integratorTemplate.stepEndOperatorContainers.append(filterOperatorContainer)
+      else:
+        raise ParserException(filtersElement, "Unknown placement of filters in the 'where' tag of '%(whereString)s'.\n"
+                                              "Valid options are: 'step start' (default) or 'step end'." % locals())
+    
+  def parseFilterElements(self, filtersElement, parent, optional = False):
+    filterElements = filtersElement.getChildElementsByTagName('filter', optional = optional)
+    
+    if filterElements:
+      operatorContainer = OperatorContainerTemplate(parent = parent,
+                                                    **self.argumentsToTemplateConstructors)
+    else:
+      operatorContainer = None
+    
+    for filterElement in filterElements:
+      filterTemplate = self.parseFilterOperator(filterElement, operatorContainer)
+    
+    return operatorContainer
+  
+  def parseFilterOperator(self, filterElement, parentTemplate):
+    filterName = filterElement.getAttribute('name')
+    
+    if filterName:
+        ## Check that the name isn't already taken
+        if filterName in self.globalNameSpace['symbolNames']:
+          raise ParserException(filterElement, "Filter name '%(filterName)s' conflicts with previously "
+                                                       "defined symbol of the same name." % locals())
+    
+        ## Make sure no-one else takes the name
+        self.globalNameSpace['symbolNames'].add(filterName)
+    
+    filterTemplate = FilterOperatorTemplate(parent = parentTemplate,
+                                            xmlElement = filterElement, name = filterName,
+                                            **self.argumentsToTemplateConstructors)
+    
+    codeBlock = _UserLoopCodeBlock(field = None, xmlElement = filterElement,
+                                   parent = filterTemplate, **self.argumentsToTemplateConstructors)
+    codeBlock.dependenciesEntity = self.parseDependencies(filterElement, optional=True)
+    filterTemplate.codeBlocks['operatorDefinition'] = codeBlock
+    
+    return filterTemplate
+  
+  def parseOperatorsElements(self, integrateElement, integratorTemplate):
+    operatorsElements = integrateElement.getChildElementsByTagName('operators')
+    
+    fieldsUsed = []
+    
+    for operatorsElement in operatorsElements:
+      if not operatorsElement.hasAttribute('dimensions'):
+        integrationVectorsElement = operatorsElement.getChildElementByTagName('integration_vectors')
+        integrationVectorNames = Utilities.symbolsInString(integrationVectorsElement.innerText(), xmlElement = integrationVectorsElement)
+        vectorNameMap = dict((v.name, v) for v in self.globalNameSpace['simulationVectors'])
+        fields = set()
+        for vectorName in integrationVectorNames:
+          if not vectorName in vectorNameMap:
+            raise ParserException(integrationVectorsElement, "Unknown vector '%s'." % vectorName)
+          vector = vectorNameMap[vectorName]
+          fields.add(vector.field)
+        if not len(fields) == 1:
+          raise ParserException(integrationVectorsElement, "All integration vectors must be in the same field!  Integration vectors having different dimensions must be put in separate <operators> blocks with separate <![CDATA[...]]> blocks (within the same integrator).")
+        fieldTemplate = list(fields)[0]
+      else:
+        dimensionNames = Utilities.symbolsInString(operatorsElement.getAttribute('dimensions'), xmlElement = operatorsElement)
+        
+        fieldTemplate = FieldElementTemplate.sortedFieldWithDimensionNames(dimensionNames, xmlElement = operatorsElement, createIfNeeded = False)
+      
+      if not fieldTemplate:
+        raise ParserException(operatorsElement, "There are no vectors with this combination of dimensions.")
+      
+      if fieldTemplate in fieldsUsed:
+        parserWarning(
+          operatorsElement,
+          "There is more than one operators elements with this combination of dimensions. "
+          "The appropriate checks aren't yet in place to make sure that you aren't shooting yourself in the foot. "
+          "Are you sure you meant this?"
+        )
+      
+      fieldsUsed.append(fieldTemplate)
+      
+      self.parseOperatorsElement(operatorsElement, integratorTemplate, fieldTemplate, count = fieldsUsed.count(fieldTemplate))
+    
+  
+  def parseOperatorsElement(self, operatorsElement, integratorTemplate, fieldTemplate, count = 1):
+    if count == 1:
+      operatorSuffix = ''
+    else:
+      operatorSuffix = str(count)
+    operatorContainer = OperatorContainerTemplate(field = fieldTemplate, xmlElement = operatorsElement,
+                                                  name = fieldTemplate.name + operatorSuffix + '_operators',
+                                                  parent = integratorTemplate,
+                                                  **self.argumentsToTemplateConstructors)
+    integratorTemplate.intraStepOperatorContainers.append(operatorContainer)
+    
+    self.parseOperatorElements(operatorsElement, operatorContainer, integratorTemplate)
+  
+  def parseOperatorElements(self, operatorsElement, operatorContainer, integratorTemplate):
+    haveHitDeltaAOperator = False
+    for childNode in operatorsElement.childNodes:
+      if childNode.nodeType == minidom.Node.ELEMENT_NODE and childNode.tagName == 'operator':
+        # We have an operator element
+        operatorTemplate = self.parseOperatorElement(childNode, operatorContainer)
+        
+        if haveHitDeltaAOperator and not isinstance(operatorTemplate, (FunctionsOperatorTemplate)):
+          raise ParserException(childNode, "You cannot have this kind of operator after the CDATA section\n"
+                                           "of the <operators> element. The only operators that can be put\n"
+                                           "after the CDATA section are 'functions' operators.")
+      
+      elif childNode.nodeType == minidom.Node.CDATA_SECTION_NODE:
+        deltaAOperatorTemplate = self.parseDeltaAOperator(operatorsElement, operatorContainer)
+        haveHitDeltaAOperator = True
+    
+  
+  def parseDeltaAOperator(self, operatorsElement, operatorContainer):
+    deltaAOperatorTemplate = DeltaAOperatorTemplate(parent = operatorContainer, xmlElement = operatorsElement,
+                                                    **self.argumentsToTemplateConstructors)
+    
+    integrationVectorsElement = operatorsElement.getChildElementByTagName('integration_vectors')
+    if integrationVectorsElement.hasAttribute('basis'):
+      basis = operatorContainer.field.basisFromString(integrationVectorsElement.getAttribute('basis'))
+    else:
+      basis = operatorContainer.field.defaultCoordinateBasis
+    
+    operatorDefinitionCodeBlock = _UserLoopCodeBlock(
+      field = operatorContainer.field, parent = operatorContainer, basis = basis,
+      xmlElement = operatorsElement, **self.argumentsToTemplateConstructors)
+    operatorDefinitionCodeBlock.dependenciesEntity = self.parseDependencies(operatorsElement, optional=True)
+    
+    deltaAOperatorTemplate.codeBlocks['operatorDefinition'] = operatorDefinitionCodeBlock
+    
+    self.parseFeatureAttributes(operatorsElement, deltaAOperatorTemplate)
+    
+    integrationVectorsNames = Utilities.symbolsInString(integrationVectorsElement.innerText(), xmlElement = integrationVectorsElement)
+    
+    if not integrationVectorsNames:
+      raise ParserException(integrationVectorsElement, "Element must be non-empty.")
+    
+    deltaAOperatorTemplate.integrationVectorsEntity = ParsedEntity(integrationVectorsElement, integrationVectorsNames)
+  
+  def parseOperatorElement(self, operatorElement, operatorContainer):
+    if not operatorElement.hasAttribute('kind'):
+      raise ParserException(operatorElement, "Missing 'kind' attribute.")
+    
+    kindString = operatorElement.getAttribute('kind').strip().lower()
+    
+    constantString = None
+    if operatorElement.hasAttribute('constant'):
+      constantString = operatorElement.getAttribute('constant').strip().lower()
+    
+    parserMethod = None
+    operatorTemplateClass = None
+    
+    if kindString == 'ip':
+      integratorTemplate = operatorContainer.parent
+      
+      if isinstance(integratorTemplate, Integrators.FixedStep.FixedStep) and not constantString:
+        raise ParserException(operatorElement, "Missing 'constant' attribute.")
+      elif isinstance(integratorTemplate, Integrators.AdaptiveStep.AdaptiveStep):
+        operatorTemplateClass = NonConstantIPOperatorTemplate
+      elif constantString == 'yes':
+        operatorTemplateClass = ConstantIPOperatorTemplate
+      elif constantString == 'no':
+        operatorTemplateClass = NonConstantIPOperatorTemplate
+      else:
+        raise ParserException(operatorElement, "The 'constant' attribute must be either 'yes' or 'no'.")
+      
+      parserMethod = self.parseIPOperatorElement
+    elif kindString == 'ex':
+      if not constantString:
+        raise ParserException(operatorElement, "Missing 'constant' attribute.")
+      
+      parserMethod = self.parseEXOperatorElement
+      if constantString == 'yes':
+        operatorTemplateClass = ConstantEXOperatorTemplate
+      elif constantString == 'no':
+        operatorTemplateClass = NonConstantEXOperatorTemplate
+      else:
+        raise ParserException(operatorElement, "The constant attribute must be either 'yes' or 'no'.")
+    elif kindString == 'cross_propagation':
+      parserMethod = self.parseCrossPropagationOperatorElement
+      operatorTemplateClass = CrossPropagationOperatorTemplate
+    elif kindString == 'functions':
+      parserMethod = None
+      operatorTemplateClass = FunctionsOperatorTemplate
+    else:
+      raise ParserException(operatorElement, "Unknown operator kind '%(kindString)s'\n"
+                                             "Valid options are: 'ip', 'ex', 'functions' or 'cross-propagation'." % locals())
+    
+    operatorTemplate = operatorTemplateClass(parent = operatorContainer,
+                                             xmlElement = operatorElement,
+                                             **self.argumentsToTemplateConstructors)
+    
+    operatorDefinitionCodeBlock = _UserLoopCodeBlock(field = operatorContainer.field, xmlElement = operatorElement,
+                                                     parent = operatorTemplate, **self.argumentsToTemplateConstructors)
+    operatorDefinitionCodeBlock.dependenciesEntity = self.parseDependencies(operatorElement, optional=True)
+    
+    operatorTemplate.codeBlocks['operatorDefinition'] = operatorDefinitionCodeBlock
+    
+    if parserMethod:
+      parserMethod(operatorTemplate, operatorElement)
+    
+    return operatorTemplate
+  
+  def parseIPOperatorElement(self, operatorTemplate, operatorElement):
+    operatorDefinitionCodeBlock = operatorTemplate.primaryCodeBlock
+    
+    if operatorElement.hasAttribute('basis'):
+      operatorDefinitionCodeBlock.basis = \
+        operatorTemplate.field.basisFromString(operatorElement.getAttribute('basis'), xmlElement = operatorElement)
+    else:
+      operatorDefinitionCodeBlock.basis = operatorTemplate.field.defaultSpectralBasis
+    
+    operatorNamesElement = operatorElement.getChildElementByTagName('operator_names')
+    operatorNames = Utilities.symbolsInString(operatorNamesElement.innerText(), xmlElement = operatorNamesElement)
+    
+    if not operatorNames:
+      raise ParserException(operatorNamesElement, "operator_names must not be empty.")
+    
+    for operatorName in operatorNames:
+      if operatorName in self.globalNameSpace['symbolNames']:
+        raise ParserException(operatorNamesElement,
+                "Operator name '%(operatorName)s' conflicts with previously-defined symbol." % locals())
+      # self.globalNameSpace['symbolNames'].add(operatorName)
+      
+    operatorTemplate.operatorNames = operatorNames
+    
+    vectorName = operatorTemplate.id + "_field"
+    
+    typeString = 'complex'
+    if operatorElement.hasAttribute('type'):
+      typeString = operatorElement.getAttribute('type').strip().lower()
+      if not typeString in ['real', 'imaginary', 'complex']:
+        raise ParserException(operatorElement, "Unknown IP operator type '%(typeString)s'.\n"
+                                               "The 'type' attribute must be 'real', 'imaginary' or 'complex'." % locals())
+      if typeString == 'imaginary':
+        typeString = 'complex'
+        operatorTemplate.expFunction = 'cis'
+        operatorTemplate.valueSuffix = '.Im()'
+    
+    operatorVectorTemplate = VectorElementTemplate(
+      name = vectorName, field = operatorTemplate.field,
+      parent = operatorTemplate, initialBasis = operatorTemplate.operatorBasis,
+      type = typeString,
+      **self.argumentsToTemplateConstructors
+    )
+    
+    operatorVectorTemplate.needsInitialisation = False
+    
+    operatorDefinitionCodeBlock.targetVector = operatorVectorTemplate
+    
+    operatorContainer = operatorTemplate.parent
+    integratorTemplate = operatorContainer.parent
+    
+    if not isinstance(operatorTemplate, NonConstantIPOperatorTemplate):
+      operatorVectorTemplate.nComponents = len(integratorTemplate.ipPropagationStepFractions) * len(operatorNames)
+    else:
+      operatorVectorTemplate.nComponents = integratorTemplate.nonconstantIPFields * len(operatorNames)
+    operatorTemplate.operatorVector = operatorVectorTemplate
+    
+    return operatorTemplate
+  
+  def parseEXOperatorElement(self, operatorTemplate, operatorElement):
+    operatorDefinitionCodeBlock = operatorTemplate.primaryCodeBlock
+    
+    if operatorElement.hasAttribute('basis'):
+      operatorDefinitionCodeBlock.basis = \
+        operatorTemplate.field.basisFromString(operatorElement.getAttribute('basis'), xmlElement = operatorElement)
+    else:
+      operatorDefinitionCodeBlock.basis = operatorTemplate.field.defaultSpectralBasis
+    
+    operatorNamesElement = operatorElement.getChildElementByTagName('operator_names')
+    
+    operatorNames = Utilities.symbolsInString(operatorNamesElement.innerText(), xmlElement = operatorNamesElement)
+    
+    if not operatorNames:
+      raise ParserException(operatorNamesElement, "operator_names must not be empty.")
+    
+    resultVectorComponentPrefix = "_" + operatorTemplate.id
+    resultVectorComponents = []
+    
+    for operatorName in operatorNames:
+      if operatorName in self.globalNameSpace['symbolNames']:
+        raise ParserException(operatorNamesElement,
+                "Operator name '%(operatorName)s' conflicts with previously-defined symbol." % locals())
+      # I'm not sure that we should be protecting the operator names in an EX or IP operator (except within
+      # an operators element)
+      
+      # self.globalNameSpace['symbolNames'].add(operatorName)
+    
+    operatorTemplate.operatorNames = operatorNames
+    
+    if isinstance(operatorTemplate, ConstantEXOperatorTemplate):
+      vectorName = operatorTemplate.id + "_field"
+      
+      operatorVectorTemplate = VectorElementTemplate(
+        name = vectorName, field = operatorTemplate.field,
+        parent = operatorTemplate, initialBasis = operatorTemplate.operatorBasis,
+        type = 'real',
+        **self.argumentsToTemplateConstructors
+      )
+      
+      operatorVectorTemplate.needsInitialisation = False
+      operatorVectorTemplate.components = operatorNames[:]
+      operatorTemplate.operatorVector = operatorVectorTemplate
+      
+      operatorDefinitionCodeBlock.targetVector = operatorVectorTemplate
+    
+    vectorName = operatorTemplate.id + "_result"
+    resultVector = VectorElementTemplate(
+      name = vectorName, field = operatorTemplate.field,
+      parent = operatorTemplate, initialBasis = operatorTemplate.field.defaultCoordinateBasis,
+      type = 'real',
+      **self.argumentsToTemplateConstructors
+    )
+    
+    resultVector.needsInitialisation = False
+    resultVector.components = resultVectorComponents
+    operatorTemplate.resultVector = resultVector
+    resultVector.basesNeeded.add(resultVector.field.basisForBasis(operatorTemplate.operatorBasis))
+    
+    if isinstance(operatorTemplate, NonConstantEXOperatorTemplate):
+      operatorDefinitionCodeBlock.targetVector = resultVector
+    
+    return operatorTemplate
+  
+  
+  def parseCrossPropagationOperatorElement(self, operatorTemplate, operatorElement):
+    operatorDefinitionCodeBlock = operatorTemplate.primaryCodeBlock
+    
+    operatorDefinitionCodeBlock.basis = operatorDefinitionCodeBlock.field.defaultCoordinateBasis
+    
+    if not operatorElement.hasAttribute('algorithm'):
+      raise ParserException(operatorElement, "Missing 'algorithm' attribute.")
+    
+    algorithmString = operatorElement.getAttribute('algorithm').strip()
+    
+    crossIntegratorClass = None
+    crossStepperClass = None
+    algorithmSpecificOptionsDict = {}
+    
+    integrator = operatorTemplate.parent.parent
+    if algorithmString != 'SI' and isinstance(integrator, Integrators.FixedStepWithCross.FixedStepWithCross):
+      raise ParserException(operatorElement, "The SIC integrator can only be used with SI cross-propagators.  Please change the algorithm of this cross-propagator to 'SI'.")      
+    
+    if algorithmString == 'RK4':
+      crossIntegratorClass = Integrators.FixedStep.FixedStep
+      crossStepperClass = Integrators.RK4Stepper.RK4Stepper
+    elif algorithmString == 'SI':
+      crossIntegratorClass = Integrators.FixedStep.FixedStep
+      crossStepperClass = Integrators.SIStepper.SIStepper
+      if operatorElement.hasAttribute('iterations'):
+        algorithmSpecificOptionsDict['iterations'] = RegularExpressionStrings.integerInString(operatorElement.getAttribute('iterations'))
+        if algorithmSpecificOptionsDict['iterations'] < 1:
+          raise ParserException(operatorElement, "Iterations element must be 1 or greater (default 3).")
+      
+    else:
+      raise ParserException(operatorElement, "Unknown cross-propagation algorithm '%(algorithmString)s'.\n"
+                                             "The options are 'SI' or 'RK4'." % locals())
+    
+    crossIntegratorTemplate = crossIntegratorClass(stepperClass = crossStepperClass,
+                                                   xmlElement = operatorElement,
+                                                   parent = operatorTemplate,
+                                                   **self.argumentsToTemplateConstructors)
+    crossIntegratorTemplate.cross = True
+    crossIntegratorTemplate.homeBasis = operatorDefinitionCodeBlock.basis
+    
+    self.applyAttributeDictionaryToObject(algorithmSpecificOptionsDict, crossIntegratorTemplate)
+    
+    if not operatorElement.hasAttribute('propagation_dimension'):
+      raise ParserException(operatorElement, "Missing 'propagation_dimension' attribute.")
+    
+    propagationDimensionName = operatorElement.getAttribute('propagation_dimension').strip()
+    fullField = operatorTemplate.field
+    if not fullField.hasDimensionName(propagationDimensionName):
+      fullFieldName = fullField.name
+      raise ParserException(operatorElement, "The '%(propagationDimensionName)s' dimension must be a dimension of the\n"
+                                             "'%(fullFieldName)s' field in order to cross-propagate along this dimension."
+                                             % locals())
+    
+    operatorTemplate.propagationDimension = propagationDimensionName
+    
+    propagationDimension = fullField.dimensionWithName(propagationDimensionName)
+    
+    propDimRep = propagationDimension.representations[0]
+    
+    if not propDimRep.type == 'real' or not isinstance(propDimRep, UniformDimensionRepresentation):
+      raise ParserException(operatorElement, "Cannot integrate in the '%(propagationDimensionName)s' direction as it is an integer-valued dimension.\n"
+                                             "Cross-propagators can only integrate along normal dimensions." % locals())
+    
+    fieldPropagationDimensionIndex = fullField.indexOfDimension(propagationDimension)
+    # Set the stepCount -- this is the lattice for this dimension minus 1 because we know the value at the starting boundary
+    crossIntegratorTemplate.stepCount = ''.join(['(', propDimRep.globalLattice, ' - 1)'])
+    
+    boundaryConditionElement = operatorElement.getChildElementByTagName('boundary_condition')
+    
+    if not boundaryConditionElement.hasAttribute('kind'):
+      raise ParserException(boundaryConditionElement, "The 'boundary_condition' tag must have a kind='left' or kind='right' attribute.")
+    
+    kindString = boundaryConditionElement.getAttribute('kind').strip().lower()
+    
+    if kindString == 'left':
+      operatorTemplate.propagationDirection = '+'
+    elif kindString == 'right':
+      operatorTemplate.propagationDirection = '-'
+    else:
+      raise ParserException(boundaryConditionElement, "Unknown boundary condition kind '%(kindString)s'. Options are 'left' or 'right'." % locals())
+    
+    # Set the step
+    crossIntegratorTemplate.step = operatorTemplate.propagationDirection + propDimRep.stepSize
+    
+    integrationVectorsElement = operatorElement.getChildElementByTagName('integration_vectors')
+    integrationVectorNames = Utilities.symbolsInString(integrationVectorsElement.innerText(), xmlElement = integrationVectorsElement)
+    operatorTemplate.integrationVectorsEntity = ParsedEntity(integrationVectorsElement, integrationVectorNames)
+    
+    # We need to construct the field element for the reduced dimensions
+    reducedField = operatorTemplate.reducedDimensionFieldForField(fullField)
+    operatorTemplate.reducedField = reducedField
+    
+    operatorContainer = OperatorContainerTemplate(field = reducedField,
+                                                  parent = crossIntegratorTemplate,
+                                                  **self.argumentsToTemplateConstructors)
+    crossIntegratorTemplate.intraStepOperatorContainers.append(operatorContainer)
+    
+    boundaryConditionCodeBlock = _UserLoopCodeBlock(
+      field = reducedField, xmlElement = boundaryConditionElement,
+      parent = operatorTemplate, basis = operatorDefinitionCodeBlock.basis,
+      **self.argumentsToTemplateConstructors)
+    boundaryConditionCodeBlock.dependenciesEntity = self.parseDependencies(boundaryConditionElement, optional=True)
+    
+    operatorTemplate.codeBlocks['boundaryCondition'] = boundaryConditionCodeBlock
+    
+    
+    # Now we can construct the delta a operator for the cross-propagation integrator
+    # When we parse our operator elements (if we have any), the delta a operator will also be constructed
+    self.parseOperatorElements(operatorElement, operatorContainer, crossIntegratorTemplate)
+    
+    operatorTemplate.crossPropagationIntegrator = crossIntegratorTemplate
+    operatorContainer.deltaAOperator.codeBlocks['operatorDefinition'].basis = operatorDefinitionCodeBlock.basis
+    operatorTemplate.crossPropagationIntegratorDeltaAOperator = operatorContainer.deltaAOperator
+  
+  
+  def parseOutputElement(self, simulationElement):
+    outputElement = simulationElement.getChildElementByTagName('output')
+    
+    outputFeature = Features.Output.Output(parent = self.simulation, xmlElement = outputElement,
+                                           **self.argumentsToTemplateConstructors)
+    
+    formatName = 'hdf5'
+    
+    if outputElement.hasAttribute('format'):
+      formatName = outputElement.getAttribute('format').strip().lower()
+    
+    outputFormatClass = Features.OutputFormat.OutputFormat.outputFormatClasses.get(formatName)
+    if not outputFormatClass:
+      validFormats = ', '.join(["'%s'" % formatType for formatType in Features.OutputFormat.OutputFormat.outputFormatClasses.keys()])
+      raise ParserException(outputElement, "Breakpoint format attribute '%(formatName)s' unknown.\n"
+                                           "The valid formats are %(validFormats)s." % locals())
+    
+    if not outputElement.hasAttribute('filename'):
+      filename = self.globalNameSpace['simulationName']
+    elif not outputElement.getAttribute('filename').strip():
+      raise ParserException(outputElement, "Filename attribute is empty.")
+    else:
+      filename = outputElement.getAttribute('filename').strip()
+    
+    if filename.lower().endswith('.xsil'):
+      index = filename.lower().rindex('.xsil')
+      filename = filename[0:index]
+    
+    outputFormat = outputFormatClass(parent = outputFeature, xmlElement = outputElement,
+                                     **self.argumentsToTemplateConstructors)
+    outputFeature.filename = filename
+    outputFeature._children.append(outputFormat)
+    outputFeature.outputFormat = outputFormat
+    
+    geometryTemplate = self.globalNameSpace['geometry']
+    
+    geometryDimRepNameMap = {}
+    for dim in geometryTemplate.transverseDimensions: # Skip the propagation dimension
+        for dimRep in dim.representations:
+            geometryDimRepNameMap[dimRep.name] = dim
+    
+    
+    momentGroupElements = outputElement.getChildElementsByTagNames(['group', 'sampling_group'], optional=True)
+    for momentGroupNumber, momentGroupElement in enumerate(momentGroupElements):
+      samplingElement = momentGroupElement if momentGroupElement.tagName == 'sampling_group' else momentGroupElement.getChildElementByTagName('sampling')
+      
+      momentGroupTemplate = MomentGroupTemplate(number = momentGroupNumber, xmlElement = momentGroupElement,
+                                                parent = self.simulation,
+                                                **self.argumentsToTemplateConstructors)
+      
+      samplingFieldTemplate = FieldElementTemplate(name = momentGroupTemplate.name + "_sampling", parent = self.simulation,
+                                                   **self.argumentsToTemplateConstructors)
+      momentGroupTemplate.samplingField = samplingFieldTemplate
+      
+      outputFieldTemplate = FieldElementTemplate(name = momentGroupTemplate.name + "_output", parent = self.simulation,
+                                                 **self.argumentsToTemplateConstructors)
+      momentGroupTemplate.outputField = outputFieldTemplate
+      
+      momentGroupTemplate.computedVectors.update(self.parseComputedVectorElements(samplingElement, momentGroupTemplate))
+      
+      sampleCount = 0
+      
+      if samplingElement.hasAttribute('initial_sample'):
+        if samplingElement.getAttribute('initial_sample').strip().lower() == 'yes':
+          momentGroupTemplate.requiresInitialSample = True
+          sampleCount = 1
+      
+      transformMultiplexer = self.globalNameSpace['features']['TransformMultiplexer']
+      samplingDimension = Dimension(name = self.globalNameSpace['globalPropagationDimension'],
+                                    transverse = False,
+                                    transform = transformMultiplexer.transformWithName('none'),
+                                    parent = momentGroupTemplate.outputField,
+                                    **self.argumentsToTemplateConstructors)
+      
+      propagationDimRep = NonUniformDimensionRepresentation(name = self.globalNameSpace['globalPropagationDimension'],
+                                                            type = 'real',
+                                                            runtimeLattice = sampleCount,
+                                                            parent = samplingDimension,
+                                                            **self.argumentsToTemplateConstructors)
+      samplingDimension.addRepresentation(propagationDimRep)
+      
+      momentGroupTemplate.outputField.dimensions = [samplingDimension]
+      
+      basisString = samplingElement.getAttribute('basis') if samplingElement.hasAttribute('basis') else ''
+      basisStringComponents = basisString.split()
+      dimensionsNeedingLatticeUpdates = {}
+      sampleBasis = []
+      singlePointSamplingBasis = []
+      
+      for component in basisStringComponents:
+        # Each component of the basis string is to be of the form 'dimRepName(numberOfPoints)'
+        # where dimRepName is a name of a dimension in a basis,
+        #       numberOfPoints is a non-negative integer,
+        # and where the '(numberOfPoints)' part is optional.  If not provided, 
+        # it defaults to sampling all points in that dimension.
+        
+        if '(' in component:
+          dimRepName, latticeString = component.split('(')
+        else:
+          dimRepName, latticeString = component, ''
+        sampleBasis.append(dimRepName)
+        latticeString = latticeString.strip(')')
+        if not dimRepName in geometryDimRepNameMap:
+            raise ParserException(samplingElement,
+                      "'%(dimRepName)s' is not recognised as a valid basis specifier." % locals())
+        geometryDimension = geometryDimRepNameMap[dimRepName]
+        dimRep = [rep for rep in geometryDimension.representations if rep.name == dimRepName][0]
+        lattice = dimRep.runtimeLattice # Default
+        if latticeString:
+          try:
+            lattice = int(latticeString)
+          except ValueError, err:
+            raise ParserException(samplingElement,
+                        "Unable to interpret '%(latticeString)s' as an integer." % locals())
+        
+        if not isinstance(lattice, basestring):
+          if not lattice >= 0:
+            raise ParserException(samplingElement,
+                      "Lattice size '%(latticeString)s' must be positive." % locals())
+        
+        # Now we check that the number of sample points is not larger than the 
+        # number of points in the geometry lattice. Also check that the number of sample
+        # points divide the geometry lattice (if sampling in coord space) or is smaller
+        # than the total number of points (spectral or auxillary space).
+        # There is an additional complication if run-time validation has been selected, and
+        # the number of lattice points is a variable to be passed in at run time, rather than
+        # a number given at the script parse-time.
+        # If this is the case, set up the checks (e.g. sample points must be less than
+        # total lattice points etc) to be done at run-time rather than here.
+
+        # Check to see if run-time validation has been selected
+        runTimeValidationSelected = False
+        if 'Validation' in self.globalNameSpace['features']:
+          if self.globalNameSpace['features']['Validation'].runValidationChecks == True:
+            runTimeValidationSelected = True
+
+        geometryLattice = dimRep.runtimeLattice
+
+        if isinstance(geometryLattice, basestring):
+          if runTimeValidationSelected == False:
+            # Theoretically this code won't execute, since the only way geometryLattice
+            # can be a run-time variable at this point is if run-time validation is
+            # on. Still, make the check in case something is screwed up.
+            raise ParserException(samplingElement, 
+                    "Sampling: Geometry lattice not a number, and run-time validation is off! \n"
+                    "This shouldn't happen. Please report this to xmds-devel at lists.sourceforge.net.\n")
+          else:
+            # Run-time validation is on, so we need to set up some run-time checks
+            # to make sure the geometry lattice size given at run-time is sensible for
+            # sampling that has been specified.
+            validationFeature = self.globalNameSpace['features']['Validation']
+            validationFeature.validationChecks.append("""
+              if (%(lattice)s > %(geometryLattice)s)
+                _LOG(_ERROR_LOG_LEVEL, "ERROR: Can't sample more points in dimension '%(dimRepName)s' than\\n"
+                                       "there are points in the full dimension.\\n"
+                                       "%%i > %%i.\\n", (int)%(lattice)s, (int)%(geometryLattice)s);""" % locals())
+            
+            # Coordinate space: the number of sample points must divide the number of geometry points
+            if issubclass(dimRep.tag, dimRep.tagForName('coordinate')):
+              validationFeature.validationChecks.append("""
+                if ( (%(lattice)s > 0) && (%(geometryLattice)s %% %(lattice)s !=0) )
+                  _LOG(_ERROR_LOG_LEVEL, "ERROR: The number of sampling lattice points (%%i) must divide the number\\n"
+                                       "of lattice points on the simulation grid (%%i).\\n", (int)%(lattice)s, (int)%(geometryLattice)s);\n""" % locals())
+
+        else:
+          # the geometry lattice is a number, not a run-time variable, so we can do the 
+          # following checks now 
+          if lattice > geometryLattice:
+            raise ParserException(samplingElement,
+                        "Can't sample more points in dimension '%(dimRepName)s' than there are points in the full dimension.\n"
+                        "%(lattice)i > %(geometryLattice)i." % locals())
+          if issubclass(dimRep.tag, dimRep.tagForName('coordinate')):
+            # Coordinate space: the number of sample points must divide the number of geometry points
+            if lattice > 0 and not (geometryLattice % lattice) == 0:
+              raise ParserException(samplingElement,
+                        "The number of sampling lattice points (%(lattice)i) must divide the number "
+                        "of lattice points on the simulation grid (%(geometryLattice)i)." % locals())
+            # For spectral / auxiliary space, the number of lattice points just needs to be smaller than
+            # the total number of points, something we have already checked.
+        
+        # This code sets up the sampling for various dimensions. There are three
+        # cases: lattice>1, lattice=1, and lattice=0, where lattice is the number
+        # of points to sample on the full geometry lattice.
+        # If lattice>1 and lattice<geometry lattice, we're subsampling.
+        # We have to note that in the case where the geometry lattice is specified
+        # at runtime (so it's a string, not a number), if no number was explicitly
+        # given for the sampling lattice, then it inherits the string as a value
+        # from the geometry lattice. In this case, we don't need to subsample, but
+        # we should be aware that lattice can be a string.
+        if isinstance(lattice, basestring) or lattice > 1:
+          outputFieldDimension = geometryDimension.copy(parent = outputFieldTemplate)
+          if geometryLattice != lattice:
+             # Yes, we are subsampling
+             dimensionsNeedingLatticeUpdates[outputFieldDimension.name] = lattice
+          samplingFieldTemplate.dimensions.append(outputFieldDimension.copy(parent = samplingFieldTemplate))
+          outputFieldTemplate.dimensions.append(outputFieldDimension)
+        elif lattice == 1:
+          # In this case, we don't want the dimension in either the moment group, or the sampling field.
+          # But we do want it in the sampling basis, we have to add it at the end
+          singlePointSamplingBasis.append(dimRepName)
+        elif lattice == 0:
+          # In this case, the dimension only belongs to the sampling field because we are integrating over it.
+          # Note that we previously set the lattice of the dimension to be the same as the number
+          # of points in this dimension according to the geometry element.
+          samplingFieldTemplate.dimensions.append(geometryDimension.copy(parent = samplingFieldTemplate))
+          
+      
+      samplingFieldTemplate.sortDimensions()
+      outputFieldTemplate.sortDimensions()
+      
+      driver = self.globalNameSpace['features']['Driver']
+      
+      sampleBasis = samplingFieldTemplate.basisForBasis(driver.canonicalBasisForBasis(tuple(sampleBasis)))
+      outputBasis = momentGroupTemplate.outputField.basisForBasis(
+        (propagationDimRep.canonicalName,) + sampleBasis
+      )
+      momentGroupTemplate.singlePointSamplingBasis = driver.canonicalBasisForBasis(tuple(singlePointSamplingBasis))
+      
+      if formatName == 'hdf5':
+        # HDF5 doesn't like writing out data when the order of dimensions in the file and
+        # in memory aren't the same. It's slow. So we make sure that we sample in the same
+        # order that we would write out to file. But only for HDF5 as this requires extra
+        # MPI Transpose operations at each sample.
+        sampleBasis = driver.canonicalBasisForBasis(sampleBasis, noTranspose = True)
+        outputBasis = driver.canonicalBasisForBasis(outputBasis, noTranspose = True)
+      
+      
+      for dimName, lattice in dimensionsNeedingLatticeUpdates.items():
+        for field, basis in [(samplingFieldTemplate, sampleBasis), (outputFieldTemplate, outputBasis)]:
+          field.dimensionWithName(dimName).setReducedLatticeInBasis(lattice, basis)
+      
+      # end looping over dimension elements.  
+      momentGroupTemplate.outputBasis = outputBasis
+      
+      rawVectorTemplate = VectorElementTemplate(
+        name = 'raw', field = momentGroupTemplate.outputField,
+        initialBasis = momentGroupTemplate.outputBasis, type = 'real',
+        **self.argumentsToTemplateConstructors
+      )
+      momentGroupTemplate.rawVector = rawVectorTemplate
+      
+      momentsElement = samplingElement.getChildElementByTagName('moments')
+      momentNames = Utilities.symbolsInString(momentsElement.innerText(), xmlElement = momentsElement)
+      
+      if not momentNames:
+        raise ParserException(momentsElement, "Moments element should be a list of moment names")
+      
+      for momentName in momentNames:
+        if momentName in self.globalNameSpace['symbolNames']:
+          raise ParserException(momentsElement, 
+                  "'%(momentName)s' cannot be used as a moment name because it clashes with "
+                  "a previously-defined variable." % locals())
+        
+        ## We don't add the momentName to the symbol list because they can be used by other moment groups safely
+        rawVectorTemplate.components.append(momentName)
+      
+      samplingCodeBlock = _UserLoopCodeBlock(
+        field = samplingFieldTemplate, xmlElement = samplingElement,
+        parent = momentGroupTemplate, basis = sampleBasis,
+        **self.argumentsToTemplateConstructors)
+      samplingCodeBlock.dependenciesEntity = self.parseDependencies(samplingElement)
+      if samplingCodeBlock.dependenciesEntity.xmlElement.hasAttribute("basis"):
+          parserWarning(samplingCodeBlock.dependenciesEntity.xmlElement, "'basis' attribute is ignored on the <dependencies> tag in a sampling block. "
+                        "Instead specify the basis on the <sampling_group> tag itself.")
+      # The raw vector will be needed during looping
+      samplingCodeBlock.targetVector = rawVectorTemplate
+      momentGroupTemplate.codeBlocks['sampling'] = samplingCodeBlock
+      
+      if not samplingCodeBlock.codeString:
+        raise ParserException(samplingElement, "The CDATA section for the sampling code must not be empty.")
+      
+      operatorContainer = self.parseFilterElements(samplingElement, parent=momentGroupTemplate, optional=True)
+      if operatorContainer:
+        momentGroupTemplate.operatorContainers.append(operatorContainer)
+      
+      operatorElements = samplingElement.getChildElementsByTagName('operator', optional=True)
+      if operatorElements:
+        operatorContainer = OperatorContainerTemplate(field = samplingFieldTemplate,
+                                                      # Point the proxies for the shared code etc at
+                                                      # the moment group object's sampling code, the sampling space, etc.
+                                                      sharedCodeBlockKeyPath = 'parent.codeBlocks.sampling',
+                                                      parent = momentGroupTemplate,
+                                                      **self.argumentsToTemplateConstructors)
+        
+        momentGroupTemplate.operatorContainers.append(operatorContainer)
+        for operatorElement in operatorElements:
+          kindString = operatorElement.getAttribute('kind').strip().lower()
+          if not kindString in ('functions', 'ex'):
+            raise ParserException(operatorElement, "Unrecognised operator kind '%(kindString)s'. "
+                                                   "The only valid operator kinds in sampling elements are 'functions' and 'ex'." % locals())
+          
+          if kindString == 'ex':
+            # We can't handle constant=yes in this case, so we'll just replace it with the value we can support
+            operatorElement.setAttribute('constant', 'no')
+          operatorTemplate = self.parseOperatorElement(operatorElement, operatorContainer)
+          if isinstance(operatorTemplate, ConstantEXOperatorTemplate):
+            raise ParserException(operatorElement, "You cannot have a constant EX operator in moment group sampling. Try constant=\"no\".")
+      
+      
+      
+      # We have now dealt with the sampling element, and now need to deal with the processing element.
+      # TODO: Implement processing element.
+      processingElement = momentGroupElement.getChildElementByTagName('post_processing', optional=True)
+      
+      processedVectorTemplate = VectorElementTemplate(
+        name = 'processed', field = outputFieldTemplate, initialBasis = momentGroupTemplate.outputBasis,
+        type = 'real',
+        **self.argumentsToTemplateConstructors
+      )
+      momentGroupTemplate.processedVector = processedVectorTemplate
+      
+      if not processingElement:
+        momentGroupTemplate.hasPostProcessing = False
+        processedVectorTemplate.components = rawVectorTemplate.components[:]
+        rawVectorTemplate.type = 'real'
+      else:
+        momentGroupTemplate.hasPostProcessing = True
+  
+
diff --git a/xpdeint/XMDSScriptLexer.py b/xpdeint/XMDSScriptLexer.py
new file mode 100644
index 0000000..bf7325e
--- /dev/null
+++ b/xpdeint/XMDSScriptLexer.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+XMDSScriptLexer.py
+
+Created by Graham Dennis on 2008-11-18.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from pygments.lexers.web import XmlLexer
+from pygments.lexers.compiled import CLexer
+from pygments.lexer import bygroups, using
+from pygments.token import Comment, Keyword, Name
+
+class XMDSCodeLexer(CLexer):
+  """
+  A lexer for the code sections of XMDS/xpdeint simulation scripts.
+  
+  Only to be used by the XMDSScriptLexer.
+  """
+  
+  name = 'XMDS-Code'
+  aliases = ['xmds-code', 'xpdeint-code']
+  filenames = []
+  
+  xmds_types = set(['complex', 'fftw_complex'])
+  xmds_functions = set(['rcomplex', 'pcomplex', 'real', 'imag', 'mod', 'mod2',
+                        'arg', 'conj', 'c_exp', 'c_log', 'c_sqrt'])
+  xmds_constants = set(['i'])
+  
+  def get_tokens_unprocessed(self, text):
+    for index, token, value in CLexer.get_tokens_unprocessed(self, text):
+      if token is Name:
+        if value in self.xmds_types:
+          token = Keyword.Type
+        elif value in self.xmds_functions:
+          token = Name.Function
+        elif value in self.xmds_constants:
+          token = Keyword.Constant
+      yield index, token, value
+      
+  
+
+class XMDSScriptLexer(XmlLexer):
+  """
+  A lexer for XMDS/xpdeint simulation scripts.
+  """
+  
+  
+  name = 'XMDS'
+  aliases = ['xmds2','xmds','xpdeint']
+  filenames = ['*.xmds']
+  
+  cdataRule = (r'(\<\!\[CDATA\[)(.*?)(\]\]\>)',
+               bygroups(Comment.Preproc, using(XMDSCodeLexer), Comment.Preproc))
+  
+  tokens = XmlLexer.tokens.copy()
+  tokens['root'].insert(0, cdataRule)
+  
+  def analyse_text(text):
+    if XmlLexer.analyse_text(text) > 0 and '<simulation' in text:
+      return 0.8
+  
+
diff --git a/xpdeint/XSILFile.py b/xpdeint/XSILFile.py
new file mode 100644
index 0000000..75edc31
--- /dev/null
+++ b/xpdeint/XSILFile.py
@@ -0,0 +1,272 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+XSILFile.py
+
+Created by Graham Dennis on 2008-06-18.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+import os
+from xml.dom import minidom
+import xpdeint.minidom_extras
+
+h5py = None
+
+numpy = None
+
+def require_h5py():
+  global h5py
+  if not h5py:
+    import h5py
+
+def require_numpy():
+  global numpy
+  if not numpy:
+    import numpy
+
+
+class XSILData(object):
+  def __init__(self, independentVariables, dependentVariables):
+    self.independentVariables = independentVariables
+    self.dependentVariables = dependentVariables
+  
+
+class XSILDataASCII(XSILData):
+  format = 'ascii'
+  
+  def __init__(self, independentVariables, dependentVariables, dataString):
+    XSILData.__init__(self, independentVariables, dependentVariables)
+    if dataString: self.parseDataString(dataString)
+  
+  def parseDataString(self, dataString):
+    require_numpy()
+    
+    lines = dataString.splitlines()
+    del dataString
+    varCount = len(self.independentVariables) + len(self.dependentVariables)
+    indepSize = reduce(int.__mul__, [indVar['length'] for indVar in self.independentVariables])
+    result = numpy.empty(indepSize*varCount)
+    for lineNum, line in enumerate(lines):
+      result[lineNum*varCount:((lineNum+1)*varCount)] = numpy.fromstring(line, numpy.float64, sep=' ')
+    assert len(result) == indepSize*varCount
+    
+    result = result.reshape(indepSize, varCount)
+    independentGeometry = []
+    
+    for varNum, ivar in enumerate(self.independentVariables):
+      independentGeometry.append(ivar['length'])
+      ivar['array'] = numpy.unique(result[:, varNum])
+      assert len(ivar['array']) == ivar['length']
+    for varNum, dvar in enumerate(self.dependentVariables):
+      a = result[:, varNum + len(self.independentVariables)]
+      dvar['array'] = a.reshape(*independentGeometry)
+    
+  
+
+class XSILDataBinary(XSILData):
+  """Class representing the binary data."""
+  
+  format = 'binary'
+  
+  def __init__(self, independentVariables, dependentVariables, uLong, precision, encoding, dataFile, loadData = True):
+    XSILData.__init__(self, independentVariables, dependentVariables)
+    self.filename = os.path.split(dataFile)[1]
+    
+    assert uLong in ['uint32', 'uint64']
+    assert precision in ['single', 'double']
+    assert encoding in ['BigEndian', 'LittleEndian']
+    self.uLong = uLong
+    self.precision = precision
+    self.encoding = encoding
+    
+    if loadData: self.parseDataFile(uLong, precision, encoding, dataFile)
+  
+  def parseDataFile(self, uLong, precision, encoding, dataFile):
+    assert uLong in ['uint32', 'uint64']
+    assert precision in ['single', 'double']
+    assert encoding in ['BigEndian', 'LittleEndian']
+    
+    require_numpy()
+    
+    fd = file(dataFile, 'rb')
+    
+    byteorder = {'LittleEndian': '<', 'BigEndian': '>'}[encoding]
+    unsignedLongTypeString = {'uint32': 'u4', 'uint64': 'u8'}[uLong]
+    realTypeString = {'single': 'f4', 'double': 'f8'}[precision]
+    
+    ulongDType = numpy.dtype(byteorder + unsignedLongTypeString)
+    floatDType = numpy.dtype(byteorder + realTypeString)
+    
+    independentGeometry = []
+    
+    for independentVariable in self.independentVariables:
+      size = numpy.fromfile(fd, dtype=ulongDType, count=1)
+      independentGeometry.append(size)
+      assert size == independentVariable['length']
+      a = numpy.fromfile(fd, dtype=floatDType, count=size)
+      independentVariable['array'] = a
+    
+    if len(independentGeometry) == 0:
+      independentGeometry.append(1)
+    
+    for dependentVariable in self.dependentVariables:
+      size = numpy.fromfile(fd, dtype=ulongDType, count=1)
+      a = numpy.fromfile(fd, dtype=floatDType, count=size)
+      assert a.size == size, "Data file %s has incorrect size. Variable '%s' wasn't written completely." % (dataFile, dependentVariable['name'])
+      dependentVariable['array'] = a.reshape(*independentGeometry)
+    
+  
+
+class XSILDataHDF5(XSILData):
+  """Class representing HDF5 data output."""
+  
+  format = 'hdf5'
+  
+  def __init__(self, independentVariables, dependentVariables, groupName, dataFile, loadData = True):
+    XSILData.__init__(self, independentVariables, dependentVariables)
+    self.filename = os.path.split(dataFile)[1]
+    self.groupName = groupName
+    
+    if loadData: self.parseDataFile(groupName, dataFile)
+  
+  def parseDataFile(self, groupName, dataFile):
+    require_h5py()
+    f = h5py.File(dataFile, 'r')
+    
+    subgroup = f[groupName]
+    
+    for independentVariable in self.independentVariables:
+      independentVariable['array'] = subgroup[independentVariable['name']].value
+    
+    for dependentVariable in self.dependentVariables:
+      dependentVariable['array'] = subgroup[dependentVariable['name']].value
+    
+    # Now wasn't that easy.
+  
+
+
+class XSILObject(object):
+  def __init__(self, name, data):
+    self.name = name
+    self.data = data
+    if data:
+      self.independentVariables = data.independentVariables
+      self.dependentVariables = data.dependentVariables
+  
+
+
+class XSILFile(object):
+  def __init__(self, filename, loadData=True):
+    """Create an `XSILFile` object.
+    `filename` is the filename of the XSIL file, and `loadData` specifies whether or not the
+    data in the XSIL file should be loaded (if not, just the metadata is loaded).
+    `loadData` can have one of the following values:
+    
+    - ``True`` or ``'all'``: load all data
+    - ``False`` or ``'none'``: load no data
+    - ``'ascii'``: load only data stored in ASCII format
+    - ``'binary'``: load only data stored in binary format
+    - ``'hdf5'``: load only data stored in HDF5 format
+    """
+    if not isinstance(loadData, basestring):
+      # loadData is True or False
+      loadData = {True: 'all', False: 'none'}[loadData]
+    else:
+      loadData = loadData.lower()
+    assert loadData in ['all', 'ascii', 'binary', 'hdf5', 'none']
+    self.filename = filename
+    self.xsilObjects = []
+    
+    xmlDocument = minidom.parse(filename)
+    simulationElement = xmlDocument.getChildElementByTagName('simulation')
+    xsilElements = simulationElement.getChildElementsByTagName('XSIL')
+    for xsilElement in xsilElements:
+      xsilName = xsilElement.getAttribute('Name')
+      
+      paramElement = xsilElement.getChildElementByTagName('Param')
+      assert paramElement.hasAttribute('Name') and paramElement.getAttribute('Name') == 'n_independent'
+      nIndependentVariables = int(paramElement.innerText())
+      
+      arrayElements = xsilElement.getChildElementsByTagName('Array')
+      assert len(arrayElements) == 2
+      
+      variableArrayElement = arrayElements[0]
+      dataArrayElement = arrayElements[1]
+      
+      assert variableArrayElement.hasAttribute('Name') and variableArrayElement.getAttribute('Name') == 'variables'
+      dimElement = variableArrayElement.getChildElementByTagName('Dim')
+      nVariables = int(dimElement.innerText())
+      nDependentVariables = nVariables - nIndependentVariables
+      assert nDependentVariables > 0
+      streamElement = variableArrayElement.getChildElementByTagName('Stream')
+      variableNames = streamElement.innerText().strip().split(' ')
+      assert len(variableNames) == nVariables
+      
+      # We do str(name) here to convert unicode objects to str objects
+      # It seems that numpy doesn't like unicode strings.
+      independentVariables = [{'name': str(name)} for name in variableNames[0:nIndependentVariables]]
+      dependentVariables = [{'name': str(name)} for name in variableNames[nIndependentVariables:]]
+      
+      assert len(dependentVariables) == nDependentVariables
+      
+      dimElements = dataArrayElement.getChildElementsByTagName('Dim')
+      assert len(dimElements) == nIndependentVariables + 1
+      
+      for dimIndex, dimElement in enumerate(dimElements):
+        if dimIndex < nIndependentVariables:
+          independentVariables[dimIndex]['length'] = int(dimElement.innerText())
+        else:
+          assert int(dimElement.innerText()) == nVariables
+      
+      streamElement = dataArrayElement.getChildElementByTagName('Stream')
+      metalinkElement = streamElement.getChildElementByTagName('Metalink')
+      format = metalinkElement.getAttribute('Format').strip()
+      
+      data = None
+      
+      objectFilename = None
+      
+      if format == 'Binary':
+        uLong = metalinkElement.getAttribute('UnsignedLong').strip()
+        precision = metalinkElement.getAttribute('precision').strip()
+        encoding = metalinkElement.getAttribute('Encoding').strip()
+        objectFilename = streamElement.innerText().strip()
+        filename = os.path.join(os.path.split(filename)[0], objectFilename)
+        loadBinaryData = False
+        if loadData in ['all', 'binary']: loadBinaryData = True
+        data = XSILDataBinary(independentVariables, dependentVariables, uLong, precision, encoding, filename,
+                                    loadData = loadBinaryData)
+      elif format == 'Text':
+        dataString = None
+        if loadData in ['all', 'ascii']: dataString = streamElement.innerText().strip()
+        
+        data = XSILDataASCII(independentVariables, dependentVariables, dataString)
+      elif format == 'HDF5':
+        loadHDFData = False
+        if loadData in ['all', 'hdf5']: loadHDFData = True
+        objectFilename = streamElement.innerText().strip()
+        filename = os.path.join(os.path.split(filename)[0], objectFilename)
+        groupName = metalinkElement.getAttribute('Group').strip()
+        data = XSILDataHDF5(independentVariables, dependentVariables, groupName, filename, loadData = loadHDFData)
+      
+      self.xsilObjects.append(XSILObject(xsilName, data))
+    
+  
+
+
diff --git a/xpdeint/_MomentGroupElement.py b/xpdeint/_MomentGroupElement.py
new file mode 100644
index 0000000..aa94d87
--- /dev/null
+++ b/xpdeint/_MomentGroupElement.py
@@ -0,0 +1,157 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_MomentGroupElement.py
+
+This contains all the pure-python code for MomentGroupElement.tmpl
+
+Created by Graham Dennis on 2007-10-18.
+
+Copyright (c) 2007-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.ScriptElement import ScriptElement
+from xpdeint.ParserException import ParserException
+
+from xpdeint.Function import Function
+from xpdeint.Utilities import lazy_property
+
+class _MomentGroupElement (ScriptElement):
+  def __init__(self, number, *args, **KWs):
+    self.number = number
+    self.name = 'mg' + str(self.number)
+    
+    ScriptElement.__init__(self, *args, **KWs)
+    
+    # Set default variables
+    self.requiresInitialSample = False
+    self.getVar('momentGroups').append(self)
+    self.computedVectors = set()
+    self.operatorContainers = []
+    
+    sampleFunctionName = ''.join(['_', self.id, '_sample'])
+    sampleFunction = Function(name = sampleFunctionName,
+                              args = [],
+                              implementation = self.sampleFunctionContents)
+    self.functions['sample'] = sampleFunction
+    
+    processFunctionName = ''.join(['_', self.id, '_process'])
+    processFunction = Function(name = processFunctionName,
+                               args = [],
+                               implementation = self.processFunctionContents)
+    self.functions['process'] = processFunction
+    
+    writeOutFunctionName = ''.join(['_', self.id, '_write_out'])
+    writeOutFunction = Function(name = writeOutFunctionName,
+                                args = [('FILE*', '_outfile')],
+                                implementation = self.writeOutFunctionContents)
+    self.functions['writeOut'] = writeOutFunction
+  
+  @property
+  def children(self):
+    children = super(_MomentGroupElement, self).children
+    children.extend(self.computedVectors)
+    children.extend(self.operatorContainers)
+    return children
+  
+  @lazy_property
+  def propDimRep(self):
+    return self.outputField.dimensionWithName(self.propagationDimension).inBasis(self.outputBasis)
+  
+  # Do we actually need to allocate the moment group vector?
+  # We may not need to allocate the raw vector if there is no
+  # processing of the raw vector to be done before it is written.
+  @lazy_property
+  def rawVectorNeedsToBeAllocated(self):
+    # If we have processing code, then we definitely need a raw vector
+    if self.hasattr('processingCode') and self.processingCode: return True
+    
+    dict = {'returnValue': False, 'MomentGroup': self}
+    featureOrdering = ['Driver']
+    
+    # This function allows the features to determine whether or not the raw vector
+    # needs to be allocated by changing the value of the 'returnValue' key in dict.
+    # The features should only change the value to true if they need the raw vector
+    # allocated. Otherwise, they shouldn't touch the value.
+    self.insertCodeForFeatures('rawVectorNeedsToBeAllocated', featureOrdering, dict)
+    
+    return dict['returnValue']
+  
+  def bindNamedVectors(self):
+    super(_MomentGroupElement, self).bindNamedVectors()
+    
+    if not self.rawVectorNeedsToBeAllocated:
+      self.outputField.managedVectors.remove(self.processedVector)
+      self.processedVector.remove()
+      self.processedVector = self.rawVector
+    
+  
+  def addSamplePoints(self, samplePoints):
+    self.outputField.dimensionWithName(self.propagationDimension).inBasis(self.outputBasis).runtimeLattice += samplePoints
+  
+  def preflight(self):
+    super(_MomentGroupElement, self).preflight()
+    for dependency in self.codeBlocks['sampling'].dependencies:
+      if self.hasPostProcessing and dependency.type == 'complex':
+        self.rawVector.type = 'complex'
+    
+    # Throw out the propagation dimension if it only contains a single sample
+    if self.outputField.hasDimensionName(self.propagationDimension):
+      propDimRep = self.propDimRep
+      if propDimRep.runtimeLattice == 1:
+        self.propDimRep = None
+        singlePointDimension = self.outputField.dimensionWithName(self.propagationDimension)
+        self.outputField.dimensions.remove(singlePointDimension)
+        singlePointDimension.remove()
+        self.outputBasis = tuple(b for b in self.outputBasis if not b is propDimRep.canonicalName)
+        for vector in self.outputField.vectors:
+          basesNeeded = set(tuple(b for b in basis if not b is propDimRep.canonicalName) for basis in vector.basesNeeded)
+          vector.basesNeeded.clear()
+          vector.basesNeeded.update(basesNeeded)
+          vector.field._basisForBasisCache.clear()
+          vector.initialBasis = tuple(b for b in vector.initialBasis if not b is propDimRep.canonicalName)
+    
+    geometry = self.getVar('geometry')
+    singlePointSamplingDims = [dim.name for dim in geometry.dimensions \
+        if any(dimRep.canonicalName in self.singlePointSamplingBasis for dimRep in dim.representations)]
+    
+    loopingDimensionNames = set([dim.name for dim in self.samplingField.dimensions]).union(singlePointSamplingDims)
+    for dependency in self.codeBlocks['sampling'].dependencies:
+      missingLoopingDimensionNames = set(dim.name for dim in dependency.field.dimensions).difference(loopingDimensionNames)
+      if missingLoopingDimensionNames:
+        raise ParserException(self.codeBlocks['sampling'].xmlElement,
+                    "The dimension(s) %s have not been included in the basis specification.  "
+                    "They are needed by the vector '%s'." % (', '.join(missingLoopingDimensionNames), dependency.name))
+    
+    self.codeBlocks['sampling'].basis = (self.propagationDimension,) \
+                                      + self.codeBlocks['sampling'].basis \
+                                      + self.singlePointSamplingBasis
+    
+    outputFieldID = self.outputField.id
+    propagationDimension = self.propagationDimension
+    self.codeBlocks['sampling'].loopArguments['indexOverrides'] = \
+      {propagationDimension: {self.outputField: "_%(outputFieldID)s_index_%(propagationDimension)s" % locals()}}
+    
+    self.integratingComponents = bool(loopingDimensionNames.difference(set([dim.name for dim in self.outputField.dimensions])))
+    if self.integratingComponents:
+      # We are integrating over dimensions, and therefore the rawVector is an index override
+      self.codeBlocks['sampling'].loopArguments['vectorOverrides'] = [self.rawVector]
+    
+  
+  
+
+
diff --git a/xpdeint/_ScriptElement.py b/xpdeint/_ScriptElement.py
new file mode 100644
index 0000000..d69c4c1
--- /dev/null
+++ b/xpdeint/_ScriptElement.py
@@ -0,0 +1,568 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_ScriptElement.py
+
+This contains all the pure-python code for ScriptElement.tmpl
+
+Created by Graham Dennis on 2007-10-17.
+Copyright (c) 2007-2012 Graham Dennis.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+
+import textwrap
+
+from Cheetah.Template import Template
+from xpdeint.ParserException import ParserException
+
+from xpdeint.Utilities import lazy_property
+
+class _ScriptElement (Template):
+  class LoopingOrder(object):
+    MemoryOrder = 1
+    StrictlyAscendingOrder = 2
+    StrictlyDescendingOrder = 3
+  
+  argumentsToTemplateConstructors = {}
+  # Initialise the callOnceGuards to be empty
+  _callOnceGuards = set()
+  _callOncePerInstanceGuards = dict()
+  
+  simulation = None
+  
+  @classmethod
+  def resetGuards(cls):
+    """
+    Reset the flags used by the `CallOnceGuards` function decorators to ensure that
+    various functions are only called once.
+    
+    Calling these functions causes all of these flags to be reset to `False` causing
+    the functions protected by the `CallOnceGuards` function decorators to be able
+    to be called again.
+    """
+    _ScriptElement._callOnceGuards.clear()
+    for instanceGuardSet in _ScriptElement._callOncePerInstanceGuards.itervalues():
+      instanceGuardSet.clear()
+  
+  @property
+  def _driver(self):
+    """
+    Return the simulation driver, but cache the result in a variable shared between
+    all `_ScriptElement` instances.
+    """
+    _ScriptElement._driver = self.getVar('features')['Driver']
+    return _ScriptElement._driver
+  
+  
+  _ScriptElement_haveCalledInit = False
+  
+  def __init__(self, *args, **KWs):
+    # If we have a diamond-inheritence, this function could be called more than once
+    # And that would be bad. Let's check for that case, and return if it is the case.
+    # Template can deal with being called more than once, but some of the code below
+    # wouldn't be safe called more than once
+    if self._ScriptElement_haveCalledInit:
+      return
+    
+    self._ScriptElement_haveCalledInit = True
+    
+    localKWs = self.extractLocalKWs(['xmlElement', 'parent'], KWs)
+    
+    Template.__init__(self, *args, **KWs)
+    
+    self.getVar('templates').add(self)
+    
+    # Only set the dependencies attribute if it isn't taken
+    # care of elsewhere
+    if not hasattr(type(self), 'dependencies'):
+      self.dependencies = set()
+    
+    assert 'parent' in localKWs
+    self.parent = localKWs['parent']
+    
+    if self.parent and self.parent == self.simulation:
+      self.simulation._children.append(self)
+    self.xmlElement = localKWs.get('xmlElement', None)
+    self.dependenciesEntity = None
+    self.functions = {}
+    self.codeBlocks = {}
+    self._haveBeenRemoved = False
+    
+    self._children = []
+    
+    if hasattr(type(self), 'globalNameSpaceName'):
+      globalNameSpace = KWs['searchList'][0]
+      globalNameSpace[self.globalNameSpaceName] = self
+    
+    # Create the entry in the callOnceGuards
+    _ScriptElement._callOncePerInstanceGuards[self] = set()
+  
+  @lazy_property
+  def id(self):
+    """
+    Return a string that should uniquely identify this object.
+    
+    The string returned will be appropriate for use as a ``C`` variable name and
+    will begin with and underscore.
+    """
+    if not self.parent or not self.parent.id:
+      return self.name
+    else:
+      return '_'.join([self.parent.id, self.name])
+  
+  @property
+  def children(self):
+    result = self._children[:]
+    result.extend(self.codeBlocks.values())
+    return result
+  
+  @lazy_property
+  def propagationDimension(self):
+    """
+    Return the name of the current propagation dimension for this template. Note that this
+    does not need to be the same as the propagation dimension for the entire simulation because
+    cross-propagation works by using a standard integrator, but by setting a different propagation
+    dimension.
+    """
+    
+    if self.parent:
+      return self.parent.propagationDimension
+    
+    return self.getVar("globalPropagationDimension")
+  
+  @lazy_property
+  def propagationDirection(self):
+    """
+    Return a string representing the sign of the direction of propagation. This string will
+    either be '+' or '-'. Note that usually this will be '+', however it will be '-' for
+    cross-propagators that have a 'right' boundary condition.
+    
+    This method is used in the creation of the `propagationDirection` property.
+    """
+    if self.parent:
+      return self.parent.propagationDirection
+    else:
+      return '+'
+  
+  @lazy_property
+  def scriptLineNumber(self):
+    return self.xmlElement.lineNumberForCDATASection()
+  
+  def hasattr(self, attrName):
+    """
+    Helper method to return whether or not the instance has the attribute `attrName`.
+    The difference between this method and the Python `hasattr` function is that this one
+    will raise an exception if the attribute `attrName` does exist but accessing it would
+    cause an exception to be raised.
+    """
+    try:
+      getattr(self, attrName)
+    except AttributeError, err:
+      if hasattr(type(self), attrName):
+        raise
+      return False
+    else:
+      return True
+  
+  # Default description of the template
+  def description(self):
+    return type(self).__name__
+  
+  # Includes
+  def includes(self):
+    pass
+  
+  # Defines needed at the start of the simulation
+  def defines(self):
+    pass
+  
+  # Globals needed at the start of the simulation
+  def globals(self):
+    pass
+  
+  # Function prototypes
+  def functionPrototypes(self):
+    if not self.functions:
+      return
+    return ''.join([f.prototype() for f in self.functions.itervalues() if f.predicate()])
+  
+  # Function implemenations
+  def functionImplementations(self):
+    if not self.functions:
+      return
+    return '\n\n'.join([f.implementation() for f in self.functions.itervalues() if f.predicate()])
+  
+  # Define a whole bunch of static versions of these functions
+  def static_includes(self):
+    pass
+  
+  def static_defines(self):
+    pass
+  
+  def static_globals(self):
+    pass
+  
+  def static_functionPrototypes(self):
+    pass
+  
+  def static_functionImplementations(self):
+    pass
+  
+  def allocate(self):   return self.implementationsForChildren('allocate')
+  def free(self):       return self.implementationsForChildren('free')
+  
+  def initialise(self): return self.implementationsForChildren('initialise')
+  def finalise(self):   return self.implementationsForChildren('finalise')
+  
+  # Insert code for a list of features by calling a named function
+  def insertCodeForFeatures(self, functionName, featureList, dict = None, reverse = False):
+    """
+    This function is at the core of the 'Feature' system used by xpdeint. Its design is kinda
+    like aspect-oriented programming in that the idea is to separate code that is logically separate
+    but required in a large number of places. The idea behind this system is the creation of a 
+    number of named 'insertion points' in the generated C++ code where features can insert code
+    if they need to. Usually these insertion points come in pairs called 'someFunctionNameBegin'
+    and 'someFunctionNameEnd' that are at balanced points in the code.
+    
+    The 'Feature' system diverges from the usual Aspect-Oriented programming approach in that when
+    you specify the insertion point, you also specify the features that you want to be able to insert
+    code at that point and the order in which they should be able to insert code. This allows for a
+    sensible balancing of the inserted code such that when code from multiple features is inserted
+    at a 'someFunctionBegin' insertion point, by calling the `insertCodeForFeaturesInReverseOrder`
+    method at the 'someFunctionEnd' insertion point, the code necessary for these features at this
+    insertion point is inserted in the opposite order than for 'someFunctionBegin'.
+    
+    The optional `dict` argument can be used to pass additional variables to the features. The 
+    `reverse` argument should not be used, it is used internally by `insertCodeForFeaturesInReverseOrder`.
+    """
+    featureDictionary = self.getVar('features')
+    
+    if not dict:
+        dict = {}
+    
+    if self.hasattr('bannedFeatures') and self.bannedFeatures:
+      # Check if any of the features in the featureList are in the bannedFeatures
+      bannedFeatures = self.bannedFeatures
+      featureList = filter(lambda x: x not in bannedFeatures, featureList)
+    
+    result = []
+    filt = self._CHEETAH__currentFilter
+    dict['featureList'] = featureList
+    
+    # Loop over the features that we should include
+    for featureName in featureList:
+      if not featureDictionary.has_key(featureName):
+        # If we don't have the feature, then there isn't much we can do
+        continue
+      
+      # Grab the feature
+      feature = featureDictionary[featureName]
+      
+      # If the function doesn't exist, we're done
+      if not feature.hasattr(functionName):
+        continue
+      
+      # Get functionName on feature by name
+      featureFunction = getattr(feature, functionName)
+      
+      # Get the extra indent value, if we were passed one in the dict object
+      extraIndent = dict.get('extraIndent', 0)
+      
+      # The caller object is self.
+      dict['caller'] = self
+      
+      # Call the function with optional dictionary
+      featureResult = featureFunction(dict)
+      
+      if not reverse:
+        # If we're doing this in the forward order, then we use the initial indent as the indent for the result
+        result.append(filt(featureResult, extraIndent=extraIndent))
+      else:
+        # If we're doing this in reverse order, then we use the final indent as the indent for the result
+        result.append(filt(featureResult, extraIndent=dict.get('extraIndent', 0)))
+    
+    return ''.join(result)
+  
+  # Insert code for a list of features (in reverse order) by calling a named function
+  def insertCodeForFeaturesInReverseOrder(self, functionName, featureList, dict = None):
+    # Create a reversed feature list
+    reversedFeatureList = featureList[:]
+    reversedFeatureList.reverse()
+    
+    return self.insertCodeForFeatures(functionName, reversedFeatureList, dict, reverse=True)
+  
+  # Insert contents of function for self, classes and children
+  def implementationsForFunctionName(self, functionName, *args, **KWs):
+    """
+    Helper function to call the function `functionName` for this instance, its
+    class and its children and return the combined result as a string.
+    """
+    result = []
+    blankLineSeparator = ''
+    staticFunctionName = 'static_' + functionName
+    
+    for attrName in [staticFunctionName, functionName]:
+      if self.hasattr(attrName):
+        function = getattr(self, attrName)
+        functionOutput = function(*args, **KWs)
+        if functionOutput and not functionOutput.isspace():
+          result.append(blankLineSeparator)
+          blankLineSeparator = '\n'
+          result.append(functionOutput)
+    
+    for child in self.children:
+      childFunctionOutput = child.implementationsForFunctionName(functionName, *args, **KWs)
+      if childFunctionOutput and not childFunctionOutput.isspace():
+        result.append(blankLineSeparator)
+        blankLineSeparator = '\n'
+        result.append(childFunctionOutput)
+    
+    return ''.join(result)
+  
+  # Insert contents of function for children
+  def implementationsForChildren(self, functionName, *args, **KWs):
+    if not self.hasattr('children'):
+      return
+    result = []
+    blankLineSeparator = ''
+    for child in self.children:
+      if child.hasattr(functionName) and callable(getattr(child, functionName)):
+        childFunction = getattr(child, functionName)
+        childFunctionOutput = childFunction(*args, **KWs)
+        if childFunctionOutput and not childFunctionOutput.isspace():
+          result.append(blankLineSeparator)
+          blankLineSeparator = '\n'
+          result.append(childFunctionOutput)
+    
+    return ''.join(result)
+  
+  def bindNamedVectors(self):
+    """
+    Part of the 'preflight' system. Once templates have been parsed, a template should
+    implement this method if it needs to bind the name of a vector to the actual vector
+    object itself and check if it even exists.
+    """
+    if self.dependenciesEntity:
+      self.dependencies.update(self.vectorsFromEntity(self.dependenciesEntity))
+    
+    for codeBlock in self.codeBlocks.itervalues():
+      # Warning: This means that codeBlocks will have bindNamedVectors() called twice.
+      codeBlock.bindNamedVectors()
+    
+  
+  def preflight(self):
+    """
+    Part of the 'preflight' system. This function is guaranteed to be called after `bindNamedVectors`
+    has been called on all templates. This is where other post-parsing code goes before the simulation
+    is converted to a C++ source file.
+    """
+    if hasattr(self, 'uselib'):
+      self.getVar('simulationUselib').update(self.uselib)
+    if hasattr(self, 'buildVariant'):
+      buildVariant = self.getVar('simulationBuildVariant')
+      if buildVariant and not self.buildVariant in buildVariant:
+        raise ParserException(self, "Internal Error. More than one build variant is trying to be used.\n"
+                                    "Please report this error to %s\n" % self.getVar('bugReportAddress'))
+      buildVariant.add(self.buildVariant)
+    
+  
+  def vectorsFromEntity(self, entity):
+    """
+    Given the `ParsedEntity` `entity`, return the set of vectors corresponding to the list of names
+    in the value of the XML element contained by the entity.
+    """
+    vectors = set()
+    vectorDictionary = dict([(vector.name, vector) for vector in self.getVar('simulationVectors')])
+    
+    ancestors = []
+    currObject = self
+    while currObject:
+      ancestors.append(currObject)
+      currObject = currObject.parent
+    
+    for vectorName in entity.value:
+      vector = None
+      replacementVector = None
+      if self.parent:
+        replacementVector = self.parent.vectorForVectorName(vectorName, vectorDictionary)
+      
+      if not vectorName in vectorDictionary:
+        raise ParserException(entity.xmlElement, "Unknown vector '%(vectorName)s'." % locals())
+      else:
+        vector = vectorDictionary[vectorName]
+      
+      if not (vector.parent == vector.field or vector.parent in ancestors):
+        raise ParserException(entity.xmlElement, "Cannot access vector '%(vectorName)s' here. It is not available in this scope." % locals())
+      
+      if replacementVector:
+        vectors.add(replacementVector)
+      else:
+        vectors.add(vector)
+    return vectors
+  
+  def vectorForVectorName(self, vectorName, vectorDictionary):
+    """
+    Function that can be used by a template to override the mapping of vector names to vectors for children
+    """
+    if self.parent:
+      return self.parent.vectorForVectorName(vectorName, vectorDictionary)
+  
+  def basisIndexForBasis(self, basis):
+    transformMultiplier = self.getVar('features')['TransformMultiplexer']
+    return transformMultiplier.basesNeeded.index(basis)
+  
+  def transformVectorsToBasis(self, vectors, basis):
+    result = []
+    for vector in vectors:
+      if not vector.needsTransforms:
+        continue
+      vectorBasis = vector.field.basisForBasis(basis)
+      if not vector.isTransformableTo(vectorBasis):
+        raise ParserException(
+          self.xmlElement,
+          "Cannot satisfy dependence on vector '%s' because it cannot be transformed to the required basis (%s). "
+          "The vector's initial basis is (%s)." % (vector.name, ', '.join(vectorBasis), ', '.join(vector.initialBasis))
+        )
+      basisString = ', '.join(vectorBasis)
+      basisIndex = self.basisIndexForBasis(vectorBasis)
+      result.extend([vector.functions['basisTransform'].call(new_basis=basisIndex), ' // (', basisString, ')\n'])
+    return ''.join(result)
+  
+  def registerVectorsRequiredInBasis(self, vectors, basis):
+    for vector in vectors:
+      vector.basesNeeded.add(vector.field.basisForBasis(basis))
+  
+  def remove(self):
+    """
+    Remove the template from various global lists that it may have got itself into. This method
+    should be called if a template is no longer needed and should be deleted.
+    """
+    self.getVar('templates').discard(self)
+    
+    for someIterable in (self.parent.children, self.getVar('fields'),
+                         self.getVar('simulationVectors'), self.getVar('momentGroups')):
+      while self in someIterable:
+        someIterable.remove(self)
+    
+    if self.hasattr('children'):
+      for child in self.children:
+        child.remove()
+    
+    self._haveBeenRemoved = True
+  
+  def templateObjectFromStringWithTemplateVariables(self, templateString, templateVars):
+    """
+    Return a Cheetah template object (using the appropriate settings) for `templateString`
+    with the dictionary `templateVars` as variables available in the template.
+    """
+    settings = {'directiveStartToken': '@',
+                'commentStartToken': '@#',
+                'multiLineCommentStartToken': '@*',
+                'multiLineCommentEndToken': '*@'
+               }
+    return Template(source = templateString,
+                    searchList = [templateVars],
+                    compilerSettings = settings)
+  
+  
+  def evaluationOrderForVectors(self, vectors, static, predicate = lambda x: True):
+    """
+    Return the ordering for the noise vectors and computed vectors in `vectors` taking into account
+    any dependencies between the computed vectors.
+    """
+    
+    def checkSelfConsistentVectors(vectors, static):
+      #We check that all noise vectors are static or dynamic, as requested.
+      for nv in [nv for nv in vectors if nv.isNoise and nv.static != static]:
+        if static:
+            raise ParserException(self.xmlElement, "Dynamic noises (Wiener and Jump processes) cannot be used outside of integration elements.\n"
+                                                   "Perhaps %s should be a static noise (like 'Gaussian' or 'Poissonian')?" % nv.name)
+        if not static:
+            raise ParserException(self.xmlElement, "Static noises cannot be used inside integration elements.\n"
+                                                   "Perhaps %s should be a dynamic noise (like 'Wiener' or 'Jump')?" % nv.name)
+          
+    stack = []
+    
+    checkSelfConsistentVectors(vectors, static)
+    
+    # The algorithm here is basically to start with any given vector and traverse
+    # the dependencies recursively until a vector with no dependencies is found,
+    # then it is added to the list of ordered dependencies. If, during a traversal,
+    # a vector is encountered twice (the history of traversed dependencies is stored
+    # in the stack variable), then a circular dependency chain has been hit and a
+    # ParserException will be raised. Once all of a vector's dependencies have been
+    # added to the orderedDependencies, the vector itself can be added.
+    # Finally, if a vector is already in orderedDependencies, we don't need to consider
+    # its dependencies as they will have already been considered when considering the
+    # dependencies of another vector that depends on the first vector. Clear as mud?
+    
+    def orderedDependenciesForVectors(vectors):
+      """
+      Helper function that is called recursively to return the ordering for the computed
+      vectors such that all dependencies of a computed vector are evaluated first. Any
+      circular dependencies will result in a ParserException.
+      """
+      orderedDependencies = []
+      checkSelfConsistentVectors(vectors, static)
+      
+      for v in vectors:
+        # If v is in the ordering, then it has already been taken care of
+        if v in orderedDependencies:
+          continue
+        
+        # If v is on the stack, then we have a circular dependency
+        if v in stack:
+          startIndex = stack.index(v)
+          conflictList = stack[startIndex:]
+          conflictList.append(v)
+          raise ParserException(self.xmlElement, "Cannot construct ordering for computed vector dependencies.\n"
+                                                 "The vectors causing the conflict are: %s." % ' --> '.join([v.name for v in conflictList]))
+        
+        # v is not on the stack, so we are safe
+        # Put v on the stack
+        stack.append(v)
+        # Add the dependencies for v at the end of my dependencies if they aren't there already
+        newDependencies = orderedDependenciesForVectors([u for u in v.dependencies if predicate(u)])
+        orderedDependencies.extend([v for v in newDependencies if not v in orderedDependencies])
+        # Pop v off the stack and put it on our orderedDependencies
+        orderedDependencies.append(stack.pop())
+      
+      return orderedDependencies
+    
+    return orderedDependenciesForVectors([v for v in vectors if predicate(v)])
+  
+  def dynamicVectorsNeedingPrecalculationForOperatorContainers(self, operatorContainers):
+    """
+    Return a set of computed vectors that `operatorContainers` need to be precomputed
+    before executing the operator containers.
+    """
+    result = set()
+    for operatorContainer in operatorContainers:
+      result.update(operatorContainer.dynamicVectorsNeedingPrecalculation)
+    return result
+  
+  @staticmethod
+  def extractLocalKWs(legalKWs, KWs):
+    result = {}
+    for key in KWs.copy():
+      if key in legalKWs:
+        result[key] = KWs[key]
+        del KWs[key]
+    return result
+    
+  
+  def wrapArray(self, array):
+    return '\n  ' + textwrap.fill(', '.join([repr(float(e)) for e in array]), subsequent_indent='  ') + '\n  '
+  
diff --git a/xpdeint/_UserCodeBlock.py b/xpdeint/_UserCodeBlock.py
new file mode 100644
index 0000000..35bdefb
--- /dev/null
+++ b/xpdeint/_UserCodeBlock.py
@@ -0,0 +1,365 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+_UserCodeBlock.py
+
+Created by Graham Dennis on 2008-09-11.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xpdeint.ScriptElement import ScriptElement
+
+from xpdeint.Utilities import lazy_property
+from xpdeint import CodeParser
+from xpdeint.CodeParser import CodeParserException
+from xpdeint.CallOnceGuards import callOncePerInstanceGuard
+
+from xpdeint.Vectors.ComputedVector import ComputedVector
+
+import textwrap
+
+class _UserCodeBlock(ScriptElement):
+  def __init__(self, **KWs):
+    localKWs = self.extractLocalKWs(['codeString'], KWs)
+    
+    ScriptElement.__init__(self, **KWs)
+    
+    if 'codeString' in localKWs: self.codeString = localKWs.get('codeString')
+  
+  @lazy_property
+  def codeString(self):
+    return self.xmlElement.cdataContents()
+  
+  def transformCodeString(self):
+    CodeParser.checkForIntegerDivision(self)
+    
+    if self.codeString.count('\n'):
+      # Deindent code and add '#line' compiler directives
+      self.addCompilerLineDirectives()
+    
+  
+  def addCompilerLineDirectives(self):
+    """
+    Add the #line compiler directives at the start and end so that
+    any compiler errors are reported in terms of lines in the actual xmds
+    script itself.
+    """
+    result = [textwrap.dedent(self.codeString)]
+    
+    writeLineDirectives = not self.getVar('debug') and self.xmlElement
+    if writeLineDirectives:
+      result.insert(
+        0,
+        '#line %i "%s"\n' % (self.scriptLineNumber, self.getVar('scriptName'))
+      )
+      result.append('\n#line _XPDEINT_CORRECT_MISSING_LINE_NUMBER_\n')
+    self.codeString = ''.join(result)
+  
+  def preflight(self):
+    super(_UserCodeBlock, self).preflight()
+    self.transformCodeString()
+  
+
+class _UserLoopCodeBlock(_UserCodeBlock):
+  def __init__(self, **KWs):
+    localKWs = self.extractLocalKWs(['field', 'basis', 'targetVector', 'loopArguments'], KWs)
+    
+    _UserCodeBlock.__init__(self, **KWs)
+    
+    self.field = localKWs.get('field')
+    self.basis = localKWs.get('basis')
+    
+    self.targetVector = localKWs.get('targetVector', None)
+    self.loopArguments = localKWs.get('loopArguments', {})
+    
+    self.bindNamedVectorsCalled = False
+    self.preflightCalled = False
+    
+    self.prefixCodeString = ''
+    self.postfixCodeString = ''
+  
+  @property
+  def loopCodeString(self):
+    return self.prefixCodeString + self.codeString + self.postfixCodeString
+  
+  def loop(self, codeWrapperFunction = None, **KWs):
+    loopCode = self.loopCodeString
+    if codeWrapperFunction: loopCode = codeWrapperFunction(loopCode)
+    
+    loopKWs = self.loopArguments.copy()
+    loopKWs.update(KWs)
+    
+    result = self.transformVectorsToBasis(self.dependencies, self.basis)
+    if result: result = "// Transforming vectors to basis (%s)\n%s\n" % (', '.join(self.basis), result)
+    loopingVectors = set(self.dependencies)
+    if self.targetVector: loopingVectors.add(self.targetVector)
+    result += self.loopOverFieldInBasisWithVectorsAndInnerContent(self.field, self.basis, loopingVectors, loopCode, **loopKWs)
+    
+    return result
+  
+  @lazy_property
+  def specialTargetsVector(self):
+    # If all dependencies are of type real, then the special targets vector must be real too
+    specialTargetsVectorType = 'complex'
+    if all([v.type == 'real' for v in self.dependencies]):
+      if not self.targetVector or self.targetVector.type == 'real':
+        specialTargetsVectorType = 'real'
+    
+    specialTargetsVector = ComputedVector(name = self.parent.id + "_special_targets", field = self.field,
+                                          parent = self, initialBasis = self.basis,
+                                          type = specialTargetsVectorType, xmlElement = self.xmlElement,
+                                          **self.argumentsToTemplateConstructors)
+    
+    self.field.temporaryVectors.add(specialTargetsVector)
+    
+    specialTargetsVector.integratingComponents = False
+    
+    evaluationCodeBlock = _TargetConstructorCodeBlock(
+      field = self.field, basis = self.basis,
+      parent = specialTargetsVector,
+      **self.argumentsToTemplateConstructors
+    )
+    evaluationCodeBlock.targetVector = specialTargetsVector
+    specialTargetsVector.codeBlocks['evaluation'] = evaluationCodeBlock
+    
+    # Call necessary preflight functions on the special targets vector
+    if self.bindNamedVectorsCalled: specialTargetsVector.bindNamedVectors()
+    if self.preflightCalled:        specialTargetsVector.preflight()
+    
+    self._children.append(specialTargetsVector)
+    
+    return specialTargetsVector
+  
+  def addCodeStringToSpecialTargetsVector(self, codeString, containingCodeSlice):
+    specialTargetsVector = self.specialTargetsVector
+    specialTargetCodeBlock = specialTargetsVector.codeBlocks['evaluation']
+    
+    targetCodeBlocks = specialTargetCodeBlock.targetCodeBlocks
+    codeBlocksWithSameTarget = [codeBlock for codeBlock in targetCodeBlocks if codeBlock.codeString == codeString]
+    if codeBlocksWithSameTarget:
+      evaluationCodeBlock = codeBlocksWithSameTarget[0]
+      targetVariableName = 'target%i' % targetCodeBlocks.index(evaluationCodeBlock)
+    else:
+      evaluationCodeBlock = _UserLoopCodeBlock(
+        field = self.field, basis = self.basis,
+        parent = specialTargetCodeBlock, xmlElement = self.xmlElement,
+        **self.argumentsToTemplateConstructors
+      )
+      evaluationCodeBlock.codeString = codeString
+      # This code block could depend on anything we do
+      evaluationCodeBlock.dependencies.update(self.dependencies)
+      evaluationCodeBlock.scriptLineNumber = self.scriptLineNumber + self.codeString.count('\n', 0, containingCodeSlice.start)
+      targetCodeBlocks.append(evaluationCodeBlock)
+      targetVariableName = 'target%i' % targetCodeBlocks.index(evaluationCodeBlock)
+      specialTargetsVector.components.append(targetVariableName)
+      
+      # Call necessary preflight functions on the code block
+      if self.bindNamedVectorsCalled: evaluationCodeBlock.bindNamedVectors()
+      if self.preflightCalled:        evaluationCodeBlock.preflight()
+    
+    return targetVariableName
+  
+  def fixupNonlocallyAccessedComponents(self):
+    """
+    In user code, the user may refer to parts of a vector nonlocally in integer-valued dimensions.
+    This code translates variables accessed with the ``phi(j: j-3, k:k+5, l:l/2, p:p*p, q:q, r:r)`` notation to a form
+    that can be used in the C++ source file. The form currently used is ``_phi_jklpqr(j-3, k+5, l/2, p*p, q, r)``.
+    
+    This function makes an optimisation where if all dimensions are accessed locally,
+    the ``phi(j: j, k:k, l:l, p:p, q: q, r: r)`` notation is replaced with the string ``phi`` which is a faster
+    way of accessing the local value than through using the ``_phi_jklpqr(...)`` macro.
+    """
+    vectorsToFix = self.dependencies.copy()
+    if self.targetVector: vectorsToFix.add(self.targetVector)
+    
+    nonlocalVariablesCreated = set()
+    
+    vectorOverrides = self.loopArguments.get('vectorOverrides', [])
+    
+    simulationDriver = self.getVar('features')['Driver']
+    for componentName, vector, nonlocalAccessDict, codeSlice in reversed(CodeParser.nonlocalDimensionAccessForVectors(vectorsToFix, self)):
+      availableDimReps = vector.field.inBasis(self.basis)
+      validDimensionNames = [dimRep.name for dimRep in availableDimReps]
+      validDimensionNames.extend([dimRep.name + "_index" for dimRep in availableDimReps])
+      
+      # If the dict is empty, then it probably means something else
+      if not nonlocalAccessDict:
+        continue
+      
+      if vector in vectorOverrides:
+        vectorID = vector.id
+        raise CodeParserException(self, codeSlice.start, "Cannot access vector '%(vectorID)s' non-locally." % locals())
+      
+      # Check that there are no dimensions listed in the nonlocalAccessDict that don't refer to valid
+      # dimensions for this vector
+      
+      for dimName in nonlocalAccessDict.iterkeys():
+        if not dimName in validDimensionNames:
+          raise CodeParserException(self, nonlocalAccessDict[dimName][1], "Component '%s' doesn't have dimension '%s'." % (componentName, dimName))
+      
+      dimRepsNeeded = [dimRep for dimRep in availableDimReps if dimRep.name in nonlocalAccessDict and nonlocalAccessDict[dimRep.name][0] != dimRep.name]
+      dimRepsNeeded.extend([dimRep for dimRep in availableDimReps if dimRep.name + "_index" in nonlocalAccessDict])
+      
+      if not dimRepsNeeded:
+        replacementString = componentName
+      else:
+        # Check that the mpi distributed dimension isn't being accessed nonlocally.
+        if vector.field.isDistributed:
+          for dimRep in dimRepsNeeded:
+            if dimRep.hasLocalOffset:
+              dimRepName = dimRep.name
+              raise CodeParserException(self, nonlocalAccessDict[dimRepName][1],
+                                   "It is illegal to access the dimension '%(dimRepName)s' nonlocally because it is being distributed with MPI.\n"
+                                   "Try not using MPI or changing the order of your dimensions." % locals())
+        
+        nonlocalAccessVariableName = '_%s_' % componentName
+        nonlocalAccessVariableName += ''.join([dimRep.name for dimRep in dimRepsNeeded])
+        
+        if not nonlocalAccessVariableName in nonlocalVariablesCreated:
+          # Populate with whatever we have set for us if it's there.
+          indexOverrides = self.loopArguments.get('indexOverrides', {}).copy()
+          for dimRep in dimRepsNeeded:
+            indexOverrides[dimRep.name] = {vector.field: dimRep.loopIndex}
+          
+          argumentsString = ', '.join([dimRep.loopIndex for dimRep in dimRepsNeeded])
+          vectorID = vector.id
+          componentNumber = vector.components.index(componentName)
+          defineString = "#define %(nonlocalAccessVariableName)s(%(argumentsString)s) " % locals()
+          
+          nonlocalAccessString = "_active_%(vectorID)s[%(componentNumber)s + (0" % locals()
+          
+          for dimRep in vector.field.inBasis(self.basis):
+            termString = self.explicitIndexPointerTermForVectorAndDimRepWithFieldAndBasis(vector, dimRep, self.field, self.basis, indexOverrides)
+            nonlocalAccessString += termString.replace('\n', ' \\\n')
+          nonlocalAccessString += ') * _%(vectorID)s_ncomponents]' % locals()
+          
+          defineString += nonlocalAccessString + '\n'
+          undefineString = "#undef %(nonlocalAccessVariableName)s\n" % locals()
+          
+          featureDict = {
+            'vector': vector,
+            'componentName': componentName,
+            'availableDimReps': availableDimReps,
+            'dimRepsNeeded': dimRepsNeeded,
+            'nonlocalAccessVariableName': nonlocalAccessVariableName,
+            'nonlocalAccessString': nonlocalAccessString,
+            'defineString': defineString,
+            'undefineString': undefineString
+          }
+          
+          featureOrdering = ['Diagnostics']
+          
+          self.insertCodeForFeatures('nonlocalAccess', featureOrdering, featureDict)
+          
+          self.prefixCodeString += featureDict['defineString']
+          self.postfixCodeString += featureDict['undefineString']
+          nonlocalVariablesCreated.add(nonlocalAccessVariableName)
+        
+        arguments = []
+        for dimRep in dimRepsNeeded:
+          accessViaIndex = not dimRep.name in nonlocalAccessDict
+          dimRepVariableName = dimRep.name if not accessViaIndex else dimRep.name + "_index"
+          accessString = nonlocalAccessDict[dimRepVariableName][0]
+          dimRepName = dimRep.name
+          
+          if not accessViaIndex:
+            argumentValue = dimRep.nonlocalAccessIndexFromStringForFieldInBasis(accessString, self.field, self.basis)
+            if not argumentValue:
+              raise CodeParserException(self, nonlocalAccessDict[dimRep.name][1],
+                                   "Cannot access the '%(dimRepName)s' dimension nonlocally with the string '%(accessString)s'. Check the documentation." % locals())
+          else:
+            argumentValue = accessString
+          
+          arguments.append('/* %(dimRepVariableName)s => %(accessString)s */ (%(argumentValue)s)' % locals())
+        argumentsString = ', '.join(arguments)
+        replacementString = '%(nonlocalAccessVariableName)s(%(argumentsString)s)' % locals()
+      
+      # Replace the phi(j => j + 7) string with the appropriate string
+      # i.e. _phi_j(j + 7)
+      self.codeString = self.codeString[:codeSlice.start] + replacementString + self.codeString[codeSlice.stop:]
+    
+  
+  def transformCodeString(self):
+    """Modify the user code as necessary."""
+    super(_UserLoopCodeBlock, self).transformCodeString()
+    self.fixupNonlocallyAccessedComponents()
+    
+  
+  @callOncePerInstanceGuard
+  def bindNamedVectors(self):
+    # This function would be called twice otherwise because it gets called specially
+    # by the _ScriptElement implementation of bindNamedVectors
+    super(_UserLoopCodeBlock, self).bindNamedVectors()
+    self.bindNamedVectorsCalled = True
+  
+  @callOncePerInstanceGuard
+  def preflight(self):
+    super(_UserLoopCodeBlock, self).preflight()
+    
+    vectors = set(self.dependencies)
+    if self.targetVector:
+      vectors.add(self.targetVector)
+    
+    basis = self.basis
+    self.registerVectorsRequiredInBasis(vectors, basis)
+    
+    self.preflightCalled = True
+  
+
+class _TargetConstructorCodeBlock(_UserLoopCodeBlock):
+  def __init__(self, **KWs):
+    _UserLoopCodeBlock.__init__(self, **KWs)
+    
+    self.targetCodeBlocks = []
+  
+  scriptLineOffset = 0
+  
+  @property
+  def children(self):
+    children = super(_TargetConstructorCodeBlock, self).children
+    children.extend(self.targetCodeBlocks)
+    return children
+  
+  @property
+  def dependencies(self):
+    dependencies = set()
+    # Add all the dependencies of all target code blocks together
+    for targetCodeBlock in self.targetCodeBlocks:
+      dependencies.update(targetCodeBlock.dependencies)
+    return frozenset(dependencies)
+  
+  @property
+  def loopCodeString(self):
+    prefixString = ''.join([cb.prefixCodeString for cb in self.targetCodeBlocks])
+    writeLineDirectives = not self.getVar('debug')
+    loopStringTemplate = ''
+    if writeLineDirectives: loopStringTemplate += '#line %%(lineNumber)i "%s"\n' % self.getVar('scriptName')
+    loopStringTemplate += 'target%(targetNum)i = %(codeString)s;\n'
+    loopString = ''.join([loopStringTemplate % dict(lineNumber=cb.scriptLineNumber, targetNum=targetNum, codeString=cb.codeString)\
+                            for targetNum, cb in enumerate(self.targetCodeBlocks)])
+    if writeLineDirectives:
+      loopString += '#line _XPDEINT_CORRECT_MISSING_LINE_NUMBER_\n'
+    postfixString = ''.join([cb.postfixCodeString for cb in self.targetCodeBlocks])
+    return prefixString + loopString + postfixString
+  
+  def transformCodeString(self):
+    # This will be done as needed for all child code blocks
+    pass
+  
+  
+  
diff --git a/xpdeint/__init__.py b/xpdeint/__init__.py
new file mode 100644
index 0000000..4287ca8
--- /dev/null
+++ b/xpdeint/__init__.py
@@ -0,0 +1 @@
+#
\ No newline at end of file
diff --git a/xpdeint/includes/dSFMT/dSFMT-params.h b/xpdeint/includes/dSFMT/dSFMT-params.h
new file mode 100644
index 0000000..8eef593
--- /dev/null
+++ b/xpdeint/includes/dSFMT/dSFMT-params.h
@@ -0,0 +1,102 @@
+#ifndef DSFMT_PARAMS_H
+#define DSFMT_PARAMS_H
+
+#if !defined(DSFMT_MEXP)
+#ifdef __GNUC__
+  #warning "DSFMT_MEXP is not defined. I assume DSFMT_MEXP is 19937."
+#endif
+  #define DSFMT_MEXP 19937
+#endif
+/*-----------------
+  BASIC DEFINITIONS
+  -----------------*/
+/** Mersenne Exponent. The period of the sequence 
+ *  is a multiple of 2^DSFMT_MEXP-1.
+ * #define DSFMT_MEXP 19937 */
+/** DSFMT generator has an internal state array of 128-bit integers,
+ * and N is its size. */
+#define DSFMT_N (DSFMT_MEXP / 104)
+/** N32 is the size of internal state array when regarded as an array
+ * of 32-bit integers.*/
+#define DSFMT_N32 (DSFMT_N * 4)
+/** N64 is the size of internal state array when regarded as an array
+ * of 64-bit integers.*/
+#define DSFMT_N64 (DSFMT_N * 2)
+
+/*----------------------
+  the parameters of DSFMT
+  following definitions are in dSFMT-paramsXXXX.h file.
+  ----------------------*/
+/** the pick up position of the array.
+#define DSFMT_POS1 122 
+*/
+
+/** the parameter of shift left as four 32-bit registers.
+#define DSFMT_SL1 18
+ */
+
+/** the parameter of shift left as one 128-bit register. 
+ * The 128-bit integer is shifted by (SL2 * 8) bits. 
+#define DSFMT_SL2 1 
+*/
+
+/** the parameter of shift right as four 32-bit registers.
+#define DSFMT_SR1 11
+*/
+
+/** the parameter of shift right as one 128-bit register. 
+ * The 128-bit integer is shifted by (SL2 * 8) bits. 
+#define DSFMT_SR2 1 
+*/
+
+/** A bitmask, used in the recursion.  These parameters are introduced
+ * to break symmetry of SIMD.
+#define DSFMT_MSK1 (uint64_t)0xdfffffefULL
+#define DSFMT_MSK2 (uint64_t)0xddfecb7fULL
+*/
+
+/** These definitions are part of a 128-bit period certification vector.
+#define DSFMT_PCV1	UINT64_C(0x00000001)
+#define DSFMT_PCV2	UINT64_C(0x00000000)
+*/
+
+#define DSFMT_LOW_MASK  UINT64_C(0x000FFFFFFFFFFFFF)
+#define DSFMT_LOW_MASK32_1 0x000fffffU
+#define DSFMT_LOW_MASK32_2 0xffffffffU
+#define DSFMT_HIGH_CONST UINT64_C(0x3FF0000000000000)
+#define DSFMT_HIGH_CONST32 0x3ff00000U
+
+/* for sse2 */
+#define SSE2_SHUFF 0x4e
+
+#if DSFMT_MEXP == 607
+  #include "dSFMT-params607.h"
+#elif DSFMT_MEXP == 1279
+  #include "dSFMT-params1279.h"
+#elif DSFMT_MEXP == 2281
+  #include "dSFMT-params2281.h"
+#elif DSFMT_MEXP == 4423
+  #include "dSFMT-params4423.h"
+#elif DSFMT_MEXP == 11213
+  #include "dSFMT-params11213.h"
+#elif DSFMT_MEXP == 19937
+  #include "dSFMT-params19937.h"
+#elif DSFMT_MEXP == 44497
+  #include "dSFMT-params44497.h"
+#elif DSFMT_MEXP == 86243
+  #include "dSFMT-params86243.h"
+#elif DSFMT_MEXP == 132049
+  #include "dSFMT-params132049.h"
+#elif DSFMT_MEXP == 216091
+  #include "dSFMT-params216091.h"
+#else
+#ifdef __GNUC__
+  #error "DSFMT_MEXP is not valid."
+  #undef DSFMT_MEXP
+#else
+  #undef DSFMT_MEXP
+#endif
+
+#endif
+
+#endif /* DSFMT_PARAMS_H */
diff --git a/xpdeint/includes/dSFMT/dSFMT-params19937.h b/xpdeint/includes/dSFMT/dSFMT-params19937.h
new file mode 100644
index 0000000..8c0eb56
--- /dev/null
+++ b/xpdeint/includes/dSFMT/dSFMT-params19937.h
@@ -0,0 +1,66 @@
+#ifndef DSFMT_PARAMS19937_H
+#define DSFMT_PARAMS19937_H
+
+#define DSFMT_POS1	36
+#define DSFMT_SL1	29
+#define DSFMT_SL2	1
+#define DSFMT_SR1	7
+#define DSFMT_SR2	16
+#define DSFMT_MSK1	UINT64_C(0x57fbfffdffff575f)
+#define DSFMT_MSK2	UINT64_C(0xffff6febffffffee)
+#define DSFMT_MSK32_1	0x57fbfffdU
+#define DSFMT_MSK32_2	0xffff575fU
+#define DSFMT_MSK32_3	0xffff6febU
+#define DSFMT_MSK32_4	0xffffffeeU
+#define DSFMT_PCV1	UINT64_C(0x0000000000000001)
+#define DSFMT_PCV2	UINT64_C(0x000ec8f3d0b00000)
+#define DSFMT_IDSTR \
+	"dSFMT-19937:36-29-1-7-16:57fbfffdffff575f-ffff6febffffffee"
+
+
+/* PARAMETERS FOR ALTIVEC */
+#if defined(__APPLE__)	/* For OSX */
+    #define ALTI_SL1 	(vector unsigned int)(5, 5, 5, 5)
+    #define ALTI_SL1_PERM \
+	(vector unsigned char)(3,4,5,6,7,29,29,29,11,12,13,14,15,0,1,2)
+    #define ALTI_SL1_MSK \
+	(vector unsigned int)(0xffffffffU,0xe0000000U,0xffffffffU,0xe0000000U)
+    #define ALTI_SL2_PERM \
+	(vector unsigned char)(1,2,3,4,5,6,7,31,9,10,11,12,13,14,15,0)
+    #define ALTI_SR1 \
+	(vector unsigned int)(DSFMT_SR1, DSFMT_SR1, DSFMT_SR1, DSFMT_SR1)
+    #define ALTI_SR1_MSK \
+	(vector unsigned int)(0x01fbfffdU,0xffff575fU,0x01ff6febU,0xffffffeeU)
+    #define ALTI_SR2_PERM \
+	(vector unsigned char)(18,18,0,1,2,3,4,5,18,18,8,9,10,11,12,13)
+    #define ALTI_PERM \
+	(vector unsigned char)(8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7)
+    #define ALTI_LOW_MSK \
+	(vector unsigned int)(DSFMT_LOW_MASK32_1, DSFMT_LOW_MASK32_2, \
+		DSFMT_LOW_MASK32_1, DSFMT_LOW_MASK32_2)
+    #define ALTI_HIGH_CONST \
+	(vector unsigned int)(DSFMT_HIGH_CONST32, 0, DSFMT_HIGH_CONST32, 0)
+#else	/* For OTHER OSs(Linux?) */
+    #define ALTI_SL1 	{5, 5, 5, 5}
+    #define ALTI_SL1_PERM \
+	{3,4,5,6,7,29,29,29,11,12,13,14,15,0,1,2}
+    #define ALTI_SL1_MSK \
+	{0xffffffffU,0xe0000000U,0xffffffffU,0xe0000000U}
+    #define ALTI_SL2_PERM \
+	{1,2,3,4,5,6,7,31,9,10,11,12,13,14,15,0}
+    #define ALTI_SR1 \
+	{DSFMT_SR1, DSFMT_SR1, DSFMT_SR1, DSFMT_SR1}
+    #define ALTI_SR1_MSK \
+	{0x01fbfffdU,0xffff575fU,0x01ff6febU,0xffffffeeU}
+    #define ALTI_SR2_PERM \
+	{18,18,0,1,2,3,4,5,18,18,8,9,10,11,12,13}
+    #define ALTI_PERM \
+	{8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7}
+    #define ALTI_LOW_MSK \
+	{DSFMT_LOW_MASK32_1, DSFMT_LOW_MASK32_2, \
+		DSFMT_LOW_MASK32_1, DSFMT_LOW_MASK32_2}
+    #define ALTI_HIGH_CONST \
+	{DSFMT_HIGH_CONST32, 0, DSFMT_HIGH_CONST32, 0}
+#endif
+
+#endif /* DSFMT_PARAMS19937_H */
diff --git a/xpdeint/includes/dSFMT/dSFMT.c b/xpdeint/includes/dSFMT/dSFMT.c
new file mode 100644
index 0000000..6504918
--- /dev/null
+++ b/xpdeint/includes/dSFMT/dSFMT.c
@@ -0,0 +1,781 @@
+/** 
+ * @file dSFMT.c 
+ * @brief double precision SIMD-oriented Fast Mersenne Twister (dSFMT)
+ * based on IEEE 754 format.
+ *
+ * @author Mutsuo Saito (Hiroshima University)
+ * @author Makoto Matsumoto (Hiroshima University)
+ *
+ * Copyright (C) 2007,2008 Mutsuo Saito, Makoto Matsumoto and Hiroshima
+ * University. All rights reserved.
+ *
+ * The new BSD License is applied to this software, see LICENSE.txt
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "dSFMT.h"
+
+/** dsfmt internal state vector */
+dsfmt_t dsfmt_global_data;
+/** dsfmt initialized flag */
+int dsfmt_global_is_initialized = 0;
+/** dsfmt mexp for check */
+static const int dsfmt_mexp = DSFMT_MEXP;
+
+/*----------------
+  STATIC FUNCTIONS
+  ----------------*/
+inline static uint32_t ini_func1(uint32_t x);
+inline static uint32_t ini_func2(uint32_t x);
+inline static void gen_rand_array_c1o2(dsfmt_t *dsfmt, w128_t array[],
+				       int size);
+inline static void gen_rand_array_c0o1(dsfmt_t *dsfmt, w128_t array[],
+				       int size);
+inline static void gen_rand_array_o0c1(dsfmt_t *dsfmt, w128_t array[],
+				       int size);
+inline static void gen_rand_array_o0o1(dsfmt_t *dsfmt, w128_t array[],
+				       int size);
+inline static int idxof(int i);
+static void initial_mask(dsfmt_t *dsfmt);
+static void period_certification(dsfmt_t *dsfmt);
+#if !defined(HAVE_SSE2) && !defined(HAVE_ALTIVEC)
+inline static void lshift128(w128_t *out, const w128_t *in, int shift);
+#endif
+
+#if defined(HAVE_SSE2)
+#  include <emmintrin.h>
+/** mask data for sse2 */
+static __m128i sse2_param_mask;
+/** low mask data for sse2 */
+static __m128i sse2_low_mask;
+/** high constant data for sse2 */
+static __m128i sse2_high_const;
+/** 1 in 64bit for sse2 */
+static __m128i sse2_int_one;
+/** 2.0 double for sse2 */
+static __m128d sse2_double_two;
+/** -1.0 double for sse2 */
+static __m128d sse2_double_m_one;
+
+static void setup_const(void);
+#endif
+
+/**
+ * This function simulate a 32-bit array index overlapped to 64-bit
+ * array of LITTLE ENDIAN in BIG ENDIAN machine.
+ */
+#if defined(DSFMT_BIG_ENDIAN)
+inline static int idxof(int i) {
+    return i ^ 1;
+}
+#else
+inline static int idxof(int i) {
+    return i;
+}
+#endif
+
+/**
+ * This function represents the recursion formula.
+ * @param rr output
+ * @param a a 128-bit part of the internal state array
+ * @param b a 128-bit part of the internal state array
+ * @param c a 128-bit part of the internal state array
+ * @param lung a 128-bit part of the internal state array
+ */
+#if defined(HAVE_ALTIVEC)
+inline static void do_recursion(w128_t *rr,
+				w128_t *a,
+				w128_t *b,
+				w128_t *reg,
+				w128_t *lung) {
+    vector unsigned int r, s, t, u, v, w, x, y, z;
+    const vector unsigned char sl1 = ALTI_SL1;
+    const vector unsigned char sl1_perm = ALTI_SL1_PERM;
+    const vector unsigned int sl1_msk = ALTI_SL1_MSK;
+    const vector unsigned char sl2_perm = ALTI_SL2_PERM;
+    const vector unsigned char sr1 = ALTI_SR1;
+    const vector unsigned int sr1_msk = ALTI_SR1_MSK;
+    const vector unsigned char sr2_perm = ALTI_SR2_PERM;
+    const vector unsigned char perm = ALTI_PERM;
+    const vector unsigned int low_mask = ALTI_LOW_MSK;
+    const vector unsigned int high_const = ALTI_HIGH_CONST;
+
+    x = vec_perm(a->s, (vector unsigned int)sl2_perm, sl2_perm);
+    y = vec_srl(b->s, sr1);
+    y = vec_and(y, sr1_msk);
+    z = vec_perm(reg->s, (vector unsigned int)sl1_perm, sl1_perm);
+    z = vec_sll(z, sl1);
+    z = vec_and(z, sl1_msk);
+    w = vec_perm(reg->s, (vector unsigned int)sr2_perm, sr2_perm);
+    v = vec_perm(lung->s, (vector unsigned int)perm, perm);
+    s = vec_xor(a->s, x);
+    t = vec_xor(y, z);
+    u = vec_xor(w, v);
+    r = vec_xor(s, t);
+    r = vec_xor(r, u);
+    r = vec_and(r, low_mask);
+    lung->s = vec_xor(lung->s, r);
+    rr->s = vec_or(r, high_const);
+}
+#elif defined(HAVE_SSE2)
+/**
+ * This function setup some constant variables for SSE2.
+ */
+static void setup_const(void) {
+    static int first = 1;
+    if (!first) {
+	return;
+    }
+    sse2_param_mask = _mm_set_epi32(DSFMT_MSK32_3, DSFMT_MSK32_4,
+				    DSFMT_MSK32_1, DSFMT_MSK32_2);
+    sse2_low_mask = _mm_set_epi32(DSFMT_LOW_MASK32_1, DSFMT_LOW_MASK32_2,
+				  DSFMT_LOW_MASK32_1, DSFMT_LOW_MASK32_2);
+    sse2_int_one = _mm_set_epi32(0, 1, 0, 1);
+    sse2_high_const = _mm_set_epi32(DSFMT_HIGH_CONST32, 0,
+				    DSFMT_HIGH_CONST32, 0);
+    sse2_double_two = _mm_set_pd(2.0, 2.0);
+    sse2_double_m_one = _mm_set_pd(-1.0, -1.0);
+    first = 0;
+}
+
+/**
+ * This function represents the recursion formula.
+ * @param r output 128-bit
+ * @param a a 128-bit part of the internal state array
+ * @param b a 128-bit part of the internal state array
+ * @param c a 128-bit part of the internal state array
+ * @param d a 128-bit part of the internal state array (I/O)
+ */
+inline static void do_recursion(w128_t *r, w128_t *a, w128_t *b,
+				w128_t *c, w128_t *d) {
+    __m128i v, w, x, y, z;
+    
+    z = a->si;
+    y = _mm_srli_epi64(b->si, DSFMT_SR1);
+    y = _mm_and_si128(y, sse2_param_mask);
+    w = _mm_slli_epi64(c->si, DSFMT_SL1);
+    x = _mm_srli_epi64(c->si, DSFMT_SR2);
+    v = _mm_shuffle_epi32(d->si, SSE2_SHUFF);
+    w = _mm_xor_si128(w, x);
+    v = _mm_xor_si128(v, z);
+    z = _mm_slli_si128(z, DSFMT_SL2);
+    w = _mm_xor_si128(w, y);
+    v = _mm_xor_si128(v, z);
+    v = _mm_xor_si128(v, w);
+    v = _mm_and_si128(v, sse2_low_mask);
+    d->si = _mm_xor_si128(d->si, v);
+    r->si = _mm_or_si128(v, sse2_high_const);
+}
+#else /* standard C */
+/**
+ * This function simulates SIMD 128-bit left shift by the standard C.
+ * The 128-bit integer given in \b in is shifted by (shift * 8) bits.
+ * This function simulates the LITTLE ENDIAN SIMD.
+ * @param out the output of this function
+ * @param in the 128-bit data to be shifted
+ * @param shift the shift value
+ */
+inline static void lshift128(w128_t *out, const w128_t *in, int shift) {
+    out->u[0] = in->u[0] << (shift * 8);
+    out->u[1] = in->u[1] << (shift * 8);
+    out->u[1] |= in->u[0] >> (64 - shift * 8);
+}
+
+/**
+ * This function represents the recursion formula.
+ * @param r output 128-bit
+ * @param a a 128-bit part of the internal state array
+ * @param b a 128-bit part of the internal state array
+ * @param c a 128-bit part of the internal state array
+ * @param lung a 128-bit part of the internal state array (I/O)
+ */
+inline static void do_recursion(w128_t *r, w128_t *a, w128_t *b, w128_t *c,
+				w128_t *lung) {
+    w128_t x;
+
+    lshift128(&x, a, DSFMT_SL2);
+    r->u[0] = a->u[0] ^ x.u[0] ^ ((b->u[0] >> DSFMT_SR1) & DSFMT_MSK1) 
+	^ (c->u[0] >> DSFMT_SR2) ^ (c->u[0] << DSFMT_SL1) ^ lung->u[1];
+    r->u[1] = a->u[1] ^ x.u[1] ^ ((b->u[1] >> DSFMT_SR1) & DSFMT_MSK2) 
+	^ (c->u[1] >> DSFMT_SR2) ^ (c->u[1] << DSFMT_SL1) ^ lung->u[0];
+    r->u[0] &= DSFMT_LOW_MASK;
+    r->u[1] &= DSFMT_LOW_MASK;
+    lung->u[0] ^= r->u[0];
+    lung->u[1] ^= r->u[1];
+    r->u[0] |= DSFMT_HIGH_CONST;
+    r->u[1] |= DSFMT_HIGH_CONST;
+}
+#endif
+
+#if defined(HAVE_SSE2)
+/**
+ * This function converts the double precision floating point numbers which
+ * distribute uniformly in the range [1, 2) to those which distribute uniformly
+ * in the range [0, 1).
+ * @param w 128bit stracture of double precision floating point numbers (I/O)
+ */
+inline static void convert_c0o1(w128_t *w) {
+    w->sd = _mm_add_pd(w->sd, sse2_double_m_one);
+}
+
+/**
+ * This function converts the double precision floating point numbers which
+ * distribute uniformly in the range [1, 2) to those which distribute uniformly
+ * in the range (0, 1].
+ * @param w 128bit stracture of double precision floating point numbers (I/O)
+ */
+inline static void convert_o0c1(w128_t *w) {
+    w->sd = _mm_sub_pd(sse2_double_two, w->sd);
+}
+
+/**
+ * This function converts the double precision floating point numbers which
+ * distribute uniformly in the range [1, 2) to those which distribute uniformly
+ * in the range (0, 1).
+ * @param w 128bit stracture of double precision floating point numbers (I/O)
+ */
+inline static void convert_o0o1(w128_t *w) {
+    w->si = _mm_or_si128(w->si, sse2_int_one);
+    w->sd = _mm_add_pd(w->sd, sse2_double_m_one);
+}
+#else /* standard C and altivec */
+/**
+ * This function converts the double precision floating point numbers which
+ * distribute uniformly in the range [1, 2) to those which distribute uniformly
+ * in the range [0, 1).
+ * @param w 128bit stracture of double precision floating point numbers (I/O)
+ */
+inline static void convert_c0o1(w128_t *w) {
+    w->d[0] -= 1.0;
+    w->d[1] -= 1.0;
+}
+
+/**
+ * This function converts the double precision floating point numbers which
+ * distribute uniformly in the range [1, 2) to those which distribute uniformly
+ * in the range (0, 1].
+ * @param w 128bit stracture of double precision floating point numbers (I/O)
+ */
+inline static void convert_o0c1(w128_t *w) {
+    w->d[0] = 2.0 - w->d[0];
+    w->d[1] = 2.0 - w->d[1];
+}
+
+/**
+ * This function converts the double precision floating point numbers which
+ * distribute uniformly in the range [1, 2) to those which distribute uniformly
+ * in the range (0, 1).
+ * @param w 128bit stracture of double precision floating point numbers (I/O)
+ */
+inline static void convert_o0o1(w128_t *w) {
+    w->u[0] |= 1;
+    w->u[1] |= 1;
+    w->d[0] -= 1.0;
+    w->d[1] -= 1.0;
+}
+#endif
+
+/**
+ * This function fills the user-specified array with double precision
+ * floating point pseudorandom numbers of the IEEE 754 format.
+ * @param dsfmt dsfmt state vector.
+ * @param array an 128-bit array to be filled by pseudorandom numbers.  
+ * @param size number of 128-bit pseudorandom numbers to be generated.
+ */
+inline static void gen_rand_array_c1o2(dsfmt_t *dsfmt, w128_t array[],
+				       int size) {
+    int i, j;
+    w128_t lung;
+
+    lung = dsfmt->status[DSFMT_N];
+    do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1],
+		 &dsfmt->status[DSFMT_N - 1], &lung);
+    for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) {
+	do_recursion(&array[i], &dsfmt->status[i],
+		     &dsfmt->status[i + DSFMT_POS1], &array[i - 1],
+		     &lung);
+    }
+    for (; i < DSFMT_N; i++) {
+	do_recursion(&array[i], &dsfmt->status[i],
+		     &array[i + DSFMT_POS1 - DSFMT_N], &array[i - 1], &lung);
+    }
+    for (; i < size - DSFMT_N; i++) {
+	do_recursion(&array[i], &array[i - DSFMT_N],
+		     &array[i + DSFMT_POS1 - DSFMT_N], &array[i - 1], &lung);
+    }
+    for (j = 0; j < 2 * DSFMT_N - size; j++) {
+	dsfmt->status[j] = array[j + size - DSFMT_N];
+    }
+    for (; i < size; i++, j++) {
+	do_recursion(&array[i], &array[i - DSFMT_N],
+		     &array[i + DSFMT_POS1 - DSFMT_N], &array[i - 1], &lung);
+	dsfmt->status[j] = array[i];
+    }
+    dsfmt->status[DSFMT_N] = lung;
+}
+
+/**
+ * This function fills the user-specified array with double precision
+ * floating point pseudorandom numbers of the IEEE 754 format.
+ * @param dsfmt dsfmt state vector.
+ * @param array an 128-bit array to be filled by pseudorandom numbers.  
+ * @param size number of 128-bit pseudorandom numbers to be generated.
+ */
+inline static void gen_rand_array_c0o1(dsfmt_t *dsfmt, w128_t array[],
+				       int size) {
+    int i, j;
+    w128_t lung;
+
+    lung = dsfmt->status[DSFMT_N];
+    do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1],
+		 &dsfmt->status[DSFMT_N - 1], &lung);
+    for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) {
+	do_recursion(&array[i], &dsfmt->status[i],
+		     &dsfmt->status[i + DSFMT_POS1], &array[i - 1],
+		     &lung);
+    }
+    for (; i < DSFMT_N; i++) {
+	do_recursion(&array[i], &dsfmt->status[i],
+		     &array[i + DSFMT_POS1 - DSFMT_N], &array[i - 1], &lung);
+    }
+    for (; i < size - DSFMT_N; i++) {
+	do_recursion(&array[i], &array[i - DSFMT_N],
+		     &array[i + DSFMT_POS1 - DSFMT_N], &array[i - 1], &lung);
+	convert_c0o1(&array[i - DSFMT_N]);
+    }
+    for (j = 0; j < 2 * DSFMT_N - size; j++) {
+	dsfmt->status[j] = array[j + size - DSFMT_N];
+    }
+    for (; i < size; i++, j++) {
+	do_recursion(&array[i], &array[i - DSFMT_N],
+		     &array[i + DSFMT_POS1 - DSFMT_N], &array[i - 1], &lung);
+	dsfmt->status[j] = array[i];
+	convert_c0o1(&array[i - DSFMT_N]);
+    }
+    for (i = size - DSFMT_N; i < size; i++) {
+	convert_c0o1(&array[i]);
+    }
+    dsfmt->status[DSFMT_N] = lung;
+}
+
+/**
+ * This function fills the user-specified array with double precision
+ * floating point pseudorandom numbers of the IEEE 754 format.
+ * @param dsfmt dsfmt state vector.
+ * @param array an 128-bit array to be filled by pseudorandom numbers.  
+ * @param size number of 128-bit pseudorandom numbers to be generated.
+ */
+inline static void gen_rand_array_o0o1(dsfmt_t *dsfmt, w128_t array[],
+				       int size) {
+    int i, j;
+    w128_t lung;
+
+    lung = dsfmt->status[DSFMT_N];
+    do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1],
+		 &dsfmt->status[DSFMT_N - 1], &lung);
+    for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) {
+	do_recursion(&array[i], &dsfmt->status[i],
+		     &dsfmt->status[i + DSFMT_POS1], &array[i - 1],
+		     &lung);
+    }
+    for (; i < DSFMT_N; i++) {
+	do_recursion(&array[i], &dsfmt->status[i],
+		     &array[i + DSFMT_POS1 - DSFMT_N], &array[i - 1], &lung);
+    }
+    for (; i < size - DSFMT_N; i++) {
+	do_recursion(&array[i], &array[i - DSFMT_N],
+		     &array[i + DSFMT_POS1 - DSFMT_N], &array[i - 1], &lung);
+	convert_o0o1(&array[i - DSFMT_N]);
+    }
+    for (j = 0; j < 2 * DSFMT_N - size; j++) {
+	dsfmt->status[j] = array[j + size - DSFMT_N];
+    }
+    for (; i < size; i++, j++) {
+	do_recursion(&array[i], &array[i - DSFMT_N],
+		     &array[i + DSFMT_POS1 - DSFMT_N], &array[i - 1], &lung);
+	dsfmt->status[j] = array[i];
+	convert_o0o1(&array[i - DSFMT_N]);
+    }
+    for (i = size - DSFMT_N; i < size; i++) {
+	convert_o0o1(&array[i]);
+    }
+    dsfmt->status[DSFMT_N] = lung;
+}
+
+/**
+ * This function fills the user-specified array with double precision
+ * floating point pseudorandom numbers of the IEEE 754 format.
+ * @param dsfmt dsfmt state vector.
+ * @param array an 128-bit array to be filled by pseudorandom numbers.  
+ * @param size number of 128-bit pseudorandom numbers to be generated.
+ */
+inline static void gen_rand_array_o0c1(dsfmt_t *dsfmt, w128_t array[],
+				       int size) {
+    int i, j;
+    w128_t lung;
+
+    lung = dsfmt->status[DSFMT_N];
+    do_recursion(&array[0], &dsfmt->status[0], &dsfmt->status[DSFMT_POS1],
+		 &dsfmt->status[DSFMT_N - 1], &lung);
+    for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) {
+	do_recursion(&array[i], &dsfmt->status[i],
+		     &dsfmt->status[i + DSFMT_POS1], &array[i - 1],
+		     &lung);
+    }
+    for (; i < DSFMT_N; i++) {
+	do_recursion(&array[i], &dsfmt->status[i],
+		     &array[i + DSFMT_POS1 - DSFMT_N], &array[i - 1], &lung);
+    }
+    for (; i < size - DSFMT_N; i++) {
+	do_recursion(&array[i], &array[i - DSFMT_N],
+		     &array[i + DSFMT_POS1 - DSFMT_N], &array[i - 1], &lung);
+	convert_o0c1(&array[i - DSFMT_N]);
+    }
+    for (j = 0; j < 2 * DSFMT_N - size; j++) {
+	dsfmt->status[j] = array[j + size - DSFMT_N];
+    }
+    for (; i < size; i++, j++) {
+	do_recursion(&array[i], &array[i - DSFMT_N],
+		     &array[i + DSFMT_POS1 - DSFMT_N], &array[i - 1], &lung);
+	dsfmt->status[j] = array[i];
+	convert_o0c1(&array[i - DSFMT_N]);
+    }
+    for (i = size - DSFMT_N; i < size; i++) {
+	convert_o0c1(&array[i]);
+    }
+    dsfmt->status[DSFMT_N] = lung;
+}
+
+/**
+ * This function represents a function used in the initialization
+ * by init_by_array
+ * @param x 32-bit integer
+ * @return 32-bit integer
+ */
+static uint32_t ini_func1(uint32_t x) {
+    return (x ^ (x >> 27)) * (uint32_t)1664525UL;
+}
+
+/**
+ * This function represents a function used in the initialization
+ * by init_by_array
+ * @param x 32-bit integer
+ * @return 32-bit integer
+ */
+static uint32_t ini_func2(uint32_t x) {
+    return (x ^ (x >> 27)) * (uint32_t)1566083941UL;
+}
+
+/**
+ * This function initializes the internal state array to fit the IEEE
+ * 754 format.
+ * @param dsfmt dsfmt state vector.
+ */
+static void initial_mask(dsfmt_t *dsfmt) {
+    int i;
+    uint64_t *psfmt;
+
+    psfmt = &dsfmt->status[0].u[0];
+    for (i = 0; i < (DSFMT_N + 1) * 2; i++) {
+        psfmt[i] = (psfmt[i] & DSFMT_LOW_MASK) | DSFMT_HIGH_CONST;
+    }
+}
+
+/**
+ * This function certificate the period of 2^{SFMT_MEXP}-1.
+ * @param dsfmt dsfmt state vector.
+ */
+static void period_certification(dsfmt_t *dsfmt) {
+    int i, j;
+    uint64_t pcv[2] = {DSFMT_PCV1, DSFMT_PCV2};
+    uint64_t inner;
+    uint64_t new_lung[2];
+    uint64_t work;
+    uint64_t fix[2];
+
+    fix[0] = (((DSFMT_HIGH_CONST >> DSFMT_SR1) & DSFMT_MSK2) 
+	      ^ (DSFMT_HIGH_CONST >> DSFMT_SR2)) | DSFMT_HIGH_CONST;
+    fix[1] = (((DSFMT_HIGH_CONST >> DSFMT_SR1) & DSFMT_MSK1) 
+	      ^ (DSFMT_HIGH_CONST >> DSFMT_SR2)) | DSFMT_HIGH_CONST;
+    fix[0] = fix[0] ^ (DSFMT_HIGH_CONST >> (64 - 8 * DSFMT_SL2));
+    new_lung[0] = dsfmt->status[DSFMT_N].u[0] ^ fix[0];
+    new_lung[1] = dsfmt->status[DSFMT_N].u[1] ^ fix[1];
+    inner = new_lung[0] & pcv[0];
+    inner ^= new_lung[1] & pcv[1];
+    for (i = 32; i > 0; i >>= 1) {
+        inner ^= inner >> i;
+    }
+    inner &= 1;
+    /* check OK */
+    if (inner == 1) {
+	return;
+    }
+    /* check NG, and modification */
+    for (i = 0; i < 2; i++) {
+	work = 1;
+	for (j = 0; j < 52; j++) {
+	    if ((work & pcv[i]) != 0) {
+		dsfmt->status[DSFMT_N].u[i] ^= work;
+		return;
+	    }
+	    work = work << 1;
+	}
+    }
+}
+
+/*----------------
+  PUBLIC FUNCTIONS
+  ----------------*/
+/**
+ * This function returns the identification string.  The string shows
+ * the Mersenne exponent, and all parameters of this generator.
+ * @return id string.
+ */
+const char *dsfmt_get_idstring(void) {
+    return DSFMT_IDSTR;
+}
+
+/**
+ * This function returns the minimum size of array used for \b
+ * fill_array functions.
+ * @return minimum size of array used for fill_array functions.
+ */
+int dsfmt_get_min_array_size(void) {
+    return DSFMT_N64;
+}
+
+/**
+ * This function fills the internal state array with double precision
+ * floating point pseudorandom numbers of the IEEE 754 format.
+ * @param dsfmt dsfmt state vector.
+ */
+void dsfmt_gen_rand_all(dsfmt_t *dsfmt) {
+    int i;
+    w128_t lung;
+
+    lung = dsfmt->status[DSFMT_N];
+    do_recursion(&dsfmt->status[0], &dsfmt->status[0],
+		 &dsfmt->status[DSFMT_POS1], &dsfmt->status[DSFMT_N -1], &lung);
+    for (i = 1; i < DSFMT_N - DSFMT_POS1; i++) {
+	do_recursion(&dsfmt->status[i], &dsfmt->status[i],
+		     &dsfmt->status[i + DSFMT_POS1], &dsfmt->status[i - 1],
+		     &lung);
+    }
+    for (; i < DSFMT_N; i++) {
+	do_recursion(&dsfmt->status[i], &dsfmt->status[i],
+		     &dsfmt->status[i + DSFMT_POS1 - DSFMT_N],
+		     &dsfmt->status[i - 1], &lung);
+    }
+    dsfmt->status[DSFMT_N] = lung;
+}
+
+/**
+ * This function generates double precision floating point
+ * pseudorandom numbers which distribute in the range [1, 2) to the
+ * specified array[] by one call. The number of pseudorandom numbers
+ * is specified by the argument \b size, which must be at least (SFMT_MEXP
+ * / 128) * 2 and a multiple of two.  The function
+ * get_min_array_size() returns this minimum size.  The generation by
+ * this function is much faster than the following fill_array_xxx functions.
+ *
+ * For initialization, init_gen_rand() or init_by_array() must be called
+ * before the first call of this function. This function can not be
+ * used after calling genrand_xxx functions, without initialization.
+ *
+ * @param dsfmt dsfmt state vector.
+ * @param array an array where pseudorandom numbers are filled
+ * by this function.  The pointer to the array must be "aligned"
+ * (namely, must be a multiple of 16) in the SIMD version, since it
+ * refers to the address of a 128-bit integer.  In the standard C
+ * version, the pointer is arbitrary.
+ *
+ * @param size the number of 64-bit pseudorandom integers to be
+ * generated.  size must be a multiple of 2, and greater than or equal
+ * to (SFMT_MEXP / 128) * 2.
+ *
+ * @note \b memalign or \b posix_memalign is available to get aligned
+ * memory. Mac OSX doesn't have these functions, but \b malloc of OSX
+ * returns the pointer to the aligned memory block.
+ */
+void dsfmt_fill_array_close1_open2(dsfmt_t *dsfmt, double array[], int size) {
+    assert(size % 2 == 0);
+    assert(size >= DSFMT_N64);
+    gen_rand_array_c1o2(dsfmt, (w128_t *)array, size / 2);
+}
+
+/**
+ * This function generates double precision floating point
+ * pseudorandom numbers which distribute in the range (0, 1] to the
+ * specified array[] by one call. This function is the same as
+ * fill_array_close1_open2() except the distribution range.
+ *
+ * @param dsfmt dsfmt state vector.
+ * @param array an array where pseudorandom numbers are filled
+ * by this function.
+ * @param size the number of pseudorandom numbers to be generated.
+ * see also \sa fill_array_close1_open2()
+ */
+void dsfmt_fill_array_open_close(dsfmt_t *dsfmt, double array[], int size) {
+    assert(size % 2 == 0);
+    assert(size >= DSFMT_N64);
+    gen_rand_array_o0c1(dsfmt, (w128_t *)array, size / 2);
+}
+
+/**
+ * This function generates double precision floating point
+ * pseudorandom numbers which distribute in the range [0, 1) to the
+ * specified array[] by one call. This function is the same as
+ * fill_array_close1_open2() except the distribution range.
+ *
+ * @param array an array where pseudorandom numbers are filled
+ * by this function.
+ * @param dsfmt dsfmt state vector.
+ * @param size the number of pseudorandom numbers to be generated.
+ * see also \sa fill_array_close1_open2()
+ */
+void dsfmt_fill_array_close_open(dsfmt_t *dsfmt, double array[], int size) {
+    assert(size % 2 == 0);
+    assert(size >= DSFMT_N64);
+    gen_rand_array_c0o1(dsfmt, (w128_t *)array, size / 2);
+}
+
+/**
+ * This function generates double precision floating point
+ * pseudorandom numbers which distribute in the range (0, 1) to the
+ * specified array[] by one call. This function is the same as
+ * fill_array_close1_open2() except the distribution range.
+ *
+ * @param dsfmt dsfmt state vector.
+ * @param array an array where pseudorandom numbers are filled
+ * by this function.
+ * @param size the number of pseudorandom numbers to be generated.
+ * see also \sa fill_array_close1_open2()
+ */
+void dsfmt_fill_array_open_open(dsfmt_t *dsfmt, double array[], int size) {
+    assert(size % 2 == 0);
+    assert(size >= DSFMT_N64);
+    gen_rand_array_o0o1(dsfmt, (w128_t *)array, size / 2);
+}
+
+#if defined(__INTEL_COMPILER)
+#  pragma warning(disable:981)
+#endif
+/**
+ * This function initializes the internal state array with a 32-bit
+ * integer seed.
+ * @param dsfmt dsfmt state vector.
+ * @param seed a 32-bit integer used as the seed.
+ * @param mexp caller's mersenne expornent
+ */
+void dsfmt_chk_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed, int mexp) {
+    int i;
+    uint32_t *psfmt;
+
+    /* make sure caller program is compiled with the same MEXP */
+    if (mexp != dsfmt_mexp) {
+	fprintf(stderr, "DSFMT_MEXP doesn't match with dSFMT.c\n");
+	exit(1);
+    }
+    psfmt = &dsfmt->status[0].u32[0];
+    psfmt[idxof(0)] = seed;
+    for (i = 1; i < (DSFMT_N + 1) * 4; i++) {
+        psfmt[idxof(i)] = 1812433253UL 
+	    * (psfmt[idxof(i - 1)] ^ (psfmt[idxof(i - 1)] >> 30)) + i;
+    }
+    initial_mask(dsfmt);
+    period_certification(dsfmt);
+    dsfmt->idx = DSFMT_N64;
+#if defined(HAVE_SSE2)
+    setup_const();
+#endif
+}
+
+/**
+ * This function initializes the internal state array,
+ * with an array of 32-bit integers used as the seeds
+ * @param dsfmt dsfmt state vector.
+ * @param init_key the array of 32-bit integers, used as a seed.
+ * @param key_length the length of init_key.
+ * @param mexp caller's mersenne expornent
+ */
+void dsfmt_chk_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[],
+			     int key_length, int mexp) {
+    int i, j, count;
+    uint32_t r;
+    uint32_t *psfmt32;
+    int lag;
+    int mid;
+    int size = (DSFMT_N + 1) * 4;	/* pulmonary */
+
+    /* make sure caller program is compiled with the same MEXP */
+    if (mexp != dsfmt_mexp) {
+	fprintf(stderr, "DSFMT_MEXP doesn't match with dSFMT.c\n");
+	exit(1);
+    }
+    if (size >= 623) {
+	lag = 11;
+    } else if (size >= 68) {
+	lag = 7;
+    } else if (size >= 39) {
+	lag = 5;
+    } else {
+	lag = 3;
+    }
+    mid = (size - lag) / 2;
+
+    psfmt32 = &dsfmt->status[0].u32[0];
+    memset(dsfmt->status, 0x8b, sizeof(dsfmt->status));
+    if (key_length + 1 > size) {
+	count = key_length + 1;
+    } else {
+	count = size;
+    }
+    r = ini_func1(psfmt32[idxof(0)] ^ psfmt32[idxof(mid % size)] 
+		  ^ psfmt32[idxof((size - 1) % size)]);
+    psfmt32[idxof(mid % size)] += r;
+    r += key_length;
+    psfmt32[idxof((mid + lag) % size)] += r;
+    psfmt32[idxof(0)] = r;
+    i = 1;
+    count--;
+    for (i = 1, j = 0; (j < count) && (j < key_length); j++) {
+	r = ini_func1(psfmt32[idxof(i)] 
+		      ^ psfmt32[idxof((i + mid) % size)] 
+		      ^ psfmt32[idxof((i + size - 1) % size)]);
+	psfmt32[idxof((i + mid) % size)] += r;
+	r += init_key[j] + i;
+	psfmt32[idxof((i + mid + lag) % size)] += r;
+	psfmt32[idxof(i)] = r;
+	i = (i + 1) % size;
+    }
+    for (; j < count; j++) {
+	r = ini_func1(psfmt32[idxof(i)] 
+		      ^ psfmt32[idxof((i + mid) % size)] 
+		      ^ psfmt32[idxof((i + size - 1) % size)]);
+	psfmt32[idxof((i + mid) % size)] += r;
+	r += i;
+	psfmt32[idxof((i + mid + lag) % size)] += r;
+	psfmt32[idxof(i)] = r;
+	i = (i + 1) % size;
+    }
+    for (j = 0; j < size; j++) {
+	r = ini_func2(psfmt32[idxof(i)] 
+		      + psfmt32[idxof((i + mid) % size)] 
+		      + psfmt32[idxof((i + size - 1) % size)]);
+	psfmt32[idxof((i + mid) % size)] ^= r;
+	r -= i;
+	psfmt32[idxof((i + mid + lag) % size)] ^= r;
+	psfmt32[idxof(i)] = r;
+	i = (i + 1) % size;
+    }
+    initial_mask(dsfmt);
+    period_certification(dsfmt);
+    dsfmt->idx = DSFMT_N64;
+#if defined(HAVE_SSE2)
+    setup_const();
+#endif
+}
+#if defined(__INTEL_COMPILER)
+#  pragma warning(default:981)
+#endif
diff --git a/xpdeint/includes/dSFMT/dSFMT.h b/xpdeint/includes/dSFMT/dSFMT.h
new file mode 100644
index 0000000..d9d206e
--- /dev/null
+++ b/xpdeint/includes/dSFMT/dSFMT.h
@@ -0,0 +1,578 @@
+/** 
+ * @file dSFMT.h 
+ *
+ * @brief double precision SIMD oriented Fast Mersenne Twister(dSFMT)
+ * pseudorandom number generator based on IEEE 754 format.
+ *
+ * @author Mutsuo Saito (Hiroshima University)
+ * @author Makoto Matsumoto (Hiroshima University)
+ *
+ * Copyright (C) 2007, 2008 Mutsuo Saito, Makoto Matsumoto and
+ * Hiroshima University. All rights reserved.
+ *
+ * The new BSD License is applied to this software.
+ * see LICENSE.txt
+ *
+ * @note We assume that your system has inttypes.h.  If your system
+ * doesn't have inttypes.h, you have to typedef uint32_t and uint64_t,
+ * and you have to define PRIu64 and PRIx64 in this file as follows:
+ * @verbatim
+ typedef unsigned int uint32_t
+ typedef unsigned long long uint64_t  
+ #define PRIu64 "llu"
+ #define PRIx64 "llx"
+ at endverbatim
+ * uint32_t must be exactly 32-bit unsigned integer type (no more, no
+ * less), and uint64_t must be exactly 64-bit unsigned integer type.
+ * PRIu64 and PRIx64 are used for printf function to print 64-bit
+ * unsigned int and 64-bit unsigned int in hexadecimal format.
+ */
+
+#ifndef DSFMT_H
+#define DSFMT_H
+
+#include <stdio.h>
+#include <assert.h>
+#include "dSFMT-params.h"
+
+#if !defined(DSFMT_BIG_ENDIAN)
+#  if defined(__BYTE_ORDER) && defined(__BIG_ENDIAN)
+#    if __BYTE_ORDER == __BIG_ENDIAN
+#      define DSFMT_BIG_ENDIAN 1
+#    endif
+#  elif defined(_BYTE_ORDER) && defined(_BIG_ENDIAN)
+#    if _BYTE_ORDER == _BIG_ENDIAN
+#      define DSFMT_BIG_ENDIAN 1
+#    endif
+#  elif defined(__BYTE_ORDER__) && defined(__BIG_ENDIAN__)
+#    if __BYTE_ORDER__ == __BIG_ENDIAN__
+#      define DSFMT_BIG_ENDIAN 1
+#    endif
+#  elif defined(BYTE_ORDER) && defined(BIG_ENDIAN)
+#    if BYTE_ORDER == BIG_ENDIAN
+#      define DSFMT_BIG_ENDIAN 1
+#    endif
+#  elif defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN) \
+    || defined(__BIG_ENDIAN__) || defined(BIG_ENDIAN)
+#      define DSFMT_BIG_ENDIAN 1
+#  endif
+#endif
+
+#if defined(DSFMT_BIG_ENDIAN) && defined(__amd64)
+#  undef DSFMT_BIG_ENDIAN
+#endif
+
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+#  include <inttypes.h>
+#elif defined(_MSC_VER) || defined(__BORLANDC__)
+#  if !defined(DSFMT_UINT32_DEFINED) && !defined(SFMT_UINT32_DEFINED)
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+#    define DSFMT_UINT32_DEFINED
+#    if !defined(inline)
+#      define inline __inline
+#    endif
+#  endif
+#else
+#  include <inttypes.h>
+#  if !defined(inline)
+#    if defined(__GNUC__)
+#      define inline __inline__
+#    else
+#      define inline
+#    endif
+#  endif
+#endif
+
+#ifndef PRIu64
+#  if defined(_MSC_VER) || defined(__BORLANDC__)
+#    define PRIu64 "I64u"
+#    define PRIx64 "I64x"
+#  else
+#    define PRIu64 "llu"
+#    define PRIx64 "llx"
+#  endif
+#endif
+
+#ifndef UINT64_C
+#  define UINT64_C(v) (v ## ULL) 
+#endif
+
+/*------------------------------------------
+  128-bit SIMD like data type for standard C
+  ------------------------------------------*/
+#if defined(HAVE_ALTIVEC)
+#  if !defined(__APPLE__)
+#    include <altivec.h>
+#  endif
+/** 128-bit data structure */
+union W128_T {
+    vector unsigned int s;
+    uint64_t u[2];
+    uint32_t u32[4];
+    double d[2];
+};
+
+#elif defined(HAVE_SSE2)
+#  include <emmintrin.h>
+
+/** 128-bit data structure */
+union W128_T {
+    __m128i si;
+    __m128d sd;
+    uint64_t u[2];
+    uint32_t u32[4];
+    double d[2];
+};
+#else  /* standard C */
+/** 128-bit data structure */
+union W128_T {
+    uint64_t u[2];
+    uint32_t u32[4];
+    double d[2];
+};
+#endif
+
+/** 128-bit data type */
+typedef union W128_T w128_t;
+
+/** the 128-bit internal state array */
+struct DSFMT_T {
+    w128_t status[DSFMT_N + 1];
+    int idx;
+};
+typedef struct DSFMT_T dsfmt_t;
+
+/** dsfmt initialized flag */
+extern int dsfmt_global_is_initialized;
+/** dsfmt internal state vector */
+extern dsfmt_t dsfmt_global_data;
+/** dsfmt mexp for check */
+extern const int dsfmt_global_mexp;
+
+void dsfmt_gen_rand_all(dsfmt_t *dsfmt);
+void dsfmt_fill_array_open_close(dsfmt_t *dsfmt, double array[], int size);
+void dsfmt_fill_array_close_open(dsfmt_t *dsfmt, double array[], int size);
+void dsfmt_fill_array_open_open(dsfmt_t *dsfmt, double array[], int size);
+void dsfmt_fill_array_close1_open2(dsfmt_t *dsfmt, double array[], int size);
+void dsfmt_chk_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed, int mexp);
+void dsfmt_chk_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[],
+			     int key_length, int mexp);
+const char *dsfmt_get_idstring(void);
+int dsfmt_get_min_array_size(void);
+
+#if defined(__GNUC__)
+#  define DSFMT_PRE_INLINE inline static
+#  define DSFMT_PST_INLINE __attribute__((always_inline))
+#elif defined(_MSC_VER) && _MSC_VER >= 1200
+#  define DSFMT_PRE_INLINE __forceinline
+#  define DSFMT_PST_INLINE
+#else
+#  define DSFMT_PRE_INLINE inline static
+#  define DSFMT_PST_INLINE
+#endif
+DSFMT_PRE_INLINE double dsfmt_genrand_close1_open2(dsfmt_t *dsfmt)
+    DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE double dsfmt_genrand_close_open(dsfmt_t *dsfmt)
+    DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE double dsfmt_genrand_open_close(dsfmt_t *dsfmt)
+    DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE double dsfmt_genrand_open_open(dsfmt_t *dsfmt)
+    DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE double dsfmt_gv_genrand_close1_open2(void) DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE double dsfmt_gv_genrand_close_open(void) DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE double dsfmt_gv_genrand_open_close(void) DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE double dsfmt_gv_genrand_open_open(void) DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE void dsfmt_gv_fill_array_open_close(double array[], int size)
+    DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE void dsfmt_gv_fill_array_close_open(double array[], int size)
+    DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE void dsfmt_gv_fill_array_open_open(double array[], int size)
+    DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE void dsfmt_gv_fill_array_close1_open2(double array[], int size)
+    DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE void dsfmt_gv_init_gen_rand(uint32_t seed) DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE void dsfmt_gv_init_by_array(uint32_t init_key[],
+					     int key_length) DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE void dsfmt_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed)
+    DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[],
+					  int key_length) DSFMT_PST_INLINE;
+
+/**
+ * This function generates and returns double precision pseudorandom
+ * number which distributes uniformly in the range [1, 2).  This is
+ * the primitive and faster than generating numbers in other ranges.
+ * dsfmt_init_gen_rand() or dsfmt_init_by_array() must be called
+ * before this function.
+ * @param dsfmt dsfmt internal state date
+ * @return double precision floating point pseudorandom number
+ */
+inline static double dsfmt_genrand_close1_open2(dsfmt_t *dsfmt) {
+    double r;
+    double *psfmt64 = &dsfmt->status[0].d[0];
+
+    if (dsfmt->idx >= DSFMT_N * 2) {
+	dsfmt_gen_rand_all(dsfmt);
+	dsfmt->idx = 0;
+    }
+    r = psfmt64[dsfmt->idx++];
+    return r;
+}
+
+/**
+ * This function generates and returns double precision pseudorandom
+ * number which distributes uniformly in the range [1, 2).  This is
+ * the primitive and faster than generating numbers in other ranges.
+ * dsfmt_gv_init_gen_rand() or dsfmt_gv_init_by_array() must be called
+ * before this function. This function uses \b global variables.
+ * @return double precision floating point pseudorandom number
+ */
+inline static double dsfmt_gv_genrand_close1_open2(void) {
+    assert(dsfmt_global_is_initialized);
+    return dsfmt_genrand_close1_open2(&dsfmt_global_data);
+}
+
+/**
+ * This function generates and returns double precision pseudorandom
+ * number which distributes uniformly in the range [0, 1).
+ * dsfmt_init_gen_rand() or dsfmt_init_by_array() must be called
+ * before this function.
+ * @param dsfmt dsfmt internal state date
+ * @return double precision floating point pseudorandom number
+ */
+inline static double dsfmt_genrand_close_open(dsfmt_t *dsfmt) {
+    return dsfmt_genrand_close1_open2(dsfmt) - 1.0;
+}
+
+/**
+ * This function generates and returns double precision pseudorandom
+ * number which distributes uniformly in the range [0, 1).
+ * dsfmt_gv_init_gen_rand() or dsfmt_gv_init_by_array() must be called
+ * before this function. This function uses \b global variables.
+ * @return double precision floating point pseudorandom number
+ */
+inline static double dsfmt_gv_genrand_close_open(void) {
+    return dsfmt_gv_genrand_close1_open2() - 1.0;
+}
+
+/**
+ * This function generates and returns double precision pseudorandom
+ * number which distributes uniformly in the range (0, 1].
+ * dsfmt_init_gen_rand() or dsfmt_init_by_array() must be called
+ * before this function. 
+ * @param dsfmt dsfmt internal state date
+ * @return double precision floating point pseudorandom number
+ */
+inline static double dsfmt_genrand_open_close(dsfmt_t *dsfmt) {
+    return 2.0 - dsfmt_genrand_close1_open2(dsfmt);
+}
+
+/**
+ * This function generates and returns double precision pseudorandom
+ * number which distributes uniformly in the range (0, 1].
+ * dsfmt_gv_init_gen_rand() or dsfmt_gv_init_by_array() must be called
+ * before this function. This function uses \b global variables.
+ * @return double precision floating point pseudorandom number
+ */
+inline static double dsfmt_gv_genrand_open_close(void) {
+    return 2.0 - dsfmt_gv_genrand_close1_open2();
+}
+
+/**
+ * This function generates and returns double precision pseudorandom
+ * number which distributes uniformly in the range (0, 1).
+ * dsfmt_init_gen_rand() or dsfmt_init_by_array() must be called
+ * before this function.
+ * @param dsfmt dsfmt internal state date
+ * @return double precision floating point pseudorandom number
+ */
+inline static double dsfmt_genrand_open_open(dsfmt_t *dsfmt) {
+    double *dsfmt64 = &dsfmt->status[0].d[0];
+    union {
+	double d;
+	uint64_t u;
+    } r;
+
+    if (dsfmt->idx >= DSFMT_N * 2) {
+	dsfmt_gen_rand_all(dsfmt);
+	dsfmt->idx = 0;
+    }
+    r.d = dsfmt64[dsfmt->idx++];
+    r.u |= 1;
+    return r.d - 1.0;
+}
+
+/**
+ * This function generates and returns double precision pseudorandom
+ * number which distributes uniformly in the range (0, 1).
+ * dsfmt_gv_init_gen_rand() or dsfmt_gv_init_by_array() must be called
+ * before this function. This function uses \b global variables.
+ * @return double precision floating point pseudorandom number
+ */
+inline static double dsfmt_gv_genrand_open_open(void) {
+    return dsfmt_genrand_open_open(&dsfmt_global_data);
+}
+
+/**
+ * This function generates double precision floating point
+ * pseudorandom numbers which distribute in the range [1, 2) to the
+ * specified array[] by one call. This function is the same as
+ * dsfmt_fill_array_close1_open2() except that this function uses
+ * \b global variables.
+ * @param array an array where pseudorandom numbers are filled
+ * by this function.
+ * @param size the number of pseudorandom numbers to be generated.
+ * see also \sa dsfmt_fill_array_close1_open2()
+ */
+inline static void dsfmt_gv_fill_array_close1_open2(double array[], int size) {
+    assert(dsfmt_global_is_initialized);
+    dsfmt_fill_array_close1_open2(&dsfmt_global_data, array, size);
+}
+
+/**
+ * This function generates double precision floating point
+ * pseudorandom numbers which distribute in the range (0, 1] to the
+ * specified array[] by one call. This function is the same as
+ * dsfmt_gv_fill_array_close1_open2() except the distribution range.
+ * This function uses \b global variables.
+ * @param array an array where pseudorandom numbers are filled
+ * by this function.
+ * @param size the number of pseudorandom numbers to be generated.
+ * see also \sa dsfmt_fill_array_close1_open2() and \sa
+ * dsfmt_gv_fill_array_close1_open2()
+ */
+inline static void dsfmt_gv_fill_array_open_close(double array[], int size) {
+    assert(dsfmt_global_is_initialized);
+    dsfmt_fill_array_open_close(&dsfmt_global_data, array, size);
+}
+
+/**
+ * This function generates double precision floating point
+ * pseudorandom numbers which distribute in the range [0, 1) to the
+ * specified array[] by one call. This function is the same as
+ * dsfmt_gv_fill_array_close1_open2() except the distribution range.
+ * This function uses \b global variables.
+ * @param array an array where pseudorandom numbers are filled
+ * by this function.
+ * @param size the number of pseudorandom numbers to be generated.
+ * see also \sa dsfmt_fill_array_close1_open2() \sa
+ * dsfmt_gv_fill_array_close1_open2()
+ */
+inline static void dsfmt_gv_fill_array_close_open(double array[], int size) {
+    assert(dsfmt_global_is_initialized);
+    dsfmt_fill_array_close_open(&dsfmt_global_data, array, size);
+}
+
+/**
+ * This function generates double precision floating point
+ * pseudorandom numbers which distribute in the range (0, 1) to the
+ * specified array[] by one call. This function is the same as
+ * dsfmt_gv_fill_array_close1_open2() except the distribution range.
+ * This function uses \b global variables.
+ * @param array an array where pseudorandom numbers are filled
+ * by this function.
+ * @param size the number of pseudorandom numbers to be generated.
+ * see also \sa dsfmt_fill_array_close1_open2() \sa
+ * dsfmt_gv_fill_array_close1_open2()
+ */
+inline static void dsfmt_gv_fill_array_open_open(double array[], int size) {
+    assert(dsfmt_global_is_initialized);
+    dsfmt_fill_array_open_open(&dsfmt_global_data, array, size);
+}
+
+/**
+ * This function initializes the internal state array with a 32-bit
+ * integer seed.
+ * @param dsfmt dsfmt state vector.
+ * @param seed a 32-bit integer used as the seed.
+ */
+inline static void dsfmt_init_gen_rand(dsfmt_t *dsfmt, uint32_t seed) {
+    dsfmt_chk_init_gen_rand(dsfmt, seed, DSFMT_MEXP);
+}
+
+/**
+ * This function initializes the internal state array with a 32-bit
+ * integer seed. This function uses \b global variables.
+ * @param seed a 32-bit integer used as the seed.
+ * see also \sa dsfmt_init_gen_rand()
+ */
+inline static void dsfmt_gv_init_gen_rand(uint32_t seed) {
+    dsfmt_init_gen_rand(&dsfmt_global_data, seed);
+    dsfmt_global_is_initialized = 1;
+}
+
+/**
+ * This function initializes the internal state array,
+ * with an array of 32-bit integers used as the seeds.
+ * @param dsfmt dsfmt state vector
+ * @param init_key the array of 32-bit integers, used as a seed.
+ * @param key_length the length of init_key.
+ */
+inline static void dsfmt_init_by_array(dsfmt_t *dsfmt, uint32_t init_key[],
+				       int key_length) {
+    dsfmt_chk_init_by_array(dsfmt, init_key, key_length, DSFMT_MEXP);
+}
+
+/**
+ * This function initializes the internal state array,
+ * with an array of 32-bit integers used as the seeds.
+ * This function uses \b global variables.
+ * @param init_key the array of 32-bit integers, used as a seed.
+ * @param key_length the length of init_key.
+ * see also \sa dsfmt_init_by_array()
+ */
+inline static void dsfmt_gv_init_by_array(uint32_t init_key[], int key_length) {
+    dsfmt_init_by_array(&dsfmt_global_data, init_key, key_length);
+    dsfmt_global_is_initialized = 1;
+}
+
+#if !defined(DSFMT_DO_NOT_USE_OLD_NAMES)
+DSFMT_PRE_INLINE const char *get_idstring(void) DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE int get_min_array_size(void) DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE void init_gen_rand(uint32_t seed) DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE void init_by_array(uint32_t init_key[], int key_length)
+    DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE double genrand_close1_open2(void) DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE double genrand_close_open(void) DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE double genrand_open_close(void) DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE double genrand_open_open(void) DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE void fill_array_open_close(double array[], int size)
+    DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE void fill_array_close_open(double array[], int size)
+    DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE void fill_array_open_open(double array[], int size)
+    DSFMT_PST_INLINE;
+DSFMT_PRE_INLINE void fill_array_close1_open2(double array[], int size)
+    DSFMT_PST_INLINE;
+
+/**
+ * This function is just the same as dsfmt_get_idstring().
+ * @return id string.
+ * see also \sa dsfmt_get_idstring()
+ */
+inline static const char *get_idstring(void) {
+    return dsfmt_get_idstring();
+}
+
+/**
+ * This function is just the same as dsfmt_get_min_array_size().
+ * @return minimum size of array used for fill_array functions.
+ * see also \sa dsfmt_get_min_array_size()
+ */
+inline static int get_min_array_size(void) {
+    return dsfmt_get_min_array_size();
+}
+
+/**
+ * This function is just the same as dsfmt_gv_init_gen_rand().
+ * @param seed a 32-bit integer used as the seed.
+ * see also \sa dsfmt_gv_init_gen_rand(), \sa dsfmt_init_gen_rand().
+ */
+inline static void init_gen_rand(uint32_t seed) {
+    dsfmt_gv_init_gen_rand(seed);
+}
+
+/**
+ * This function is just the same as dsfmt_gv_init_by_array().
+ * @param init_key the array of 32-bit integers, used as a seed.
+ * @param key_length the length of init_key.
+ * see also \sa dsfmt_gv_init_by_array(), \sa dsfmt_init_by_array().
+ */
+inline static void init_by_array(uint32_t init_key[], int key_length) {
+    dsfmt_gv_init_by_array(init_key, key_length);
+}
+
+/**
+ * This function is just the same as dsfmt_gv_genrand_close1_open2().
+ * @return double precision floating point number.
+ * see also \sa dsfmt_genrand_close1_open2() \sa
+ * dsfmt_gv_genrand_close1_open2()
+ */
+inline static double genrand_close1_open2(void) {
+    return dsfmt_gv_genrand_close1_open2();
+}
+
+/**
+ * This function is just the same as dsfmt_gv_genrand_close_open().
+ * @return double precision floating point number.
+ * see also \sa dsfmt_genrand_close_open() \sa
+ * dsfmt_gv_genrand_close_open()
+ */
+inline static double genrand_close_open(void) {
+    return dsfmt_gv_genrand_close_open();
+}
+
+/**
+ * This function is just the same as dsfmt_gv_genrand_open_close().
+ * @return double precision floating point number.
+ * see also \sa dsfmt_genrand_open_close() \sa
+ * dsfmt_gv_genrand_open_close()
+ */
+inline static double genrand_open_close(void) {
+    return dsfmt_gv_genrand_open_close();
+}
+
+/**
+ * This function is just the same as dsfmt_gv_genrand_open_open().
+ * @return double precision floating point number.
+ * see also \sa dsfmt_genrand_open_open() \sa
+ * dsfmt_gv_genrand_open_open()
+ */
+inline static double genrand_open_open(void) {
+    return dsfmt_gv_genrand_open_open();
+}
+
+/**
+ * This function is juset the same as dsfmt_gv_fill_array_open_close().
+ * @param array an array where pseudorandom numbers are filled
+ * by this function.
+ * @param size the number of pseudorandom numbers to be generated.
+ * see also \sa dsfmt_gv_fill_array_open_close(), \sa
+ * dsfmt_fill_array_close1_open2(), \sa
+ * dsfmt_gv_fill_array_close1_open2()
+ */
+inline static void fill_array_open_close(double array[], int size) {
+    dsfmt_gv_fill_array_open_close(array, size);
+}
+
+/**
+ * This function is juset the same as dsfmt_gv_fill_array_close_open().
+ * @param array an array where pseudorandom numbers are filled
+ * by this function.
+ * @param size the number of pseudorandom numbers to be generated.
+ * see also \sa dsfmt_gv_fill_array_close_open(), \sa
+ * dsfmt_fill_array_close1_open2(), \sa
+ * dsfmt_gv_fill_array_close1_open2()
+ */
+inline static void fill_array_close_open(double array[], int size) {
+    dsfmt_gv_fill_array_close_open(array, size);
+}
+
+/**
+ * This function is juset the same as dsfmt_gv_fill_array_open_open().
+ * @param array an array where pseudorandom numbers are filled
+ * by this function.
+ * @param size the number of pseudorandom numbers to be generated.
+ * see also \sa dsfmt_gv_fill_array_open_open(), \sa
+ * dsfmt_fill_array_close1_open2(), \sa
+ * dsfmt_gv_fill_array_close1_open2()
+ */
+inline static void fill_array_open_open(double array[], int size) {
+    dsfmt_gv_fill_array_open_open(array, size);
+}
+
+/**
+ * This function is juset the same as dsfmt_gv_fill_array_close1_open2().
+ * @param array an array where pseudorandom numbers are filled
+ * by this function.
+ * @param size the number of pseudorandom numbers to be generated.
+ * see also \sa dsfmt_fill_array_close1_open2(), \sa
+ * dsfmt_gv_fill_array_close1_open2()
+ */
+inline static void fill_array_close1_open2(double array[], int size) {
+    dsfmt_gv_fill_array_close1_open2(array, size);
+}
+#endif /* DSFMT_DO_NOT_USE_OLD_NAMES */
+
+#endif /* DSFMT_H */
diff --git a/xpdeint/includes/solirte/SFMTparams.h b/xpdeint/includes/solirte/SFMTparams.h
new file mode 100644
index 0000000..a60843d
--- /dev/null
+++ b/xpdeint/includes/solirte/SFMTparams.h
@@ -0,0 +1,196 @@
+#ifndef SFMTPARAMS_H
+#define SFMTPARAMS_H
+
+#include <string>
+
+class CSFMTParams_607
+{
+  public:
+    static const size_t MEXP = 607;
+    static const size_t POS1 = 2;
+    static const int SL1 = 15;
+    static const int SL2 = 3;
+    static const int SR1 = 13;
+    static const int SR2 = 3;
+    static const uint32_t MSK1 = 0xfdff37ffU;
+    static const uint32_t MSK2 = 0xef7f3f7dU;
+    static const uint32_t MSK3 = 0xff777b7dU;
+    static const uint32_t MSK4 = 0x7ff7fb2fU;
+    static const uint32_t PARITY1 = 0x00000001U;
+    static const uint32_t PARITY2 = 0x00000000U;
+    static const uint32_t PARITY3 = 0x00000000U;
+    static const uint32_t PARITY4 = 0x5986f054U;
+};
+
+class CSFMTParams_1279
+{
+  public:
+    static const size_t MEXP = 1279;
+    static const size_t POS1 = 7;
+    static const int SL1 = 14;
+    static const int SL2 = 3;
+    static const int SR1 = 5;
+    static const int SR2 = 1;
+    static const uint32_t MSK1 = 0xf7fefffdU;
+    static const uint32_t MSK2 = 0x7fefcfffU;
+    static const uint32_t MSK3 = 0xaff3ef3fU;
+    static const uint32_t MSK4 = 0xb5ffff7fU;
+    static const uint32_t PARITY1 = 0x00000001U;
+    static const uint32_t PARITY2 = 0x00000000U;
+    static const uint32_t PARITY3 = 0x00000000U;
+    static const uint32_t PARITY4 = 0x20000000U;
+};
+
+class CSFMTParams_2281
+{
+  public:
+    static const size_t MEXP = 2281;
+    static const size_t POS1 = 12;
+    static const int SL1 = 19;
+    static const int SL2 = 1;
+    static const int SR1 = 5;
+    static const int SR2 = 1;
+    static const uint32_t MSK1 = 0xbff7ffbfU;
+    static const uint32_t MSK2 = 0xfdfffffeU;
+    static const uint32_t MSK3 = 0xf7ffef7fU;
+    static const uint32_t MSK4 = 0xf2f7cbbfU;
+    static const uint32_t PARITY1 = 0x00000001U;
+    static const uint32_t PARITY2 = 0x00000000U;
+    static const uint32_t PARITY3 = 0x00000000U;
+    static const uint32_t PARITY4 = 0x41dfa600U;
+};
+
+class CSFMTParams_4253
+{
+  public:
+    static const size_t MEXP = 4253;
+    static const size_t POS1 = 17;
+    static const int SL1 = 20;
+    static const int SL2 = 1;
+    static const int SR1 = 7;
+    static const int SR2 = 1;
+    static const uint32_t MSK1 = 0x9f7bffffU;
+    static const uint32_t MSK2 = 0x9fffff5fU;
+    static const uint32_t MSK3 = 0x3efffffbU;
+    static const uint32_t MSK4 = 0xfffff7bbU;
+    static const uint32_t PARITY1 = 0xa8000001U;
+    static const uint32_t PARITY2 = 0xaf5390a3U;
+    static const uint32_t PARITY3 = 0xb740b3f8U;
+    static const uint32_t PARITY4 = 0x6c11486dU;
+};
+
+class CSFMTParams_11213
+{
+  public:
+    static const size_t MEXP = 11213;
+    static const size_t POS1 = 68;
+    static const int SL1 = 14;
+    static const int SL2 = 3;
+    static const int SR1 = 7;
+    static const int SR2 = 3;
+    static const uint32_t MSK1 = 0xeffff7fbU;
+    static const uint32_t MSK2 = 0xffffffefU;
+    static const uint32_t MSK3 = 0xdfdfbfffU;
+    static const uint32_t MSK4 = 0x7fffdbfdU;
+    static const uint32_t PARITY1 = 0x00000001U;
+    static const uint32_t PARITY2 = 0x00000000U;
+    static const uint32_t PARITY3 = 0xe8148000U;
+    static const uint32_t PARITY4 = 0xd0c7afa3U;
+};
+
+class CSFMTParams_19937
+{
+  public:
+    static const size_t MEXP = 19937;
+    static const size_t POS1 = 122;
+    static const int SL1 = 18;
+    static const int SL2 = 1;
+    static const int SR1 = 11;
+    static const int SR2 = 1;
+    static const uint32_t MSK1 = 0xdfffffefU;
+    static const uint32_t MSK2 = 0xddfecb7fU;
+    static const uint32_t MSK3 = 0xbffaffffU;
+    static const uint32_t MSK4 = 0xbffffff6U;
+    static const uint32_t PARITY1 = 0x00000001U;
+    static const uint32_t PARITY2 = 0x00000000U;
+    static const uint32_t PARITY3 = 0x00000000U;
+    static const uint32_t PARITY4 = 0x13c9e684U;
+};
+
+class CSFMTParams_44497
+{
+  public:
+    static const size_t MEXP = 44497;
+    static const size_t POS1 = 330;
+    static const int SL1 = 5;
+    static const int SL2 = 3;
+    static const int SR1 = 9;
+    static const int SR2 = 3;
+    static const uint32_t MSK1 = 0xeffffffbU;
+    static const uint32_t MSK2 = 0xdfbebfffU;
+    static const uint32_t MSK3 = 0xbfbf7befU;
+    static const uint32_t MSK4 = 0x9ffd7bffU;
+    static const uint32_t PARITY1 = 0x00000001U;
+    static const uint32_t PARITY2 = 0x00000000U;
+    static const uint32_t PARITY3 = 0xa3ac4000U;
+    static const uint32_t PARITY4 = 0xecc1327aU;
+};
+
+class CSFMTParams_86243
+{
+  public:
+    static const size_t MEXP = 86243;
+    static const size_t POS1 = 366;
+    static const int SL1 = 6;
+    static const int SL2 = 7;
+    static const int SR1 = 19;
+    static const int SR2 = 1;
+    static const uint32_t MSK1 = 0xfdbffbffU;
+    static const uint32_t MSK2 = 0xbff7ff3fU;
+    static const uint32_t MSK3 = 0xfd77efffU;
+    static const uint32_t MSK4 = 0xbf9ff3ffU;
+    static const uint32_t PARITY1 = 0x00000001U;
+    static const uint32_t PARITY2 = 0x00000000U;
+    static const uint32_t PARITY3 = 0x00000000U;
+    static const uint32_t PARITY4 = 0xe9528d85U;
+};
+
+class CSFMTParams_132049
+{
+  public:
+    static const size_t MEXP = 132049;
+    static const size_t POS1 = 110;
+    static const int SL1 = 19;
+    static const int SL2 = 1;
+    static const int SR1 = 21;
+    static const int SR2 = 1;
+    static const uint32_t MSK1 = 0xffffbb5fU;
+    static const uint32_t MSK2 = 0xfb6ebf95U;
+    static const uint32_t MSK3 = 0xfffefffaU;
+    static const uint32_t MSK4 = 0xcff77fffU;
+    static const uint32_t PARITY1 = 0x00000001U;
+    static const uint32_t PARITY2 = 0x00000000U;
+    static const uint32_t PARITY3 = 0xcb520000U;
+    static const uint32_t PARITY4 = 0xc7e91c7dU;
+};
+
+class CSFMTParams_216091
+{
+  public:
+    static const size_t MEXP = 216091;
+    static const size_t POS1 = 627;
+    static const int SL1 = 11;
+    static const int SL2 = 3;
+    static const int SR1 = 10;
+    static const int SR2 = 1;
+    static const uint32_t MSK1 = 0xbff7bff7U;
+    static const uint32_t MSK2 = 0xbfffffffU;
+    static const uint32_t MSK3 = 0xbffffa7fU;
+    static const uint32_t MSK4 = 0xffddfbfbU;
+    static const uint32_t PARITY1 = 0xf8000001U;
+    static const uint32_t PARITY2 = 0x89e80709U;
+    static const uint32_t PARITY3 = 0x3bd2b64bU;
+    static const uint32_t PARITY4 = 0x0c64b1e4U;
+};
+
+#endif
diff --git a/xpdeint/includes/solirte/prng.h b/xpdeint/includes/solirte/prng.h
new file mode 100644
index 0000000..591538f
--- /dev/null
+++ b/xpdeint/includes/solirte/prng.h
@@ -0,0 +1,2020 @@
+/* *****************************************************************************
+/
+/ This file is part of Solirte, a solenoid ion ray-tracing engine.
+/ (c) 2008 Michael Brown.
+/ michael.brown at anu.edu.au
+/
+/ A random number generator that can do various distributions.
+/ *************************************************************************** */
+
+#ifndef PRNG_H
+#define PRNG_H
+
+#include "randpool.h"
+#include "ziggurat.h"
+// #include <math.h>
+#include <string>
+#include <vector>
+
+#ifndef CFG_TIMETRACK_DISABLE
+#include "../platform/timetrack.h"
+#endif
+
+#if CFG_COMPILER == CFG_COMPILER_MSVC
+// Shut up one of the more braindead MSVC warnings.
+#pragma warning(push)
+#pragma warning(disable: 4127)
+#endif
+
+template<class SFMTParams>
+class CPRNG
+{
+  public:
+    static const size_t BufSize = CRandPool<SFMTParams>::BufSize;
+  private:
+    #ifndef CFG_TIMETRACK_DISABLE
+    static struct TMetrics
+    {
+      static THREADVAR uint32_t uniform_FP64_refill_count;
+      static THREADVAR uint64_t uniform_FP64_refill_time;
+      static THREADVAR uint32_t uniform_FP32_refill_count;
+      static THREADVAR uint64_t uniform_FP32_refill_time;
+      static THREADVAR uint32_t gaussiantail_FP64_refill_count;
+      static THREADVAR uint64_t gaussiantail_FP64_refill_time;
+      static THREADVAR uint32_t gaussian_FP64_refill_count;
+      static THREADVAR uint64_t gaussian_FP64_refill_time;
+      static THREADVAR uint64_t gaussian_FP64_numgen;
+      static THREADVAR uint32_t exponential_FP64_refill_count;
+      static THREADVAR uint64_t exponential_FP64_refill_time;
+      static THREADVAR uint64_t exponential_FP64_numgen;
+      static THREADVAR uint32_t exponential_FP32_refill_count;
+      static THREADVAR uint64_t exponential_FP32_refill_time;
+      static THREADVAR uint64_t exponential_FP32_numgen;
+
+      TMetrics(void)
+      {
+        CPerfCounters::SetName(uniform_FP64_refill_count, "CPRNG<" + GenToString(SFMTParams::MEXP) + ">.uniform.FP64.refill.count");
+        CPerfCounters::SetName(uniform_FP64_refill_time, "CPRNG<" + GenToString(SFMTParams::MEXP) + ">.uniform.FP64.refill.time");
+        CPerfCounters::SetName(uniform_FP32_refill_count, "CPRNG<" + GenToString(SFMTParams::MEXP) + ">.uniform.FP32.refill.count");
+        CPerfCounters::SetName(uniform_FP32_refill_time, "CPRNG<" + GenToString(SFMTParams::MEXP) + ">.uniform.FP32.refill.time");
+        CPerfCounters::SetName(gaussiantail_FP64_refill_count, "CPRNG<" + GenToString(SFMTParams::MEXP) + ">.gaussiantail.FP64.refill.count");
+        CPerfCounters::SetName(gaussiantail_FP64_refill_time, "CPRNG<" + GenToString(SFMTParams::MEXP) + ">.gaussiantail.FP64.refill.time");
+        CPerfCounters::SetName(gaussian_FP64_refill_count, "CPRNG<" + GenToString(SFMTParams::MEXP) + ">.gaussian.FP64.refill.count");
+        CPerfCounters::SetName(gaussian_FP64_refill_time, "CPRNG<" + GenToString(SFMTParams::MEXP) + ">.gaussian.FP64.refill.time");
+        CPerfCounters::SetName(gaussian_FP64_numgen, "CPRNG<" + GenToString(SFMTParams::MEXP) + ">.gaussian.FP64.numgen");
+        CPerfCounters::SetName(exponential_FP64_refill_count, "CPRNG<" + GenToString(SFMTParams::MEXP) + ">.exponential.FP64.refill.count");
+        CPerfCounters::SetName(exponential_FP64_refill_time, "CPRNG<" + GenToString(SFMTParams::MEXP) + ">.exponential.FP64.refill.time");
+        CPerfCounters::SetName(exponential_FP64_numgen, "CPRNG<" + GenToString(SFMTParams::MEXP) + ">.exponential.FP64.numgen");
+        CPerfCounters::SetName(exponential_FP32_refill_count, "CPRNG<" + GenToString(SFMTParams::MEXP) + ">.exponential.FP32.refill.count");
+        CPerfCounters::SetName(exponential_FP32_refill_time, "CPRNG<" + GenToString(SFMTParams::MEXP) + ">.exponential.FP32.refill.time");
+        CPerfCounters::SetName(exponential_FP32_numgen, "CPRNG<" + GenToString(SFMTParams::MEXP) + ">.exponential.FP32.numgen");
+      }
+
+      void ForceConstruction(void) { }
+    } Metrics;
+    #endif
+    
+  private:
+    // Uniform random doubles on [0,1)
+    static const size_t FBufLen_uniform_FP64 = BufSize * 2;
+    CDataBuffer<BufSize * 16> FBuffer_uniform_FP64;
+    // Uniform random singles on [0,1)
+    static const size_t FBufLen_uniform_FP32 = BufSize * 4;
+    CDataBuffer<BufSize * 16> FBuffer_uniform_FP32;
+
+    // Gaussian tail random doubles (for Ziggurat). Note 2:1 reduction ratio
+    // (needs 2 u128's to generate 2 doubles).
+    static const size_t FBufLen_gaussiantail_FP64 = (BufSize / 2) * 2;
+    CDataBuffer<BufSize / 2 * 16> FBuffer_gaussiantail_FP64;
+    // Gaussian random doubles.
+    CDataBuffer<BufSize * 16> FBuffer_gaussian_FP64;
+    // Exponential random doubles.
+    CDataBuffer<BufSize * 16> FBuffer_exponential_FP64;
+    // Exponential random singles.
+    CDataBuffer<BufSize * 16> FBuffer_exponential_FP32;
+    // Generic integer pool
+    CDataBuffer<BufSize * 16> FBuffer_integer;
+    // The randpool itself.
+    CRandPool<SFMTParams> FRandPool;
+    // Positions and lengths.
+    size_t FBufPos_uniform_FP64;
+    size_t FBufPos_uniform_FP32;
+    size_t FBufPos_gaussiantail_FP64;
+    size_t FBufLen_gaussian_FP64;
+    size_t FBufPos_gaussian_FP64;
+    size_t FBufLen_exponential_FP64;
+    size_t FBufPos_exponential_FP64;
+    size_t FBufLen_exponential_FP32;
+    size_t FBufPos_exponential_FP32;
+    double FScaleFactor_exponential_FP64;
+    float FScaleFactor_exponential_FP32;
+    size_t FBufPos_integer;
+    int RefCount;
+  protected:
+    void RefillBuf_uniform_FP64(void);
+    void RefillBuf_uniform_FP32(void);
+    void RefillBuf_gaussiantail_FP64(void);
+    void RefillBuf_gaussian_FP64(void);
+    void RefillBuf_exponential_FP64(void);
+    void RefillBuf_exponential_FP32(void);
+    void RefillBuf_integer(void);
+  public:
+    static std::string GetIDString(void) { return CRandPool<SFMTParams>::GetIDString(); }
+
+    void Seed(uint32_t seed)
+    {
+      FRandPool.init_gen_rand(seed);
+      FBufPos_uniform_FP64 = BufSize * 2;
+      FBufPos_uniform_FP32 = BufSize * 4;
+      FBufPos_gaussiantail_FP64 = BufSize;
+      FBufPos_gaussian_FP64 = 0;
+      FBufLen_gaussian_FP64 = 0;
+      FBufPos_exponential_FP64 = 0;
+      FBufLen_exponential_FP64 = 0;
+      FScaleFactor_exponential_FP64 = 0;
+      FBufPos_exponential_FP32 = 0;
+      FBufLen_exponential_FP32 = 0;
+      FScaleFactor_exponential_FP32 = 0;
+      FBufPos_integer = BufSize * 16;
+    }
+
+    CPRNG(uint32_t seed)
+    {
+      Seed(seed);
+      RefCount = 1;
+      #ifndef CFG_TIMETRACK_DISABLE
+      Metrics.ForceConstruction();
+      #endif
+    }
+
+    int AddRef(void) { return ++RefCount; }
+    // Note: We can't do "delete this" in Release because of the thread-moving
+    // capability. See CThreadRand::MovedThreads() for details.
+    int Release(void) { return --RefCount; }
+    int GetRefCount(void) { return RefCount; }
+
+    double Random_uniform_FP64(void);
+    float Random_uniform_FP32(void);
+    double Random_gaussiantail_FP64(void);
+    double Random_gaussian_FP64(void);
+    double Random_exponential_FP64(void);
+    float Random_exponential_FP32(void);
+    uint32_t Random_u32(void);
+    uint32_t Random_u32(uint32_t MaxVal);
+
+    void Random_uniform_FP(float &x) { x = Random_uniform_FP32(); }
+    void Random_uniform_FP(double &x) { x = Random_uniform_FP64(); }
+    void Random_exponential_FP(double &x) { x = Random_exponential_FP64(); }
+    void Random_exponential_FP(float &x) { x = Random_exponential_FP32(); }
+
+    void RandFill_uniform_FP64(double *Buffer, size_t NumDoubles);
+    void RandFill_uniform_FP32(float *Buffer, size_t NumFloats);
+    void RandFill_gaussian_FP64(double *Buffer, size_t NumDoubles);
+    void RandFill_gaussiantail_FP64(double *Buffer, size_t NumDoubles);
+    void RandFill_exponential_FP64(double *Buffer, size_t NumDoubles);
+    void RandFill_exponential_FP32(float *Buffer, size_t NumFloats);
+    void RandFill_u32(uint32_t *Buffer, size_t NumU32s);
+
+    typedef typename CRandPool<SFMTParams>::CRandomBlockPtr CRandomBlockPtr;
+    CRandomBlockPtr GetRandomBlock(void) { return FRandPool.GetRandomBlock(); }
+
+    static void *operator new(size_t size)
+    {
+      return _aligned_malloc(size, 16);
+    }
+
+    static void operator delete(void *p)
+    {
+      _aligned_free(p);
+    }
+};
+
+// -----------------------------------------------------------------------------
+// Uniform random singles.
+// PATHDEF UniformFP32
+// -----------------------------------------------------------------------------
+template<class SFMTParams>
+NOINLINE void CPRNG<SFMTParams>::RefillBuf_uniform_FP32(void)
+{
+  #ifndef CFG_TIMETRACK_DISABLE
+  CTimedScope ScopeTimer(Metrics.uniform_FP32_refill_time);
+  Metrics.uniform_FP32_refill_count++;
+  #endif
+
+  typename CRandPool<SFMTParams>::CRandomBlockPtr RandomBlock = FRandPool.GetRandomBlock();
+  // Don't need SIMDOps::EmptyForFP() here (handled per-path, since we've got an MMX path)
+
+#if (CFG_HAVE_U128FP32 == CFG_SIMD_INTRINSIC)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// FP32-intrinsic implementation
+// PATHNAME u128fp32intrinsic
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  SIMDOps::EmptyForFP();
+  CDataBuffer_ConstView<uint128fp32_t, BufSize * 16> SrcPtr = RandomBlock.template GetConstView<uint128fp32_t>();
+  CDataBuffer_VarView<uint128fp32_t, BufSize * 16> DstPtr = FBuffer_uniform_FP32.template GetVarView<uint128fp32_t>();
+
+  uint128fp32_t AndMask = SIMDOps::uint128fp32_t_const<0x007FFFFF, 0x007FFFFF, 0x007FFFFF, 0x007FFFFF>::Value();
+  uint128fp32_t One = SIMDOps::uint128fp32_t_const<0x3F800000, 0x3F800000, 0x3F800000, 0x3F800000>::Value();
+
+  size_t CopyLoop;
+  for (CopyLoop = 0; CopyLoop < BufSize - (BufSize % 4); CopyLoop += 4)
+  {
+    DstPtr.Store(CopyLoop + 0, SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 0), AndMask), One), One));
+    DstPtr.Store(CopyLoop + 1, SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 1), AndMask), One), One));
+    DstPtr.Store(CopyLoop + 2, SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 2), AndMask), One), One));
+    DstPtr.Store(CopyLoop + 3, SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 3), AndMask), One), One));
+  }
+
+  // Unrolling tail.
+  if ((BufSize % 4) == 3)
+  {
+    DstPtr.Store(CopyLoop + 0, SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 0), AndMask), One), One));
+    DstPtr.Store(CopyLoop + 1, SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 1), AndMask), One), One));
+    DstPtr.Store(CopyLoop + 2, SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 2), AndMask), One), One));
+  }
+  if ((BufSize % 4) == 2)
+  {
+    DstPtr.Store(CopyLoop + 0, SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 0), AndMask), One), One));
+    DstPtr.Store(CopyLoop + 1, SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 1), AndMask), One), One));
+  }
+  if ((BufSize % 4) == 1)
+  {
+    DstPtr.Store(CopyLoop + 0, SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 0), AndMask), One), One));
+  }
+#elif (CFG_HAVE_U128 == CFG_SIMD_INTRINSIC)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// U128-intrinsic, fp32-scalar implementation
+// PATHNAME u128intrinsic-fp32scalar
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  SIMDOps::EmptyForFP();
+  CDataBuffer_ConstView<uint128_t, BufSize * 16> SrcPtr = RandomBlock.template GetConstView<uint128_t>();
+  CDataBuffer_VarView<float, BufSize * 16> DstPtr = FBuffer_uniform_FP32.template GetVarView<float>();
+
+  uint128_t AndMask = SIMDOps::uint128_t_const<0x007FFFFF, 0x007FFFFF, 0x007FFFFF, 0x007FFFFF>::Value();
+  uint128_t OrMask = SIMDOps::uint128_t_const<0x3F800000, 0x3F800000, 0x3F800000, 0x3F800000>::Value();
+
+  // Unrolled part
+  union 
+  {
+    uint128_t AsU128;
+    float AsFP32[4];
+  } TempBuf[4];
+
+  size_t CopyLoop;
+  for (CopyLoop = 0; CopyLoop < BufSize - (BufSize % 4); CopyLoop += 4)
+  {
+    TempBuf[0].AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 0), AndMask), OrMask);
+    DstPtr.Store(CopyLoop * 4 + 0, TempBuf[0].AsFP32[0] - 1);
+    DstPtr.Store(CopyLoop * 4 + 1, TempBuf[0].AsFP32[1] - 1);
+    DstPtr.Store(CopyLoop * 4 + 2, TempBuf[0].AsFP32[2] - 1);
+    DstPtr.Store(CopyLoop * 4 + 3, TempBuf[0].AsFP32[3] - 1);
+    TempBuf[1].AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 1), AndMask), OrMask);
+    DstPtr.Store(CopyLoop * 4 + 4, TempBuf[1].AsFP32[0] - 1);
+    DstPtr.Store(CopyLoop * 4 + 5, TempBuf[1].AsFP32[1] - 1);
+    DstPtr.Store(CopyLoop * 4 + 6, TempBuf[1].AsFP32[2] - 1);
+    DstPtr.Store(CopyLoop * 4 + 7, TempBuf[1].AsFP32[3] - 1);
+    TempBuf[2].AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 2), AndMask), OrMask);
+    DstPtr.Store(CopyLoop * 4 + 8, TempBuf[2].AsFP32[0] - 1);
+    DstPtr.Store(CopyLoop * 4 + 9, TempBuf[2].AsFP32[1] - 1);
+    DstPtr.Store(CopyLoop * 4 + 10, TempBuf[2].AsFP32[2] - 1);
+    DstPtr.Store(CopyLoop * 4 + 11, TempBuf[2].AsFP32[3] - 1);
+    TempBuf[3].AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 3), AndMask), OrMask);
+    DstPtr.Store(CopyLoop * 4 + 12, TempBuf[3].AsFP32[0] - 1);
+    DstPtr.Store(CopyLoop * 4 + 13, TempBuf[3].AsFP32[1] - 1);
+    DstPtr.Store(CopyLoop * 4 + 14, TempBuf[3].AsFP32[2] - 1);
+    DstPtr.Store(CopyLoop * 4 + 15, TempBuf[3].AsFP32[3] - 1);
+  }
+
+  // Unrolling tail.
+  if ((BufSize % 4) == 3)
+  {
+    TempBuf[0].AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 0), AndMask), OrMask);
+    DstPtr.Store(CopyLoop * 4 + 0, TempBuf[0].AsFP32[0] - 1);
+    DstPtr.Store(CopyLoop * 4 + 1, TempBuf[0].AsFP32[1] - 1);
+    DstPtr.Store(CopyLoop * 4 + 2, TempBuf[0].AsFP32[2] - 1);
+    DstPtr.Store(CopyLoop * 4 + 3, TempBuf[0].AsFP32[3] - 1);
+    TempBuf[1].AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 1), AndMask), OrMask);
+    DstPtr.Store(CopyLoop * 4 + 4, TempBuf[1].AsFP32[0] - 1);
+    DstPtr.Store(CopyLoop * 4 + 5, TempBuf[1].AsFP32[1] - 1);
+    DstPtr.Store(CopyLoop * 4 + 6, TempBuf[1].AsFP32[2] - 1);
+    DstPtr.Store(CopyLoop * 4 + 7, TempBuf[1].AsFP32[3] - 1);
+    TempBuf[2].AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 2), AndMask), OrMask);
+    DstPtr.Store(CopyLoop * 4 + 8, TempBuf[2].AsFP32[0] - 1);
+    DstPtr.Store(CopyLoop * 4 + 9, TempBuf[2].AsFP32[1] - 1);
+    DstPtr.Store(CopyLoop * 4 + 10, TempBuf[2].AsFP32[2] - 1);
+    DstPtr.Store(CopyLoop * 4 + 11, TempBuf[2].AsFP32[3] - 1);
+  }
+  if ((BufSize % 4) == 2)
+  {
+    TempBuf[0].AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 0), AndMask), OrMask);
+    DstPtr.Store(CopyLoop * 4 + 0, TempBuf[0].AsFP32[0] - 1);
+    DstPtr.Store(CopyLoop * 4 + 1, TempBuf[0].AsFP32[1] - 1);
+    DstPtr.Store(CopyLoop * 4 + 2, TempBuf[0].AsFP32[2] - 1);
+    DstPtr.Store(CopyLoop * 4 + 3, TempBuf[0].AsFP32[3] - 1);
+    TempBuf[1].AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 1), AndMask), OrMask);
+    DstPtr.Store(CopyLoop * 4 + 4, TempBuf[1].AsFP32[0] - 1);
+    DstPtr.Store(CopyLoop * 4 + 5, TempBuf[1].AsFP32[1] - 1);
+    DstPtr.Store(CopyLoop * 4 + 6, TempBuf[2].AsFP32[2] - 1);
+    DstPtr.Store(CopyLoop * 4 + 7, TempBuf[2].AsFP32[3] - 1);
+  }
+  if ((BufSize % 4) == 1)
+  {
+    TempBuf[0].AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 0), AndMask), OrMask);
+    DstPtr.Store(CopyLoop * 4 + 0, TempBuf[0].AsFP32[0] - 1);
+    DstPtr.Store(CopyLoop * 4 + 1, TempBuf[0].AsFP32[1] - 1);
+    DstPtr.Store(CopyLoop * 4 + 2, TempBuf[0].AsFP32[2] - 1);
+    DstPtr.Store(CopyLoop * 4 + 3, TempBuf[0].AsFP32[3] - 1);
+  }
+#elif (CFG_HAVE_U128 == CFG_SIMD_MMX)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// U128-mmx, fp32-scalar two-pass implementation
+// PATHNAME u128mmx-fp32scalar-2pass
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  {
+    // Integer pass.
+    CDataBuffer_ConstView<__m64, BufSize * 16> SrcPtr = RandomBlock.template GetConstView<__m64>();
+    CDataBuffer_VarView<__m64, BufSize * 16> DstPtr = FBuffer_uniform_FP32.template GetVarView<__m64>();
+
+    __m64 AndMask = SIMDOps::__m64_const<0x007FFFFF, 0x007FFFFF>::Value();
+    __m64 OrMask = SIMDOps::__m64_const<0x3F800000, 0x3F800000>::Value();
+
+    size_t CopyLoop;
+    for (CopyLoop = 0; CopyLoop < BufSize - BufSize % 2; CopyLoop += 2)
+    {
+      DstPtr.Store(CopyLoop * 2 + 0, _mm_or_si64(_mm_and_si64(SrcPtr.Load(CopyLoop * 2 + 0), AndMask), OrMask));
+      DstPtr.Store(CopyLoop * 2 + 1, _mm_or_si64(_mm_and_si64(SrcPtr.Load(CopyLoop * 2 + 1), AndMask), OrMask));
+      DstPtr.Store(CopyLoop * 2 + 2, _mm_or_si64(_mm_and_si64(SrcPtr.Load(CopyLoop * 2 + 2), AndMask), OrMask));
+      DstPtr.Store(CopyLoop * 2 + 3, _mm_or_si64(_mm_and_si64(SrcPtr.Load(CopyLoop * 2 + 3), AndMask), OrMask));
+    }
+    if ((BufSize % 2) == 1)
+    {
+      DstPtr.Store(CopyLoop * 2 + 0, _mm_or_si64(_mm_and_si64(SrcPtr.Load(CopyLoop * 2 + 0), AndMask), OrMask));
+      DstPtr.Store(CopyLoop * 2 + 1, _mm_or_si64(_mm_and_si64(SrcPtr.Load(CopyLoop * 2 + 1), AndMask), OrMask));
+    }
+
+    SIMDOps::EmptyForFP();
+  }
+  {
+    // Floating point pass.
+    CDataBuffer_VarView<float, BufSize * 16> DstPtr = FBuffer_uniform_FP32.template GetVarView<float>();
+
+    size_t CopyLoop;
+    for (CopyLoop = 0; CopyLoop < BufSize - BufSize % 2; CopyLoop += 2)
+    {
+      DstPtr.Store(CopyLoop * 4 + 0, DstPtr.Load(CopyLoop * 4 + 0) - 1.0f);
+      DstPtr.Store(CopyLoop * 4 + 1, DstPtr.Load(CopyLoop * 4 + 1) - 1.0f);
+      DstPtr.Store(CopyLoop * 4 + 2, DstPtr.Load(CopyLoop * 4 + 2) - 1.0f);
+      DstPtr.Store(CopyLoop * 4 + 3, DstPtr.Load(CopyLoop * 4 + 3) - 1.0f);
+      DstPtr.Store(CopyLoop * 4 + 4, DstPtr.Load(CopyLoop * 4 + 4) - 1.0f);
+      DstPtr.Store(CopyLoop * 4 + 5, DstPtr.Load(CopyLoop * 4 + 5) - 1.0f);
+      DstPtr.Store(CopyLoop * 4 + 6, DstPtr.Load(CopyLoop * 4 + 6) - 1.0f);
+      DstPtr.Store(CopyLoop * 4 + 7, DstPtr.Load(CopyLoop * 4 + 7) - 1.0f);
+    }
+    if ((BufSize % 2) == 1)
+    {
+      DstPtr.Store(CopyLoop * 4 + 0, DstPtr.Load(CopyLoop * 4 + 0) - 1.0f);
+      DstPtr.Store(CopyLoop * 4 + 1, DstPtr.Load(CopyLoop * 4 + 1) - 1.0f);
+      DstPtr.Store(CopyLoop * 4 + 2, DstPtr.Load(CopyLoop * 4 + 2) - 1.0f);
+      DstPtr.Store(CopyLoop * 4 + 3, DstPtr.Load(CopyLoop * 4 + 3) - 1.0f);
+    }
+  }
+#elif (CFG_BITS == 64)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// U128-scalar, fp32-scalar 64-bit one-pass implementation
+// PATHNAME u128scalar-fp32scalar-64bit
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  SIMDOps::EmptyForFP();
+  CDataBuffer_ConstView<uint64_t, BufSize * 16> SrcPtr = RandomBlock.template GetConstView<uint64_t>();
+  CDataBuffer_VarView<float, BufSize * 16> DstPtr = FBuffer_uniform_FP32.template GetVarView<float>();
+
+  uint64_t AndMask = UINT64_C(0x007FFFFF007FFFFF);
+  uint64_t OrMask = UINT64_C(0x3F8000003F800000);
+
+  // The main conversion loop.
+  union
+  {
+    uint64_t AsU64;
+    float AsFP32[2];
+  } FPConv[2];
+
+  for (size_t CopyLoop = 0; CopyLoop < BufSize; CopyLoop++)
+  {
+    FPConv[0].AsU64 = (SrcPtr.Load(CopyLoop * 2 + 0) & AndMask) | OrMask;
+    DstPtr.Store(CopyLoop * 4 + 0, FPConv[0].AsFP32[0] - 1.0f);
+    DstPtr.Store(CopyLoop * 4 + 1, FPConv[0].AsFP32[1] - 1.0f);
+    FPConv[1].AsU64 = (SrcPtr.Load(CopyLoop * 2 + 1) & AndMask) | OrMask;
+    DstPtr.Store(CopyLoop * 4 + 2, FPConv[1].AsFP32[0] - 1.0f);
+    DstPtr.Store(CopyLoop * 4 + 3, FPConv[1].AsFP32[1] - 1.0f);
+  }
+#else
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// U128-scalar, fp32-scalar 32-bit one-pass implementation
+// PATHNAME u128scalar-fp32scalar-32bit
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  SIMDOps::EmptyForFP();
+  CDataBuffer_ConstView<uint32_t, BufSize * 16> SrcPtr = RandomBlock.template GetConstView<uint32_t>();
+  CDataBuffer_VarView<float, BufSize * 16> DstPtr = FBuffer_uniform_FP32.template GetVarView<float>();
+
+  uint32_t AndMask = 0x007FFFFF;
+  uint32_t OrMask = 0x3F800000;
+
+  // The main conversion loop.
+  union
+  {
+    uint32_t AsU32;
+    float AsFP32;
+  } FPConv[4];
+
+  for (size_t CopyLoop = 0; CopyLoop < BufSize; CopyLoop++)
+  {
+    FPConv[0].AsU32 = (SrcPtr.Load(CopyLoop * 4 + 0) & AndMask) | OrMask;
+    DstPtr.Store(CopyLoop * 4 + 0, FPConv[0].AsFP32 - 1.0f);
+    FPConv[1].AsU32 = (SrcPtr.Load(CopyLoop * 4 + 1) & AndMask) | OrMask;
+    DstPtr.Store(CopyLoop * 4 + 1, FPConv[1].AsFP32 - 1.0f);
+    FPConv[2].AsU32 = (SrcPtr.Load(CopyLoop * 4 + 2) & AndMask) | OrMask;
+    DstPtr.Store(CopyLoop * 4 + 2, FPConv[2].AsFP32 - 1.0f);
+    FPConv[3].AsU32 = (SrcPtr.Load(CopyLoop * 4 + 3) & AndMask) | OrMask;
+    DstPtr.Store(CopyLoop * 4 + 3, FPConv[3].AsFP32 - 1.0f);
+  }
+#endif
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Common code.
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  FBufPos_uniform_FP32 = 0;
+}
+
+template<class SFMTParams>
+inline float CPRNG<SFMTParams>::Random_uniform_FP32(void)
+{
+  if (FBufPos_uniform_FP32 == FBufLen_uniform_FP32) RefillBuf_uniform_FP32();
+  return FBuffer_uniform_FP32.LoadFP32(EndianFix<2>(FBufPos_uniform_FP32++));
+}
+
+template<class SFMTParams>
+inline void CPRNG<SFMTParams>::RandFill_uniform_FP32(float *Buffer, size_t NumFloats)
+{
+  size_t NumToGo = NumFloats;
+  while (NumToGo > 0)
+  {
+    // Round up to the next 128-bit boundary.
+    FBufPos_uniform_FP32 = (FBufPos_uniform_FP32 + 3) & ~3;
+
+    // Make sure there's something to copy from.
+    while (FBufLen_uniform_FP32 == FBufPos_uniform_FP32)
+      RefillBuf_uniform_FP32();
+
+    // See how many to do.
+    size_t NumInBuf = FBufLen_uniform_FP32 - FBufPos_uniform_FP32;
+    size_t NumToDo = (NumToGo > NumInBuf) ? NumInBuf : NumToGo;
+
+    // Copy.
+    memcpy(Buffer, FBuffer_uniform_FP32.GetPointerFP32() + FBufPos_uniform_FP32, NumToDo * sizeof(float));
+
+    // Update pointers, etc.
+    Buffer += NumToDo;
+    NumToGo -= NumToDo;
+    FBufPos_uniform_FP32 += NumToDo;
+  }
+}
+
+// -----------------------------------------------------------------------------
+// Uniform random doubles.
+// PATHDEF UniformFP64
+// -----------------------------------------------------------------------------
+template<class SFMTParams>
+NOINLINE void CPRNG<SFMTParams>::RefillBuf_uniform_FP64(void)
+{
+  #ifndef CFG_TIMETRACK_DISABLE
+  CTimedScope ScopeTimer(Metrics.uniform_FP64_refill_time);
+  Metrics.uniform_FP64_refill_count++;
+  #endif
+
+  typename CRandPool<SFMTParams>::CRandomBlockPtr RandomBlock = FRandPool.GetRandomBlock();
+  // Don't need SIMDOps::EmptyForFP() here (handled per-path, since we've got an MMX path)
+
+#if (CFG_HAVE_U128FP64 == CFG_SIMD_INTRINSIC)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// FP64-intrinsic implementation
+// PATHNAME u128fp64intrinsic
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  SIMDOps::EmptyForFP();
+  CDataBuffer_ConstView<uint128fp64_t, BufSize * 16> SrcPtr = RandomBlock.template GetConstView<uint128fp64_t>();
+  CDataBuffer_VarView<uint128fp64_t, BufSize * 16> DstPtr = FBuffer_uniform_FP64.template GetVarView<uint128fp64_t>();
+
+  uint128fp64_t AndMask = SIMDOps::uint128fp64_t_const<0xFFFFFFFF, 0x000FFFFF, 0xFFFFFFFF, 0x000FFFFF>::Value();
+  uint128fp64_t One = SIMDOps::uint128fp64_t_const<0x00000000, 0x3FF00000, 0x00000000, 0x3FF00000>::Value();
+
+  size_t CopyLoop;
+  for (CopyLoop = 0; CopyLoop < BufSize - (BufSize % 4); CopyLoop += 4)
+  {
+    DstPtr.Store(CopyLoop + 0, SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 0), AndMask), One), One));
+    DstPtr.Store(CopyLoop + 1, SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 1), AndMask), One), One));
+    DstPtr.Store(CopyLoop + 2, SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 2), AndMask), One), One));
+    DstPtr.Store(CopyLoop + 3, SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 3), AndMask), One), One));
+  }
+
+  // Unrolling tail.
+  if ((BufSize % 4) == 3)
+  {
+    DstPtr.Store(CopyLoop + 0, SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 0), AndMask), One), One));
+    DstPtr.Store(CopyLoop + 1, SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 1), AndMask), One), One));
+    DstPtr.Store(CopyLoop + 2, SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 2), AndMask), One), One));
+  }
+  if ((BufSize % 4) == 2)
+  {
+    DstPtr.Store(CopyLoop + 0, SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 0), AndMask), One), One));
+    DstPtr.Store(CopyLoop + 1, SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 1), AndMask), One), One));
+  }
+  if ((BufSize % 4) == 1)
+  {
+    DstPtr.Store(CopyLoop + 0, SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 0), AndMask), One), One));
+  }
+#elif (CFG_HAVE_U128 == CFG_SIMD_INTRINSIC)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// U128-intrinsic, fp64-scalar implementation
+// PATHNAME u128intrinsic-fp64scalar
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  SIMDOps::EmptyForFP();
+  CDataBuffer_ConstView<uint128_t, BufSize * 16> SrcPtr = RandomBlock.template GetConstView<uint128_t>();
+  CDataBuffer_VarView<double, BufSize * 16> DstPtr = FBuffer_uniform_FP64.template GetVarView<double>();
+
+  uint128_t AndMask = SIMDOps::uint128_t_const<0xFFFFFFFF, 0x000FFFFF, 0xFFFFFFFF, 0x000FFFFF>::Value();
+  uint128_t OrMask = SIMDOps::uint128_t_const<0x00000000, 0x3FF00000, 0x00000000, 0x3FF00000>::Value();
+
+  // Unrolled part
+  union 
+  {
+    uint128_t AsU128;
+    double AsFP64[2];
+  } TempBuf[4];
+
+  size_t CopyLoop;
+  for (CopyLoop = 0; CopyLoop < BufSize - (BufSize % 4); CopyLoop += 4)
+  {
+    TempBuf[0].AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 0), AndMask), OrMask);
+    DstPtr.Store(CopyLoop * 2 + 0, TempBuf[0].AsFP64[0] - 1.0);
+    DstPtr.Store(CopyLoop * 2 + 1, TempBuf[0].AsFP64[1] - 1.0);
+    TempBuf[1].AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 1), AndMask), OrMask);
+    DstPtr.Store(CopyLoop * 2 + 2, TempBuf[1].AsFP64[0] - 1.0);
+    DstPtr.Store(CopyLoop * 2 + 3, TempBuf[1].AsFP64[1] - 1.0);
+    TempBuf[2].AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 2), AndMask), OrMask);
+    DstPtr.Store(CopyLoop * 2 + 4, TempBuf[2].AsFP64[0] - 1.0);
+    DstPtr.Store(CopyLoop * 2 + 5, TempBuf[2].AsFP64[1] - 1.0);
+    TempBuf[3].AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 3), AndMask), OrMask);
+    DstPtr.Store(CopyLoop * 2 + 6, TempBuf[3].AsFP64[0] - 1.0);
+    DstPtr.Store(CopyLoop * 2 + 7, TempBuf[3].AsFP64[1] - 1.0);
+  }
+
+  // Unrolling tail.
+  if ((BufSize % 4) == 3)
+  {
+    TempBuf[0].AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 0), AndMask), OrMask);
+    DstPtr.Store(CopyLoop * 2 + 0, TempBuf[0].AsFP64[0] - 1.0);
+    DstPtr.Store(CopyLoop * 2 + 1, TempBuf[0].AsFP64[1] - 1.0);
+    TempBuf[1].AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 1), AndMask), OrMask);
+    DstPtr.Store(CopyLoop * 2 + 2, TempBuf[1].AsFP64[0] - 1.0);
+    DstPtr.Store(CopyLoop * 2 + 3, TempBuf[1].AsFP64[1] - 1.0);
+    TempBuf[2].AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 2), AndMask), OrMask);
+    DstPtr.Store(CopyLoop * 2 + 4, TempBuf[2].AsFP64[0] - 1.0);
+    DstPtr.Store(CopyLoop * 2 + 5, TempBuf[2].AsFP64[1] - 1.0);
+  }
+  if ((BufSize % 4) == 2)
+  {
+    TempBuf[0].AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 0), AndMask), OrMask);
+    DstPtr.Store(CopyLoop * 2 + 0, TempBuf[0].AsFP64[0] - 1.0);
+    DstPtr.Store(CopyLoop * 2 + 1, TempBuf[0].AsFP64[1] - 1.0);
+    TempBuf[1].AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 1), AndMask), OrMask);
+    DstPtr.Store(CopyLoop * 2 + 2, TempBuf[1].AsFP64[0] - 1.0);
+    DstPtr.Store(CopyLoop * 2 + 3, TempBuf[1].AsFP64[1] - 1.0);
+  }
+  if ((BufSize % 4) == 1)
+  {
+    TempBuf[0].AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(CopyLoop + 0), AndMask), OrMask);
+    DstPtr.Store(CopyLoop * 2 + 0, TempBuf[0].AsFP64[0] - 1.0);
+    DstPtr.Store(CopyLoop * 2 + 1, TempBuf[0].AsFP64[1] - 1.0);
+  }
+#elif (CFG_HAVE_U128 == CFG_SIMD_MMX)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// U128-mmx, fp64-scalar two-pass implementation
+// PATHNAME u128mmx-fp64scalar-2pass
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  {
+    // Integer pass.
+    CDataBuffer_ConstView<__m64, BufSize * 16> SrcPtr = RandomBlock.template GetConstView<__m64>();
+    CDataBuffer_VarView<__m64, BufSize * 16> DstPtr = FBuffer_uniform_FP64.template GetVarView<__m64>();
+
+    __m64 AndMask = SIMDOps::__m64_const<0xFFFFFFFF, 0x000FFFFF>::Value();
+    __m64 OrMask = SIMDOps::__m64_const<0x00000000, 0x3FF00000>::Value();
+
+    size_t CopyLoop;
+    for (CopyLoop = 0; CopyLoop < BufSize - BufSize % 2; CopyLoop += 2)
+    {
+      DstPtr.Store(CopyLoop * 2 + 0, _mm_or_si64(_mm_and_si64(SrcPtr.Load(CopyLoop * 2 + 0), AndMask), OrMask));
+      DstPtr.Store(CopyLoop * 2 + 1, _mm_or_si64(_mm_and_si64(SrcPtr.Load(CopyLoop * 2 + 1), AndMask), OrMask));
+      DstPtr.Store(CopyLoop * 2 + 2, _mm_or_si64(_mm_and_si64(SrcPtr.Load(CopyLoop * 2 + 2), AndMask), OrMask));
+      DstPtr.Store(CopyLoop * 2 + 3, _mm_or_si64(_mm_and_si64(SrcPtr.Load(CopyLoop * 2 + 3), AndMask), OrMask));
+    }
+    if ((BufSize % 2) == 1)
+    {
+      DstPtr.Store(CopyLoop * 2 + 0, _mm_or_si64(_mm_and_si64(SrcPtr.Load(CopyLoop * 2 + 0), AndMask), OrMask));
+      DstPtr.Store(CopyLoop * 2 + 1, _mm_or_si64(_mm_and_si64(SrcPtr.Load(CopyLoop * 2 + 1), AndMask), OrMask));
+    }
+
+    SIMDOps::EmptyForFP();
+  }
+  {
+    // Floating point pass.
+    CDataBuffer_VarView<double, BufSize * 16> DstPtr = FBuffer_uniform_FP64.template GetVarView<double>();
+
+    size_t CopyLoop;
+    for (CopyLoop = 0; CopyLoop < BufSize - BufSize % 2; CopyLoop += 2)
+    {
+      DstPtr.Store(CopyLoop * 2 + 0, DstPtr.Load(CopyLoop * 2 + 0) - 1.0);
+      DstPtr.Store(CopyLoop * 2 + 1, DstPtr.Load(CopyLoop * 2 + 1) - 1.0);
+      DstPtr.Store(CopyLoop * 2 + 2, DstPtr.Load(CopyLoop * 2 + 2) - 1.0);
+      DstPtr.Store(CopyLoop * 2 + 3, DstPtr.Load(CopyLoop * 2 + 3) - 1.0);
+    }
+    if ((BufSize % 2) == 1)
+    {
+      DstPtr.Store(CopyLoop * 2 + 0, DstPtr.Load(CopyLoop * 2 + 0) - 1.0);
+      DstPtr.Store(CopyLoop * 2 + 1, DstPtr.Load(CopyLoop * 2 + 1) - 1.0);
+    }
+  }
+#elif (CFG_BITS == 64)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// U128-scalar, fp64-scalar 64-bit one-pass implementation
+// PATHNAME u128scalar-fp64scalar-64bit
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  SIMDOps::EmptyForFP();
+  CDataBuffer_ConstView<uint64_t, BufSize * 16> SrcPtr = RandomBlock.template GetConstView<uint64_t>();
+  CDataBuffer_VarView<double, BufSize * 16> DstPtr = FBuffer_uniform_FP64.template GetVarView<double>();
+
+  uint64_t AndMask = UINT64_C(0x000FFFFFFFFFFFFF);
+  uint64_t OrMask = UINT64_C(0x3FF0000000000000);
+
+  // The main conversion loop.
+  union
+  {
+    uint64_t AsU64;
+    double AsFP64;
+  } FPConv[2];
+
+  for (size_t CopyLoop = 0; CopyLoop < 2 * BufSize; CopyLoop += 2)
+  {
+    FPConv[0].AsU64 = (SrcPtr.Load(CopyLoop + 0) & AndMask) | OrMask;
+    DstPtr.Store(CopyLoop + 0, FPConv[0].AsFP64 - 1.0);
+    FPConv[1].AsU64 = (SrcPtr.Load(CopyLoop + 1) & AndMask) | OrMask;
+    DstPtr.Store(CopyLoop + 1, FPConv[1].AsFP64 - 1.0);
+  }
+#else
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// U128-scalar, fp64-scalar 32-bit one-pass implementation
+// PATHNAME u128scalar-fp64scalar-32bit
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  SIMDOps::EmptyForFP();
+  CDataBuffer_ConstView<uint32_t, BufSize * 16> SrcPtr = RandomBlock.template GetConstView<uint32_t>();
+  CDataBuffer_VarView<double, BufSize * 16> DstPtr = FBuffer_uniform_FP64.template GetVarView<double>();
+
+  uint32_t AndMask = 0x000FFFFF;
+  uint32_t OrMask = 0x3FF00000;
+
+  // The main conversion loop.
+  union
+  {
+    uint32_t AsU32[2];
+    double AsFP64;
+  } FPConv[2];
+
+  for (size_t CopyLoop = 0; CopyLoop < BufSize; CopyLoop++)
+  {
+    FPConv[0].AsU32[EndianFix_static<1, 1>::Value] = (SrcPtr.Load(CopyLoop * 4 + EndianFix_static<2, 1>::Value) & AndMask) | OrMask;
+    FPConv[0].AsU32[EndianFix_static<1, 0>::Value] = SrcPtr.Load(CopyLoop * 4 + EndianFix_static<2, 0>::Value);
+    DstPtr.Store(CopyLoop * 2 + EndianFix_static<1, 0>::Value, FPConv[0].AsFP64 - 1.0);
+    FPConv[1].AsU32[EndianFix_static<1, 1>::Value] = (SrcPtr.Load((CopyLoop) * 4 + EndianFix_static<2, 3>::Value) & AndMask) | OrMask;
+    FPConv[1].AsU32[EndianFix_static<1, 0>::Value] = SrcPtr.Load((CopyLoop) * 4 + EndianFix_static<2, 2>::Value);
+    DstPtr.Store(CopyLoop * 2 + EndianFix_static<1, 1>::Value, FPConv[1].AsFP64 - 1.0);
+  }
+#endif
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Common code.
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  FBufPos_uniform_FP64 = 0;
+}
+
+
+template<class SFMTParams>
+inline double CPRNG<SFMTParams>::Random_uniform_FP64(void)
+{
+  if (FBufPos_uniform_FP64 == FBufLen_uniform_FP64) RefillBuf_uniform_FP64();
+  return FBuffer_uniform_FP64.LoadFP64(EndianFix<1>(FBufPos_uniform_FP64++));
+}
+
+template<class SFMTParams>
+inline void CPRNG<SFMTParams>::RandFill_uniform_FP64(double *Buffer, size_t NumDoubles)
+{
+  size_t NumToGo = NumDoubles;
+  while (NumToGo > 0)
+  {
+    // Round up to the next 128-bit boundary.
+    FBufPos_uniform_FP64 = (FBufPos_uniform_FP64 + 1) & ~1;
+
+    // Make sure there's something to copy from.
+    while (FBufLen_uniform_FP64 == FBufPos_uniform_FP64)
+      RefillBuf_uniform_FP64();
+
+    // See how many to do.
+    size_t NumInBuf = FBufLen_uniform_FP64 - FBufPos_uniform_FP64;
+    size_t NumToDo = (NumToGo > NumInBuf) ? NumInBuf : NumToGo;
+
+    // Copy.
+    memcpy(Buffer, FBuffer_uniform_FP64.GetPointerFP64() + FBufPos_uniform_FP64, NumToDo * sizeof(double));
+
+    // Update pointers, etc.
+    Buffer += NumToDo;
+    NumToGo -= NumToDo;
+    FBufPos_uniform_FP64 += NumToDo;
+  }
+}
+
+// -----------------------------------------------------------------------------
+// Gaussian tail random numbers.
+// PATHDEF GaussianTailFP64
+// -----------------------------------------------------------------------------
+template<class SFMTParams>
+NOINLINE void CPRNG<SFMTParams>::RefillBuf_gaussiantail_FP64(void)
+{
+  #ifndef CFG_TIMETRACK_DISABLE
+  CTimedScope ScopeTimer(Metrics.gaussiantail_FP64_refill_time);
+  Metrics.gaussiantail_FP64_refill_count++;
+  #endif
+
+  typename CRandPool<SFMTParams>::CRandomBlockPtr RandomBlock = FRandPool.GetRandomBlock();
+  SIMDOps::EmptyForFP();
+
+#if (CFG_HAVE_U128 == CFG_SIMD_INTRINSIC) && (CFG_HAVE_U128FP64 == CFG_SIMD_INTRINSIC)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// U128-intrinsic, fp64-intrinsic implementation
+// PATHNAME u128fp64intrinsic
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  // Some constants.
+  uint128fp64_t SignAndMask = SIMDOps::uint128fp64_t_const<0x00000000, 0x80000000, 0x00000000, 0x80000000>::Value();
+  uint128fp64_t FPAndMask = SIMDOps::uint128fp64_t_const<0xFFFFFFFF, 0x000FFFFF, 0xFFFFFFFF, 0x000FFFFF>::Value();
+  uint128fp64_t FPOrMask = SIMDOps::uint128fp64_t_const<0x00000000, 0x3FF00000, 0x00000000, 0x3FF00000>::Value();
+
+  double a = CZigguratGaussian_FP64::Bins[1].XScale;
+  double a2 = a * a;
+  uint128fp64_t a128 = SIMDOps::make_uint128fp64_t(a, a);
+
+  // Process each of the values.
+  CDataBuffer_ConstView<uint128fp64_t, BufSize * 16> SrcPtr = RandomBlock.template GetConstView<uint128fp64_t>();
+  CDataBuffer_VarView<uint128fp64_t, BufSize / 2 * 16> DstPtr = FBuffer_gaussiantail_FP64.template GetVarView<uint128fp64_t>();
+
+  for (size_t SrcIdx = 0; SrcIdx < FBufLen_gaussiantail_FP64 / 2; SrcIdx++)
+  {
+    // From the first uint128_t, extract two fp64's (and two signs later).
+    uint128fp64_t Src = SrcPtr.Load(SrcIdx * 2);
+    uint128fp64_t u1 = SIMDOP_sub(SIMDOP_or(SIMDOP_and(Src, FPAndMask), FPOrMask), FPOrMask);
+    uint128fp64_t SignBit = SIMDOP_and(Src, SignAndMask);
+
+    // Transform u1
+    union
+    {
+      uint128fp64_t AsU128;
+      double AsFP64[2];
+    } Test = {u1};
+    Test.AsFP64[0] = sqrt(a2 - 2 * log(Test.AsFP64[0]));
+    Test.AsFP64[1] = sqrt(a2 - 2 * log(Test.AsFP64[1]));
+
+    // Calculate the compare result (u2 < a / Test) ie: Test * u2 < a
+    // Accept if Test * u2 < a
+    uint128fp64_t u2 = SIMDOP_sub(SIMDOP_or(SIMDOP_and(SrcPtr.Load(SrcIdx * 2 + 1), FPAndMask), FPOrMask), FPOrMask);
+    uint128fp64_t CompareResult = SIMDOps::CmpGE(SIMDOP_mul(Test.AsU128, u2), a128);
+
+    // Store the transformed u1.
+    DstPtr.Store(SrcIdx, SIMDOP_or(SIMDOP_or(Test.AsU128, SignBit), CompareResult));
+  }
+#elif (CFG_HAVE_U128 == CFG_SIMD_INTRINSIC) // Note: No mmx due to emms overhead.
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// U128-intrinsic, fp64-scalar implementation
+// PATHNAME u128intrinsic-fp64scalar
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  // Some constants.
+  uint128_t SignAndMask = SIMDOps::uint128_t_const<0x00000000, 0x80000000, 0x00000000, 0x80000000>::Value();
+  uint128_t FPAndMask = SIMDOps::uint128_t_const<0xFFFFFFFF, 0x000FFFFF, 0xFFFFFFFF, 0x000FFFFF>::Value();
+  uint128_t FPOrMask = SIMDOps::uint128_t_const<0x00000000, 0x3FF00000, 0x00000000, 0x3FF00000>::Value();
+
+  double a = CZigguratGaussian_FP64::Bins[1].XScale;
+  double a2 = a * a;
+
+  // Process each of the values.
+  CDataBuffer_ConstView<uint128_t, BufSize * 16> SrcPtr = RandomBlock.template GetConstView<uint128_t>();
+  CDataBuffer_VarView<uint128_t, BufSize / 2 * 16> DstPtr = FBuffer_gaussiantail_FP64.template GetVarView<uint128_t>();
+
+  union
+  {
+    uint128_t AsU128;
+    double AsFP64[2];
+  } u1;
+
+  union
+  {
+    uint128_t AsU128;
+    double AsFP64[2];
+  } u2;
+
+  for (size_t SrcIdx = 0; SrcIdx < FBufLen_gaussiantail_FP64 / 2; SrcIdx++)
+  {
+    // Extract (u1 + 1) and the sign bit.
+    uint128_t TempSrc = SrcPtr.Load(SrcIdx * 2);
+    u1.AsU128 = SIMDOP_or(SIMDOP_and(TempSrc, FPAndMask), FPOrMask);
+    uint128_t SignBit = SIMDOP_and(TempSrc, SignAndMask);
+
+    // Extract (u2 + 1).
+    u2.AsU128 = SIMDOP_or(SIMDOP_and(SrcPtr.Load(SrcIdx * 2 + 1), FPAndMask), FPOrMask);
+
+    // Transform u1.
+    double Test0 = sqrt(a2 - 2 * log(u1.AsFP64[0] - 1.0));
+    double Test1 = sqrt(a2 - 2 * log(u1.AsFP64[1] - 1.0));
+    union
+    {
+      double AsFP64[2];
+      uint128_t AsU128;
+    } Test = {{Test0, Test1}};
+
+    // Calculate the compare results (u2 < a / Test) ie: Test * u2 < a
+    // Accept if Test * u2 < a
+    #if (CFG_BITS == 64)
+    uint64_t Compare0 = ((Test0 * (u2.AsFP64[0] - 1.0)) >= a) ? UINT64_C(0xFFFFFFFFFFFFFFFF) : 0;
+    uint64_t Compare1 = ((Test1 * (u2.AsFP64[1] - 1.0)) >= a) ? UINT64_C(0xFFFFFFFFFFFFFFFF) : 0;
+    union
+    {
+      uint64_t AsU64[2];
+      uint128_t AsU128;
+    } CompareResult = {{Compare0, Compare1}};
+    #else
+    uint32_t Compare0 = ((Test0 * (u2.AsFP64[0] - 1.0)) >= a) ? 0xFFFFFFFF : 0;
+    uint32_t Compare1 = ((Test1 * (u2.AsFP64[1] - 1.0)) >= a) ? 0xFFFFFFFF : 0;
+    union
+    {
+      uint32_t AsU32[4];
+      uint128_t AsU128;
+    } CompareResult = {{Compare0, Compare0, Compare1, Compare1}};
+    #endif
+
+    // Store the transformed u1.
+    DstPtr.Store(SrcIdx, SIMDOP_or(SIMDOP_or(Test.AsU128, SignBit), CompareResult.AsU128));
+  }
+#elif (CFG_BITS == 64)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// U128-scalar, fp64-scalar 64-bit implementation
+// PATHNAME u128scalar-fp64scalar-64bit
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  // Some constants.
+  const uint64_t FPAndMask = UINT64_C(0x000FFFFFFFFFFFFF);
+  const uint64_t FPOrMask = UINT64_C(0x3FF0000000000000);
+  const uint64_t SignAndMask = UINT64_C(0x8000000000000000);
+
+  double a = CZigguratGaussian_FP64::Bins[1].XScale;
+  double a2 = a * a;
+
+  // Process each of the values.
+  CDataBuffer_ConstView<uint64_t, BufSize * 16> SrcPtr = RandomBlock.template GetConstView<uint64_t>();
+  CDataBuffer_VarView<uint64_t, BufSize / 2 * 16> DstPtr = FBuffer_gaussiantail_FP64.template GetVarView<uint64_t>();
+
+  union
+  {
+    uint64_t AsU64;
+    double AsFP64;
+  } u1;
+
+  union
+  {
+    uint64_t AsU64;
+    double AsFP64;
+  } u2;
+
+  for (size_t SrcIdx = 0; SrcIdx < FBufLen_gaussiantail_FP64 * 2; SrcIdx++)
+  {
+    // Extract (u1 + 1) and the sign bit.
+    uint64_t TmpSrc = SrcPtr.Load(SrcIdx);
+    u1.AsU64 = (TmpSrc & FPAndMask) | FPOrMask;
+    uint64_t SignBit = TmpSrc & SignAndMask;
+
+    // Extract (u2 + 1).
+    u2.AsU64 = (SrcPtr.Load(SrcIdx + 2) & FPAndMask) | FPOrMask;
+
+    // Calculate Test = sqrt(a * a - 2 * log(u1))
+    // Reuse the u1 structure to convert to a u64.
+    double Test = sqrt(a2 - 2 * log(u1.AsFP64 - 1.0));
+    u1.AsFP64 = Test;
+
+    // Calculate the destination index.
+    size_t DstIdx = (SrcIdx & 1) + (SrcIdx / 4 * 2);
+
+    // Calculate the compare result (u2 < a / Test) ie: Test * u2 < a
+    // Accept if Test * u2 < a
+    uint64_t OrMask = ((Test * (u2.AsFP64 - 1.0)) >= a) ? UINT64_C(0xFFFFFFFFFFFFFFFF) : 0;
+
+    DstPtr.Store(DstIdx, u1.AsU64 | OrMask | SignBit);
+
+    // Special counting up: we want the loop index to go 0, 1, 4, 5, 8, 9, ...
+    // since the values inbetween are used for the second random number u2.
+    SrcIdx += 2 * (SrcIdx & 1);
+  }
+#else
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// U128-scalar, fp64-scalar 32-bit implementation
+// PATHNAME u128scalar-fp64scalar-32bit
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  // Some constants.
+  const uint32_t FPAndMask = 0x000FFFFF;
+  const uint32_t FPOrMask = 0x3FF00000;
+  const uint32_t SignAndMask = 0x80000000;
+
+  double a = CZigguratGaussian_FP64::Bins[1].XScale;
+  double a2 = a * a;
+
+  // Process each of the values.
+  CDataBuffer_ConstView<uint32_t, BufSize * 16> SrcPtr = RandomBlock.template GetConstView<uint32_t>();
+  CDataBuffer_VarView<uint32_t, BufSize / 2 * 16> DstPtr = FBuffer_gaussiantail_FP64.template GetVarView<uint32_t>();
+
+  union
+  {
+    uint32_t AsU32[2];
+    double AsFP64;
+  } u1;
+
+  union
+  {
+    uint32_t AsU32[2];
+    double AsFP64;
+  } u2;
+
+  for (size_t SrcIdx = 0; SrcIdx < FBufLen_gaussiantail_FP64 * 2; SrcIdx++)
+  {
+    // Extract (u1 + 1) and the sign bit.
+    u1.AsU32[EndianFix_static<1, 0>::Value] = SrcPtr.Load(SrcIdx * 2 + EndianFix_static<1, 0>::Value);
+    uint32_t TmpSrc = SrcPtr.Load(SrcIdx * 2 + EndianFix_static<1, 1>::Value);
+    u1.AsU32[EndianFix_static<1, 1>::Value] = (TmpSrc & FPAndMask) | FPOrMask;
+    uint32_t SignBit = TmpSrc & SignAndMask;
+
+    // Extract (u2 + 1).
+    u2.AsU32[EndianFix_static<1, 0>::Value] = SrcPtr.Load((SrcIdx + 2) * 2 + EndianFix_static<1, 0>::Value);
+    u2.AsU32[EndianFix_static<1, 1>::Value] = (SrcPtr.Load((SrcIdx + 2) * 2 + EndianFix_static<1, 1>::Value) & FPAndMask) | FPOrMask;
+
+    // Calculate Test = sqrt(a * a - 2 * log(u1))
+    // Reuse the u1 structure to convert to two u32's.
+    double Test = sqrt(a2 - 2 * log(u1.AsFP64 - 1.0));
+    u1.AsFP64 = Test;
+
+    // Calculate the destination index.
+    size_t DstIdx = (SrcIdx & 1) + (SrcIdx / 4 * 2);
+
+    // Calculate the compare result (u2 < a / Test) ie: Test * u2 < a
+    // Accept if Test * u2 < a
+    uint32_t OrMask = ((Test * (u2.AsFP64 - 1.0)) >= a) ? 0xFFFFFFFF : 0;
+
+    DstPtr.Store(DstIdx * 2 + EndianFix_static<1, 0>::Value, u1.AsU32[EndianFix_static<1, 0>::Value] | OrMask);
+    DstPtr.Store(DstIdx * 2 + EndianFix_static<1, 1>::Value, u1.AsU32[EndianFix_static<1, 1>::Value] | OrMask | SignBit);
+
+    // Special counting up: we want the loop index to go 0, 1, 4, 5, 8, 9, ...
+    // since the values inbetween are used for the second random number u2.
+    SrcIdx += 2 * (SrcIdx & 1);
+  }
+#endif
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Common code.
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  FBufPos_gaussiantail_FP64 = 0;
+}
+
+template<class SFMTParams>
+inline double CPRNG<SFMTParams>::Random_gaussiantail_FP64(void)
+{
+  for (;;)
+  {
+    while (FBufPos_gaussiantail_FP64 < FBufLen_gaussiantail_FP64)
+    {
+      size_t SrcIdx = EndianFix<1>(FBufPos_gaussiantail_FP64++);
+      // If the upper 32 bits is 0xffffffff then it's a NaN so skip.
+      if (FBuffer_gaussiantail_FP64.LoadU32(SrcIdx * 2 + EndianFix_static<1, 1>::Value) != 0xffffffff)
+        return FBuffer_gaussiantail_FP64.LoadFP64(SrcIdx);
+    }
+    RefillBuf_gaussiantail_FP64();
+  }
+}
+
+template<class SFMTParams>
+inline void CPRNG<SFMTParams>::RandFill_gaussiantail_FP64(double *Buffer, size_t NumDoubles)
+{
+  size_t NumDone = 0;
+  for(;;)
+  {
+    // Copy.
+    for (size_t CopyLoop = FBufPos_gaussiantail_FP64; CopyLoop < FBufLen_gaussiantail_FP64; CopyLoop++)
+    {
+      size_t SrcIdx = EndianFix<1>(CopyLoop);
+      if (FBuffer_gaussiantail_FP64.LoadU32(SrcIdx * 2 + EndianFix_static<1, 1>::Value) != 0xffffffff)
+      {
+        Buffer[NumDone++] = FBuffer_gaussiantail_FP64.LoadFP64(SrcIdx);
+        if (NumDone == NumDoubles)
+        {
+          FBufPos_gaussiantail_FP64 = CopyLoop + 1;
+          return;
+        }
+      }
+    }
+
+    // The only way to get here is if the buffer is empty. Refill it.
+    RefillBuf_gaussiantail_FP64();    
+  }
+}
+
+// -----------------------------------------------------------------------------
+// Gaussian random numbers.
+// PATHDEF GaussianFP64
+// -----------------------------------------------------------------------------
+template<class SFMTParams>
+NOINLINE void CPRNG<SFMTParams>::RefillBuf_gaussian_FP64(void)
+{
+  #ifndef CFG_TIMETRACK_DISABLE
+  CTimedScope ScopeTimer(Metrics.gaussian_FP64_refill_time);
+  Metrics.gaussian_FP64_refill_count++;
+  #endif
+
+  typename CRandPool<SFMTParams>::CRandomBlockPtr RandomBlock = FRandPool.GetRandomBlock();
+  SIMDOps::EmptyForFP();
+  size_t DstPos = 0;
+
+#if (CFG_HAVE_U128 == CFG_SIMD_INTRINSIC) && (CFG_HAVE_U128FP64 == CFG_SIMD_INTRINSIC)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// U128-intrinsic, fp64-intrinsic implementation
+// PATHNAME u128fp64intrinsic
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  CDataBuffer_ConstView<uint128_t, BufSize * 16> SrcPtr = RandomBlock.template GetConstView<uint128_t>();
+  CDataBuffer_VarView<double, BufSize * 16> DstPtr = FBuffer_gaussian_FP64.template GetVarView<double>();
+
+  // Load a few constants.
+  uint128_t FPAndMask = SIMDOps::uint128_t_const<0xFFFFFFFF, 0x000FFFFF, 0xFFFFFFFF, 0x000FFFFF>::Value();
+  uint128fp64_t FPSignMask = SIMDOps::uint128fp64_t_const<0x00000000, 0x80000000, 0x00000000, 0x80000000>::Value();
+  uint128fp64_t FPOrMask = SIMDOps::uint128fp64_t_const<0x00000000, 0x3FF00000, 0x00000000, 0x3FF00000>::Value();
+  uint128_t BinAndMask = SIMDOps::uint128_t_const<0x00000000, 0x07F00000, 0x00000000, 0x07F00000>::Value();
+
+  union
+  {
+    uint128_t AsU128;
+    uint64_t AsU64[2];
+  } BinPos;
+
+  union
+  {
+    uint128_t AsU128;
+    uint32_t AsU32[4];
+  } BinIndex;
+
+  union
+  {
+    double AsFP64[2];
+    uint128fp64_t AsU128;
+  } FPScale;
+
+  for (size_t SrcPos = 0; SrcPos < BufSize; SrcPos++)
+  {
+    // Get a random number, uniform over (1, 1). Note that there is a slight
+    // defect in that the "zero" bin will have twice as many elements as it
+    // should (due to +/- 0). It's small enough to be irrelevant though.
+    // Also get the integer representation.
+    uint128_t SrcU128 = SrcPtr.Load(SrcPos);
+    uint128_t TempRes = SIMDOP_and(SrcU128, FPAndMask);
+    uint128fp64_t FPTemp = SIMDOP_or(
+      SIMDOP_sub(SIMDOP_or(SIMDOps::simdcast_fp64(TempRes), FPOrMask), FPOrMask),
+      SIMDOP_and(SIMDOps::simdcast_fp64(SrcU128), FPSignMask));
+
+    BinPos.AsU128 = TempRes;
+
+    // Get the bin number. Bin 0 is in EndianFix<2>(1), Bin 1 is in
+    // EndianFix<2>(1) + 2.
+    BinIndex.AsU128 = SIMDOps::Shr_u32<20>(SIMDOP_and(SrcU128, BinAndMask));
+
+    // Pack the two multiplies together.
+    FPScale.AsFP64[0] = CZigguratGaussian_FP64::Bins[BinIndex.AsU32[EndianFix_static<1, 1>::Value + 0]].XScale;
+    FPScale.AsFP64[1] = CZigguratGaussian_FP64::Bins[BinIndex.AsU32[EndianFix_static<1, 1>::Value + 2]].XScale;
+    
+    FPScale.AsU128 = SIMDOP_mul(FPScale.AsU128, FPTemp);
+
+    // Handle the first result
+    uint32_t CurBinIndex = BinIndex.AsU32[EndianFix_static<2, 1>::Value];
+    double CurFPResult = FPScale.AsFP64[EndianFix_static<1, 0>::Value];
+
+    if (BinPos.AsU64[EndianFix_static<1, 0>::Value] < CZigguratGaussian_FP64::Bins[CurBinIndex].THold)
+    {
+      // Accept.
+      DstPtr.Store(DstPos++, CurFPResult);
+    }
+    else
+    {
+      if (CurBinIndex == 0)
+      {
+        // Sample from the tail.
+        DstPtr.Store(DstPos++, Random_gaussiantail_FP64());
+      }
+      else
+      {
+        // Intermediate region.
+        double yval = exp(-CurFPResult * CurFPResult * 0.5);
+        double ysample = CZigguratGaussian_FP64::Bins[CurBinIndex].YOffset + CZigguratGaussian_FP64::Bins[CurBinIndex].YScale * Random_uniform_FP64();
+        if (ysample < yval)
+        {
+          // Accept.
+          DstPtr.Store(DstPos++, CurFPResult);
+        }
+      }
+    }
+
+    // Handle the second result
+    CurBinIndex = BinIndex.AsU32[EndianFix_static<2, 3>::Value];
+    CurFPResult = FPScale.AsFP64[EndianFix_static<1, 1>::Value];
+
+    if (BinPos.AsU64[EndianFix_static<1, 1>::Value] < CZigguratGaussian_FP64::Bins[CurBinIndex].THold)
+    {
+      // Accept.
+      DstPtr.Store(DstPos++, CurFPResult);
+    }
+    else
+    {
+      if (CurBinIndex == 0)
+      {
+        // Sample from the tail.
+        DstPtr.Store(DstPos++, Random_gaussiantail_FP64());
+      }
+      else
+      {
+        // Intermediate region.
+        double yval = exp(-CurFPResult * CurFPResult * 0.5);
+        double ysample = CZigguratGaussian_FP64::Bins[CurBinIndex].YOffset + CZigguratGaussian_FP64::Bins[CurBinIndex].YScale * Random_uniform_FP64();
+        if (ysample < yval)
+        {
+          // Accept.
+          DstPtr.Store(DstPos++, CurFPResult);
+        }
+      }
+    }
+  }
+#else
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// U128-scalar, fp64-scalar 32/64-bit implementation
+// PATHNAME u128scalar-fp64scalar
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  CDataBuffer_ConstView<uint64_t, BufSize * 16> SrcPtr = RandomBlock.template GetConstView<uint64_t>();
+  CDataBuffer_VarView<uint64_t, BufSize * 16> DstPtr = FBuffer_gaussian_FP64.template GetVarView<uint64_t>();
+
+  // Load a few constants.
+  const uint64_t FPAndMask = UINT64_C(0x000FFFFFFFFFFFFF);
+  const uint64_t FPSignMask = UINT64_C(0x8000000000000000);
+  const uint64_t FPOrMask = UINT64_C(0x3FF0000000000000);
+  const uint32_t BinAndMask = 0x0000007F;
+
+  union
+  {
+    uint64_t AsU64;
+    double AsFP64;
+  } FPConv;
+
+  for (size_t SrcPos = 0; SrcPos < BufSize * 2; SrcPos++)
+  {
+    // Get a random number, uniform over (1, 1). Note that there is a slight
+    // defect in that the "zero" bin will have twice as many elements as it
+    // should (due to +/- 0). It's small enough to be irrelevant though.
+    // Also get the integer representation.
+    uint64_t TmpSrc = SrcPtr.Load(EndianFix<1>(SrcPos));
+    uint64_t IntBinPos = (TmpSrc & FPAndMask);
+    FPConv.AsU64 = IntBinPos | FPOrMask;
+
+    // Get the bin number.
+    uint32_t BinIdx = static_cast<uint32_t>((TmpSrc >> 52) & BinAndMask);
+
+    // Scale
+    double FPResult = (FPConv.AsFP64 - 1.0) * CZigguratGaussian_FP64::Bins[BinIdx].XScale;
+    FPConv.AsFP64 = FPResult;
+
+    // Handle the result.
+    if (IntBinPos < CZigguratGaussian_FP64::Bins[BinIdx].THold)
+    {
+      // Accept.
+      FBuffer_gaussian_FP64.StoreU64(DstPos++, FPConv.AsU64 | (TmpSrc & FPSignMask));
+    }
+    else
+    {
+      if (BinIdx == 0)
+      {
+        // Sample from the tail.
+        FBuffer_gaussian_FP64.StoreFP64(DstPos++, Random_gaussiantail_FP64());
+      }
+      else
+      {
+        // Intermediate region.
+        double yval = exp(-FPResult * FPResult * 0.5);
+        double ysample = CZigguratGaussian_FP64::Bins[BinIdx].YOffset + CZigguratGaussian_FP64::Bins[BinIdx].YScale * Random_uniform_FP64();
+        if (ysample < yval)
+        {
+          // Accept.
+          FBuffer_gaussian_FP64.StoreU64(DstPos++, FPConv.AsU64 | (TmpSrc & FPSignMask));
+        }
+      }
+    }
+  }
+#endif
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Common code
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  // Store the number of numbers we actually generated.
+  FBufLen_gaussian_FP64 = DstPos;
+  FBufPos_gaussian_FP64 = 0;
+  #ifndef CFG_TIMETRACK_DISABLE
+  Metrics.gaussian_FP64_numgen += DstPos;
+  #endif
+}
+
+template<class SFMTParams>
+inline double CPRNG<SFMTParams>::Random_gaussian_FP64(void)
+{
+  CDataBuffer_ConstView<double, BufSize * 16> SrcView = FBuffer_gaussian_FP64.template GetConstView<double>();
+  for (;;)
+  {
+    if (FBufPos_gaussian_FP64 < FBufLen_gaussian_FP64)
+      return SrcView.Load(EndianFix<1>(FBufPos_gaussian_FP64++));
+    RefillBuf_gaussian_FP64();
+  }
+}
+
+template<class SFMTParams>
+inline void CPRNG<SFMTParams>::RandFill_gaussian_FP64(double *Buffer, size_t NumDoubles)
+{
+  CDataBuffer_ConstView<double, BufSize * 16> SrcView = FBuffer_gaussian_FP64.template GetConstView<double>();
+
+  // Round the source offset up to the next 128-bit boundary.
+  size_t BufPos128 = (FBufPos_gaussian_FP64 + 1) / 2;
+  size_t NumToGo128 = NumDoubles / 2;
+
+  while (NumToGo128 > 0)
+  {
+    // Make sure there's something to copy from.
+    if (BufPos128 >= FBufLen_gaussian_FP64 / 2)
+    {
+      RefillBuf_gaussian_FP64();
+      BufPos128 = 0;
+    }
+
+    // See how many to do.
+    size_t NumInBuf128 = (FBufLen_gaussian_FP64 / 2) - BufPos128;
+    size_t NumToDo128 = (NumToGo128 > NumInBuf128) ? NumInBuf128 : NumToGo128;
+
+    // Copy.
+    memcpy(Buffer, SrcView.GetPointer() + BufPos128 * 2, NumToDo128 * 16);
+
+    // Update pointers, etc.
+    Buffer += NumToDo128 * 2;
+    NumToGo128 -= NumToDo128;
+    BufPos128 += NumToDo128;
+  }
+
+  // Store the position back.
+  FBufPos_gaussian_FP64 = BufPos128 * 2;
+
+  // If there's one left, transfer it by itself.
+  if (NumDoubles % 2 == 1) *Buffer = Random_gaussian_FP64();
+}
+
+// -----------------------------------------------------------------------------
+// Integers
+// -----------------------------------------------------------------------------
+
+template<class SFMTParams>
+inline void CPRNG<SFMTParams>::RefillBuf_integer(void)
+{
+  typename CRandPool<SFMTParams>::CRandomBlockPtr RandomBlock = FRandPool.GetRandomBlock();
+  SIMDOps::EmptyForFP();
+  memcpy(FBuffer_integer.GetPointerU8(), RandomBlock.GetDataPointer(), BufSize * 16);
+  FBufPos_integer = 0;
+}
+
+template<class SFMTParams>
+inline uint32_t CPRNG<SFMTParams>::Random_u32(void)
+{
+  // Round the source offset up to the next 32-bit boundary.
+  size_t BufPos32 = (FBufPos_integer + 3) / 4;
+
+  // Refill the buffer if need be.
+  if (BufPos32 == BufSize * 4)
+  {
+    RefillBuf_integer();
+    BufPos32 = 0;
+  }
+
+  // Get the value.
+  CDataBuffer_ConstView<uint32_t, BufSize * 16> SrcView = FBuffer_integer.template GetConstView<uint32_t>();
+  uint32_t RetVal = SrcView.Load(EndianFix<2>(BufPos32));
+  FBufPos_integer = (BufPos32 + 1) * 4;
+  return RetVal;
+}
+
+template<class SFMTParams>
+inline uint32_t CPRNG<SFMTParams>::Random_u32(uint32_t MaxVal)
+{
+  if (MaxVal == 0x0FFFFFFFF) return Random_u32();
+
+  uint32_t MaxOK = 0x0FFFFFFFF - (0x0FFFFFFFF % (MaxVal + 1)) - 1;
+  uint32_t TestVal = Random_u32();
+  while (TestVal > MaxOK) TestVal = Random_u32();
+  return TestVal % (MaxVal + 1);
+}
+
+template<class SFMTParams>
+inline void CPRNG<SFMTParams>::RandFill_u32(uint32_t *Buffer, size_t NumU32s)
+{
+  uint32_t *SrcPtr = FBuffer_integer.GetPointerU32();
+
+  // Round the source offset up to the next 128-bit boundary.
+  size_t BufPos128 = (FBufPos_integer + 15) / 16;
+  size_t NumToGo128 = NumU32s / 4;
+
+  while (NumToGo128 > 0)
+  {
+    // Make sure there's something to copy from.
+    if (BufPos128 == BufSize)
+    {
+      RefillBuf_integer();
+      BufPos128 = 0;
+    }
+
+    // See how many to do.
+    size_t NumInBuf128 = BufSize - BufPos128;
+    size_t NumToDo128 = (NumToGo128 > NumInBuf128) ? NumInBuf128 : NumToGo128;
+
+    // Copy.
+    memcpy(Buffer, SrcPtr + BufPos128 * 4, NumToDo128 * 16);
+
+    // Update pointers, etc.
+    Buffer += NumToDo128 * 4;
+    NumToGo128 -= NumToDo128;
+    BufPos128 += NumToDo128;
+  }
+
+  // Store the position back.
+  FBufPos_integer = BufPos128 * 16;
+
+  // Handle any remaining elements.
+  switch(NumU32s % 4)
+  {
+    case 3:
+      Buffer[0] = Random_u32();
+      Buffer[1] = Random_u32();
+      Buffer[2] = Random_u32();
+      break;
+    case 2:
+      Buffer[0] = Random_u32();
+      Buffer[1] = Random_u32();
+      break;
+    case 1:
+      Buffer[0] = Random_u32();
+      break;
+  }
+}
+
+// -----------------------------------------------------------------------------
+// Exponential random doubles.
+// PATHDEF ExponentialFP64
+// -----------------------------------------------------------------------------
+template<class SFMTParams>
+NOINLINE void CPRNG<SFMTParams>::RefillBuf_exponential_FP64(void)
+{
+  #ifndef CFG_TIMETRACK_DISABLE
+  CTimedScope ScopeTimer(Metrics.exponential_FP64_refill_time);
+  Metrics.exponential_FP64_refill_count++;
+  #endif
+
+  typename CRandPool<SFMTParams>::CRandomBlockPtr RandomBlock = FRandPool.GetRandomBlock();
+  SIMDOps::EmptyForFP();
+
+  double ScaleFactor = FScaleFactor_exponential_FP64;
+  size_t DstPos = 0;
+
+#if (CFG_HAVE_U128 == CFG_SIMD_INTRINSIC) && (CFG_HAVE_U128FP64 == CFG_SIMD_INTRINSIC)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// U128-intrinsic, fp64-intrinsic implementation
+// PATHNAME u128fp64intrinsic
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  CDataBuffer_ConstView<uint128_t, BufSize * 16> SrcPtr = RandomBlock.template GetConstView<uint128_t>();
+  CDataBuffer_VarView<double, BufSize * 16> DstPtr = FBuffer_exponential_FP64.template GetVarView<double>();
+
+  // Load a few constants.
+  uint128_t FPAndMask = SIMDOps::uint128_t_const<0xFFFFFFFF, 0x000FFFFF, 0xFFFFFFFF, 0x000FFFFF>::Value();
+  uint128fp64_t FPOrMask = SIMDOps::uint128fp64_t_const<0x00000000, 0x3FF00000, 0x00000000, 0x3FF00000>::Value();
+  uint128_t BinAndMask = SIMDOps::uint128_t_const<0x00000000, 0x07F00000, 0x00000000, 0x07F00000>::Value();
+
+  for (size_t SrcPos = 0; SrcPos < BufSize; SrcPos++)
+  {
+    // Get a random number, uniform over [0, 1). Also get the integer representation.
+    uint128_t SrcU128 = SrcPtr.Load(SrcPos);
+    uint128_t TempRes = SIMDOP_and(SrcU128, FPAndMask);
+    uint128fp64_t FPTemp = SIMDOP_sub(SIMDOP_or(SIMDOps::simdcast_fp64(TempRes), FPOrMask), FPOrMask);
+
+    union
+    {
+      uint128_t AsU128;
+      uint64_t AsU64[2];
+    } BinPos = {TempRes};
+
+    // Get the bin number. Bin 0 is in EndianFix<2>(1), Bin 1 is in
+    // EndianFix<2>(1) + 2.
+    union
+    {
+      uint128_t AsU128;
+      uint32_t AsU32[4];
+    } BinIndex = {SIMDOps::Shr_u32<20>(SIMDOP_and(SrcU128, BinAndMask))};
+
+    // Pack the two multiplies together.
+    union
+    {
+      double AsFP64[2];
+      uint128fp64_t AsU128;
+    } FPScale = {{
+      CZigguratExponential_FP64::Bins[BinIndex.AsU32[EndianFix_static<1, 1>::Value + 0]].XScale,
+      CZigguratExponential_FP64::Bins[BinIndex.AsU32[EndianFix_static<1, 1>::Value + 2]].XScale}};
+
+    union
+    {
+      uint128fp64_t AsU128;
+      double AsFP64[2];
+    } FPResult = {SIMDOP_mul(FPTemp, FPScale.AsU128)};
+
+    // Handle the first result
+    uint32_t CurBinIndex = BinIndex.AsU32[EndianFix_static<2, 1>::Value];
+    double CurFPResult = FPResult.AsFP64[EndianFix_static<1, 0>::Value];
+
+    if (BinPos.AsU64[EndianFix_static<1, 0>::Value] < CZigguratExponential_FP64::Bins[CurBinIndex].THold)
+    {
+      // Accept.
+      DstPtr.Store(DstPos++, CurFPResult + ScaleFactor);
+      ScaleFactor = 0;
+    }
+    else
+    {
+      if (CurBinIndex == 0)
+      {
+        // Sample from the tail. Actually, this is just another sample with a scalefactor!
+        ScaleFactor += CZigguratExponential_FP64::Bins[1].XScale;
+      }
+      else
+      {
+        // Intermediate region.
+        double yval = exp(-CurFPResult);
+        double ysample = CZigguratExponential_FP64::Bins[CurBinIndex].YOffset + CZigguratExponential_FP64::Bins[CurBinIndex].YScale * Random_uniform_FP64();
+        if (ysample < yval)
+        {
+          // Accept.
+          DstPtr.Store(DstPos++, CurFPResult + ScaleFactor);
+          ScaleFactor = 0;
+        }
+      }
+    }
+
+    // Handle the second result
+    CurBinIndex = BinIndex.AsU32[EndianFix_static<2, 3>::Value];
+    CurFPResult = FPResult.AsFP64[EndianFix_static<1, 1>::Value];
+
+    if (BinPos.AsU64[EndianFix_static<1, 1>::Value] < CZigguratExponential_FP64::Bins[CurBinIndex].THold)
+    {
+      // Accept.
+      DstPtr.Store(DstPos++, CurFPResult + ScaleFactor);
+      ScaleFactor = 0;
+    }
+    else
+    {
+      if (CurBinIndex == 0)
+      {
+        // Sample from the tail. Actually, this is just another sample with a scalefactor!
+        ScaleFactor += CZigguratExponential_FP64::Bins[1].XScale;
+      }
+      else
+      {
+        // Intermediate region.
+        double yval = exp(-CurFPResult);
+        double ysample = CZigguratExponential_FP64::Bins[CurBinIndex].YOffset + CZigguratExponential_FP64::Bins[CurBinIndex].YScale * Random_uniform_FP64();
+        if (ysample < yval)
+        {
+          // Accept.
+          DstPtr.Store(DstPos++, CurFPResult + ScaleFactor + ScaleFactor);
+          ScaleFactor = 0;
+        }
+      }
+    }
+  }
+#else
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// U128-scalar, fp64-scalar 32/64-bit implementation
+// PATHNAME u128scalar-fp64scalar
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  CDataBuffer_ConstView<uint64_t, BufSize * 16> SrcPtr = RandomBlock.template GetConstView<uint64_t>();
+  CDataBuffer_VarView<double, BufSize * 16> DstPtr = FBuffer_exponential_FP64.template GetVarView<double>();
+
+  // Load a few constants.
+  const uint64_t FPAndMask = UINT64_C(0x000FFFFFFFFFFFFF);
+  const uint64_t FPOrMask = UINT64_C(0x3FF0000000000000);
+  const uint32_t BinAndMask = 0x0000007F;
+
+  union
+  {
+    uint64_t AsU64;
+    double AsFP64;
+  } u1;
+
+  for (size_t SrcPos = 0; SrcPos < BufSize * 2; SrcPos++)
+  {
+    // Get a random number, uniform over [1, 2). Also get the integer representation.
+    uint64_t TmpSrc = SrcPtr.Load(EndianFix<1>(SrcPos));
+    uint64_t IntBinPos = (TmpSrc & FPAndMask);
+    u1.AsU64 = IntBinPos | FPOrMask;
+
+    // Get the bin number.
+    uint32_t BinIdx = static_cast<uint32_t>((TmpSrc >> 52) & BinAndMask);
+
+    // Scale
+    double FPResult = (u1.AsFP64 - 1.0) * CZigguratExponential_FP64::Bins[BinIdx].XScale;
+
+    // Handle the result.
+    if (IntBinPos < CZigguratExponential_FP64::Bins[BinIdx].THold)
+    {
+      // Accept.
+      DstPtr.Store(DstPos++, FPResult + ScaleFactor);
+      ScaleFactor = 0;
+    }
+    else
+    {
+      if (BinIdx == 0)
+      {
+        // Sample from the tail. Actually, this is just another sample with a scalefactor!
+        ScaleFactor += CZigguratExponential_FP64::Bins[1].XScale;
+      }
+      else
+      {
+        // Intermediate region.
+        double yval = exp(-FPResult);
+        double ysample = CZigguratExponential_FP64::Bins[BinIdx].YOffset + CZigguratExponential_FP64::Bins[BinIdx].YScale * Random_uniform_FP64();
+        if (ysample < yval)
+        {
+          // Accept.
+          DstPtr.Store(DstPos++, FPResult + ScaleFactor);
+          ScaleFactor = 0;
+        }
+      }
+    }
+  }
+#endif
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Common code
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  // Store the number of numbers we actually generated.
+  FBufLen_exponential_FP64 = DstPos;
+  FBufPos_exponential_FP64 = 0;
+  FScaleFactor_exponential_FP64 = ScaleFactor;
+  #ifndef CFG_TIMETRACK_DISABLE
+  Metrics.exponential_FP64_numgen += DstPos;
+  #endif
+}
+
+template<class SFMTParams>
+inline double CPRNG<SFMTParams>::Random_exponential_FP64(void)
+{
+  CDataBuffer_ConstView<double, BufSize * 16> SrcView = FBuffer_exponential_FP64.template GetConstView<double>();
+  for (;;)
+  {
+    if (FBufPos_exponential_FP64 < FBufLen_exponential_FP64)
+      return SrcView.Load(EndianFix<1>(FBufPos_exponential_FP64++));
+    RefillBuf_exponential_FP64();
+  }
+}
+
+template<class SFMTParams>
+inline void CPRNG<SFMTParams>::RandFill_exponential_FP64(double *Buffer, size_t NumDoubles)
+{
+  CDataBuffer_ConstView<double, BufSize * 16> SrcView = FBuffer_exponential_FP64.template GetConstView<double>();
+
+  // Round the source offset up to the next 128-bit boundary.
+  size_t BufPos128 = (FBufPos_exponential_FP64 + 1) / 2;
+  size_t NumToGo128 = NumDoubles / 2;
+
+  while (NumToGo128 > 0)
+  {
+    // Make sure there's something to copy from.
+    if (BufPos128 >= FBufLen_exponential_FP64 / 2)
+    {
+      RefillBuf_exponential_FP64();
+      BufPos128 = 0;
+    }
+
+
+    // See how many to do.
+    size_t NumInBuf128 = (FBufLen_exponential_FP64 / 2) - BufPos128;
+    size_t NumToDo128 = (NumToGo128 > NumInBuf128) ? NumInBuf128 : NumToGo128;
+
+    // Copy.
+    memcpy(Buffer, SrcView.GetPointer() + BufPos128 * 2, NumToDo128 * 16);
+
+    // Update pointers, etc.
+    Buffer += NumToDo128 * 2;
+    NumToGo128 -= NumToDo128;
+    BufPos128 += NumToDo128;
+  }
+
+  // Store the position back.
+  FBufPos_exponential_FP64 = BufPos128 * 2;
+
+  // If there's one left, transfer it by itself.
+  if (NumDoubles % 2 == 1) *Buffer = Random_exponential_FP64();
+}
+
+// -----------------------------------------------------------------------------
+// Exponential random singles.
+// PATHDEF ExponentialFP32
+// -----------------------------------------------------------------------------
+template<class SFMTParams>
+NOINLINE void CPRNG<SFMTParams>::RefillBuf_exponential_FP32(void)
+{
+  #ifndef CFG_TIMETRACK_DISABLE
+  CTimedScope ScopeTimer(Metrics.exponential_FP32_refill_time);
+  Metrics.exponential_FP32_refill_count++;
+  #endif
+
+  typename CRandPool<SFMTParams>::CRandomBlockPtr RandomBlock = FRandPool.GetRandomBlock();
+  SIMDOps::EmptyForFP();
+
+  float ScaleFactor = FScaleFactor_exponential_FP32;
+  size_t DstPos = 0;
+
+#if (CFG_HAVE_U128 == CFG_SIMD_INTRINSIC) && (CFG_HAVE_U128FP32 == CFG_SIMD_INTRINSIC)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// U128-intrinsic, fp32-intrinsic implementation
+// PATHNAME u128fp32intrinsic
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  CDataBuffer_ConstView<uint128_t, BufSize * 16> SrcPtr = RandomBlock.template GetConstView<uint128_t>();
+  CDataBuffer_VarView<float, BufSize * 16> DstPtr = FBuffer_exponential_FP32.template GetVarView<float>();
+
+  // Load a few constants.
+  uint128_t FPAndMask = SIMDOps::uint128_t_const<0x007FFFFF, 0x007FFFFF, 0x007FFFFF, 0x007FFFFF>::Value();
+  uint128fp32_t FPOrMask = SIMDOps::uint128fp32_t_const<0x3F800000, 0x3F800000, 0x3F800000, 0x3F800000>::Value();
+  uint128_t BinAndMask = SIMDOps::uint128_t_const<0x7F800000, 0x7F800000, 0x7F800000, 0x7F800000>::Value();
+
+  for (size_t SrcPos = 0; SrcPos < BufSize; SrcPos++)
+  {
+    // Get a random number, uniform over [0, 1). Also get the integer representation.
+    uint128_t SrcU128 = SrcPtr.Load(SrcPos);
+    uint128_t TempRes = SIMDOP_and(SrcU128, FPAndMask);
+    uint128fp32_t FPTemp = SIMDOP_sub(SIMDOP_or(SIMDOps::simdcast_fp32(TempRes), FPOrMask), FPOrMask);
+
+    union
+    {
+      uint128_t AsU128;
+      uint32_t AsU32[4];
+    } BinPos = {TempRes};
+
+    // Get the bin number.
+    union
+    {
+      uint128_t AsU128;
+      uint32_t AsU32[4];
+    } BinIndex = {SIMDOps::Shr_u32<23>(SIMDOP_and(SrcU128, BinAndMask))};
+
+    // Pack the four multiplies together.
+    union
+    {
+      float AsFP32[4];
+      uint128fp32_t AsU128;
+    } FPScale = {{
+      CZigguratExponential_FP32::Bins[BinIndex.AsU32[0]].XScale,
+      CZigguratExponential_FP32::Bins[BinIndex.AsU32[1]].XScale,
+      CZigguratExponential_FP32::Bins[BinIndex.AsU32[2]].XScale,
+      CZigguratExponential_FP32::Bins[BinIndex.AsU32[3]].XScale}};
+
+    union
+    {
+      uint128fp32_t AsU128;
+      float AsFP32[4];
+    } FPResult = {SIMDOP_mul(FPTemp, FPScale.AsU128)};
+
+    // Handle the first result
+    uint32_t CurBinIndex = BinIndex.AsU32[EndianFix_static<2, 0>::Value];
+    float CurFPResult = FPResult.AsFP32[EndianFix_static<2, 0>::Value];
+
+    if (BinPos.AsU32[EndianFix_static<2, 0>::Value] < CZigguratExponential_FP32::Bins[CurBinIndex].THold)
+    {
+      // Accept.
+      DstPtr.Store(DstPos++, CurFPResult + ScaleFactor);
+      ScaleFactor = 0;
+    }
+    else
+    {
+      if (CurBinIndex == 0)
+      {
+        // Sample from the tail. Actually, this is just another sample with a scalefactor!
+        ScaleFactor += CZigguratExponential_FP32::Bins[1].XScale;
+      }
+      else
+      {
+        // Intermediate region.
+        float yval = exp(-CurFPResult);
+        float ysample = CZigguratExponential_FP32::Bins[CurBinIndex].YOffset + CZigguratExponential_FP32::Bins[CurBinIndex].YScale * Random_uniform_FP32();
+        if (ysample < yval)
+        {
+          // Accept.
+          DstPtr.Store(DstPos++, CurFPResult + ScaleFactor);
+          ScaleFactor = 0;
+        }
+      }
+    }
+
+    // Handle the second result
+    CurBinIndex = BinIndex.AsU32[EndianFix_static<2, 1>::Value];
+    CurFPResult = FPResult.AsFP32[EndianFix_static<2, 1>::Value];
+
+    if (BinPos.AsU32[EndianFix_static<2, 1>::Value] < CZigguratExponential_FP32::Bins[CurBinIndex].THold)
+    {
+      // Accept.
+      DstPtr.Store(DstPos++, CurFPResult + ScaleFactor);
+      ScaleFactor = 0;
+    }
+    else
+    {
+      if (CurBinIndex == 0)
+      {
+        // Sample from the tail. Actually, this is just another sample with a scalefactor!
+        ScaleFactor += CZigguratExponential_FP32::Bins[1].XScale;
+      }
+      else
+      {
+        // Intermediate region.
+        float yval = exp(-CurFPResult);
+        float ysample = CZigguratExponential_FP32::Bins[CurBinIndex].YOffset + CZigguratExponential_FP32::Bins[CurBinIndex].YScale * Random_uniform_FP32();
+        if (ysample < yval)
+        {
+          // Accept.
+          DstPtr.Store(DstPos++, CurFPResult + ScaleFactor);
+          ScaleFactor = 0;
+        }
+      }
+    }
+
+    // Handle the third result
+    CurBinIndex = BinIndex.AsU32[EndianFix_static<2, 2>::Value];
+    CurFPResult = FPResult.AsFP32[EndianFix_static<2, 2>::Value];
+
+    if (BinPos.AsU32[EndianFix_static<2, 2>::Value] < CZigguratExponential_FP32::Bins[CurBinIndex].THold)
+    {
+      // Accept.
+      DstPtr.Store(DstPos++, CurFPResult + ScaleFactor);
+      ScaleFactor = 0;
+    }
+    else
+    {
+      if (CurBinIndex == 0)
+      {
+        // Sample from the tail. Actually, this is just another sample with a scalefactor!
+        ScaleFactor += CZigguratExponential_FP32::Bins[1].XScale;
+      }
+      else
+      {
+        // Intermediate region.
+        float yval = exp(-CurFPResult);
+        float ysample = CZigguratExponential_FP32::Bins[CurBinIndex].YOffset + CZigguratExponential_FP32::Bins[CurBinIndex].YScale * Random_uniform_FP32();
+        if (ysample < yval)
+        {
+          // Accept.
+          DstPtr.Store(DstPos++, CurFPResult + ScaleFactor);
+          ScaleFactor = 0;
+        }
+      }
+    }
+
+    // Handle the fourth result
+    CurBinIndex = BinIndex.AsU32[EndianFix_static<2, 3>::Value];
+    CurFPResult = FPResult.AsFP32[EndianFix_static<2, 3>::Value];
+
+    if (BinPos.AsU32[EndianFix_static<2, 3>::Value] < CZigguratExponential_FP32::Bins[CurBinIndex].THold)
+    {
+      // Accept.
+      DstPtr.Store(DstPos++, CurFPResult + ScaleFactor);
+      ScaleFactor = 0;
+    }
+    else
+    {
+      if (CurBinIndex == 0)
+      {
+        // Sample from the tail. Actually, this is just another sample with a scalefactor!
+        ScaleFactor += CZigguratExponential_FP32::Bins[1].XScale;
+      }
+      else
+      {
+        // Intermediate region.
+        float yval = exp(-CurFPResult);
+        float ysample = CZigguratExponential_FP32::Bins[CurBinIndex].YOffset + CZigguratExponential_FP32::Bins[CurBinIndex].YScale * Random_uniform_FP32();
+        if (ysample < yval)
+        {
+          // Accept.
+          DstPtr.Store(DstPos++, CurFPResult + ScaleFactor);
+          ScaleFactor = 0;
+        }
+      }
+    }
+  }
+#else
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// U128-scalar, fp32-scalar 32/64-bit implementation
+// PATHNAME u128scalar-fp32scalar
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  CDataBuffer_ConstView<uint64_t, BufSize * 16> SrcPtr = RandomBlock.template GetConstView<uint64_t>();
+  CDataBuffer_VarView<float, BufSize * 16> DstPtr = FBuffer_exponential_FP32.template GetVarView<float>();
+
+  // Load a few constants.
+  const uint64_t FPAndMask = UINT64_C(0x007FFFFF007FFFFF);
+  const uint64_t FPOrMask = UINT64_C(0x3F8000003F800000);
+  const uint32_t BinAndMask = 0x000000FF;
+
+  union
+  {
+    uint64_t AsU64;
+    float AsFP32[2];
+  } u1;
+
+  for (size_t SrcPos = 0; SrcPos < BufSize * 2; SrcPos++)
+  {
+    // Get a random number, uniform over [1, 2). Also get the integer representation.
+    uint64_t TmpSrc = SrcPtr.Load(EndianFix<1>(SrcPos));
+    uint64_t IntBinPos64 = (TmpSrc & FPAndMask);
+    u1.AsU64 = IntBinPos64 | FPOrMask;
+
+    // Handle the first result.
+    // Get the bin number and position.
+    uint32_t BinIdx = static_cast<uint32_t>(TmpSrc >> 23) & BinAndMask;
+
+    // Scale
+    float FPResult = (u1.AsFP32[EndianFix_static<1, 0>::Value] - 1.0f) * CZigguratExponential_FP32::Bins[BinIdx].XScale;
+
+    // Store if we should.
+    uint32_t IntBinPos = static_cast<uint32_t>(IntBinPos64);
+    if (IntBinPos < CZigguratExponential_FP32::Bins[BinIdx].THold)
+    {
+      // Accept.
+      DstPtr.Store(DstPos++, FPResult + ScaleFactor);
+      ScaleFactor = 0;
+    }
+    else
+    {
+      if (BinIdx == 0)
+      {
+        // Sample from the tail. Actually, this is just another sample with a scalefactor!
+        ScaleFactor += CZigguratExponential_FP32::Bins[1].XScale;
+      }
+      else
+      {
+        // Intermediate region.
+        float yval = expf(-FPResult);
+        float ysample = CZigguratExponential_FP32::Bins[BinIdx].YOffset + CZigguratExponential_FP32::Bins[BinIdx].YScale * Random_uniform_FP32();
+        if (ysample < yval)
+        {
+          // Accept.
+          DstPtr.Store(DstPos++, FPResult + ScaleFactor);
+          ScaleFactor = 0;
+        }
+      }
+    }
+
+    // Handle the second result.
+    // Get the bin number and position.
+    BinIdx = static_cast<uint32_t>(TmpSrc >> (23 + 32)) & BinAndMask;
+
+    // Scale
+    FPResult = (u1.AsFP32[EndianFix_static<1, 1>::Value] - 1.0f) * CZigguratExponential_FP32::Bins[BinIdx].XScale;
+
+    // Store if we should.
+    IntBinPos = static_cast<uint32_t>(IntBinPos64 >> 32);
+    if (IntBinPos < CZigguratExponential_FP32::Bins[BinIdx].THold)
+    {
+      // Accept.
+      DstPtr.Store(DstPos++, FPResult + ScaleFactor);
+      ScaleFactor = 0;
+    }
+    else
+    {
+      if (BinIdx == 0)
+      {
+        // Sample from the tail. Actually, this is just another sample with a scalefactor!
+        ScaleFactor += CZigguratExponential_FP32::Bins[1].XScale;
+      }
+      else
+      {
+        // Intermediate region.
+        float yval = expf(-FPResult);
+        float ysample = CZigguratExponential_FP32::Bins[BinIdx].YOffset + CZigguratExponential_FP32::Bins[BinIdx].YScale * Random_uniform_FP32();
+        if (ysample < yval)
+        {
+          // Accept.
+          DstPtr.Store(DstPos++, FPResult + ScaleFactor);
+          ScaleFactor = 0;
+        }
+      }
+    }
+  }
+#endif
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Common code
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  // Store the number of numbers we actually generated.
+  FBufLen_exponential_FP32 = DstPos;
+  FBufPos_exponential_FP32 = 0;
+  FScaleFactor_exponential_FP32 = ScaleFactor;
+  #ifndef CFG_TIMETRACK_DISABLE
+  Metrics.exponential_FP32_numgen += DstPos;
+  #endif
+}
+
+template<class SFMTParams>
+inline float CPRNG<SFMTParams>::Random_exponential_FP32(void)
+{
+  CDataBuffer_ConstView<float, BufSize * 16> SrcView = FBuffer_exponential_FP32.template GetConstView<float>();
+  for (;;)
+  {
+    if (FBufPos_exponential_FP32 < FBufLen_exponential_FP32)
+      return SrcView.Load(EndianFix<2>(FBufPos_exponential_FP32++));
+    RefillBuf_exponential_FP32();
+  }
+}
+
+template<class SFMTParams>
+inline void CPRNG<SFMTParams>::RandFill_exponential_FP32(float *Buffer, size_t NumFloats)
+{
+  CDataBuffer_ConstView<float, BufSize * 16> SrcView = FBuffer_exponential_FP32.template GetConstView<float>();
+
+  // Round the source offset up to the next 128-bit boundary.
+  size_t BufPos128 = (FBufPos_exponential_FP32 + 3) / 4;
+  size_t NumToGo128 = NumFloats / 4;
+
+  while (NumToGo128 > 0)
+  {
+    // Make sure there's something to copy from.
+    if (BufPos128 >= FBufLen_exponential_FP32 / 4)
+    {
+      RefillBuf_exponential_FP32();
+      BufPos128 = 0;
+    }
+
+    // See how many to do.
+    size_t NumInBuf128 = (FBufLen_exponential_FP32 / 4) - BufPos128;
+    size_t NumToDo128 = (NumToGo128 > NumInBuf128) ? NumInBuf128 : NumToGo128;
+
+    // Copy.
+    memcpy(Buffer, SrcView.GetPointer() + BufPos128 * 4, NumToDo128 * 16);
+
+    // Update pointers, etc.
+    Buffer += NumToDo128 * 4;
+    NumToGo128 -= NumToDo128;
+    BufPos128 += NumToDo128;
+  }
+
+  // Store the position back.
+  FBufPos_exponential_FP32 = BufPos128 * 4;
+
+  // If there's one left, transfer it by itself.
+  switch(NumFloats % 4)
+  {
+    case 3:
+      *(Buffer++) = Random_exponential_FP32();
+    case 2:
+      *(Buffer++) = Random_exponential_FP32();
+    case 1:
+      *(Buffer++) = Random_exponential_FP32();
+    case 0:
+      // Do nothing.
+      break;
+  }
+}
+
+#ifndef CFG_TIMETRACK_DISABLE
+template<class SFMTParams> typename CPRNG<SFMTParams>::TMetrics CPRNG<SFMTParams>::Metrics;
+template<class SFMTParams> THREADVAR uint32_t CPRNG<SFMTParams>::TMetrics::uniform_FP64_refill_count = 0;
+template<class SFMTParams> THREADVAR uint64_t CPRNG<SFMTParams>::TMetrics::uniform_FP64_refill_time = 0;
+template<class SFMTParams> THREADVAR uint32_t CPRNG<SFMTParams>::TMetrics::uniform_FP32_refill_count = 0;
+template<class SFMTParams> THREADVAR uint64_t CPRNG<SFMTParams>::TMetrics::uniform_FP32_refill_time = 0;
+template<class SFMTParams> THREADVAR uint32_t CPRNG<SFMTParams>::TMetrics::gaussiantail_FP64_refill_count = 0;
+template<class SFMTParams> THREADVAR uint64_t CPRNG<SFMTParams>::TMetrics::gaussiantail_FP64_refill_time = 0;
+template<class SFMTParams> THREADVAR uint32_t CPRNG<SFMTParams>::TMetrics::gaussian_FP64_refill_count = 0;
+template<class SFMTParams> THREADVAR uint64_t CPRNG<SFMTParams>::TMetrics::gaussian_FP64_refill_time = 0;
+template<class SFMTParams> THREADVAR uint64_t CPRNG<SFMTParams>::TMetrics::gaussian_FP64_numgen = 0;
+template<class SFMTParams> THREADVAR uint32_t CPRNG<SFMTParams>::TMetrics::exponential_FP64_refill_count = 0;
+template<class SFMTParams> THREADVAR uint64_t CPRNG<SFMTParams>::TMetrics::exponential_FP64_refill_time = 0;
+template<class SFMTParams> THREADVAR uint64_t CPRNG<SFMTParams>::TMetrics::exponential_FP64_numgen = 0;
+template<class SFMTParams> THREADVAR uint32_t CPRNG<SFMTParams>::TMetrics::exponential_FP32_refill_count = 0;
+template<class SFMTParams> THREADVAR uint64_t CPRNG<SFMTParams>::TMetrics::exponential_FP32_refill_time = 0;
+template<class SFMTParams> THREADVAR uint64_t CPRNG<SFMTParams>::TMetrics::exponential_FP32_numgen = 0;
+#endif
+
+#endif
diff --git a/xpdeint/includes/solirte/randpool.h b/xpdeint/includes/solirte/randpool.h
new file mode 100644
index 0000000..8f241f8
--- /dev/null
+++ b/xpdeint/includes/solirte/randpool.h
@@ -0,0 +1,684 @@
+/* *****************************************************************************
+/
+/ This file is part of Solirte, a solenoid ion ray-tracing engine.
+/ (c) 2008 Michael Brown.
+/ michael.brown at anu.edu.au
+/
+/ An object that hands out blocks of random data.
+/ *************************************************************************** */
+
+#ifndef RANDPOOL_H
+#define RANDPOOL_H
+
+#include <iostream>
+#include <iomanip>
+#include <string>
+#include <sstream>
+#include <string.h>
+
+#include "u128simd.h"
+
+#ifndef CFG_TIMETRACK_DISABLE
+#include "../platform/timetrack.h"
+#endif
+
+#define CFG_RANDPOOL_IMPL_SSE2 1
+#define CFG_RANDPOOL_IMPL_ALTIVEC 2
+#define CFG_RANDPOOL_IMPL_64BIT 3
+#define CFG_RANDPOOL_IMPL_32BITSLOW 4
+#define CFG_RANDPOOL_IMPL_MMX 5
+
+#if (CFG_HAVE_SSE2 == 1)
+  #define CFG_RANDPOOL_IMPL CFG_RANDPOOL_IMPL_SSE2
+#endif
+#if ((CFG_BITS == 64) && !defined(CFG_RANDPOOL_IMPL))
+  #define CFG_RANDPOOL_IMPL CFG_RANDPOOL_IMPL_64BIT
+#endif
+#if ((CFG_HAVE_MMX == 1) && !defined(CFG_RANDPOOL_IMPL))
+  #define CFG_RANDPOOL_IMPL CFG_RANDPOOL_IMPL_MMX
+#endif
+#if (!defined(CFG_RANDPOOL_IMPL))
+  #define CFG_RANDPOOL_IMPL CFG_RANDPOOL_IMPL_32BITSLOW
+#endif
+
+#if (CFG_RANDPOOL_IMPL == CFG_RANDPOOL_IMPL_MMX)
+  #include "sfmt_mmx.h"
+#endif
+
+#if CFG_COMPILER == CFG_COMPILER_MSVC
+// Shut up one of the more braindead MSVC warnings.
+#pragma warning(push)
+#pragma warning(disable: 4127)
+#endif
+
+template <class SFMTConsts>
+class CRandPool
+{
+  public:
+    static const size_t N = SFMTConsts::MEXP / 128 + 1;
+    static const size_t N32 = N * 4;
+
+    #ifndef CFG_TIMETRACK_DISABLE
+    static struct TMetrics
+    {
+      static THREADVAR uint32_t poolmoves;
+      static THREADVAR uint32_t gen_rand_all_count;
+      static THREADVAR uint64_t gen_rand_all_time;
+      TMetrics(void)
+      {
+        CPerfCounters::SetName(poolmoves, "CRandPool<" + GenToString(SFMTConsts::MEXP) + ">.poolmoves");
+        CPerfCounters::SetName(gen_rand_all_count, "CPRNG<" + GenToString(SFMTConsts::MEXP) + ">.gen_rand_all.count");
+        CPerfCounters::SetName(gen_rand_all_time, "CPRNG<" + GenToString(SFMTConsts::MEXP) + ">.gen_rand_all.time");
+      }
+
+      void ForceConstruction(void) { }
+    } Metrics;
+    #endif
+
+    typedef CDataBuffer_ConstView<uint32_t, N * 16> TPoolConstViewU32;
+    typedef CDataBuffer_VarView<uint32_t, N * 16> TPoolVarViewU32;
+    typedef CDataBuffer_ConstView<uint64_t, N * 16> TPoolConstViewU64;
+    typedef CDataBuffer_VarView<uint64_t, N * 16> TPoolVarViewU64;
+    #if CFG_HAVE_U128 == CFG_SIMD_INTRINSIC
+    typedef CDataBuffer_ConstView<uint128_t, N * 16> TPoolViewConstU128;
+    typedef CDataBuffer_VarView<uint128_t, N * 16> TPoolViewVarU128;
+    #endif
+    #if CFG_HAVE_U128FP64 == CFG_SIMD_INTRINSIC
+    typedef CDataBuffer_ConstView<uint128fp64_t, N * 16> TPoolConstViewU128FP64;
+    typedef CDataBuffer_VarView<uint128fp64_t, N * 16> TPoolVarViewU128FP64;
+    #endif
+
+    class CRandomBlock
+    {
+      private:
+        CDataBuffer<N * 16> FPool;
+        int FRefCount;
+      protected:
+      public:
+        CRandomBlock(void) { FRefCount = 1; }
+        int AddRef(void) { return ++FRefCount; }
+        int GetRefCount(void) { return FRefCount; }
+        int Release(void)
+        {
+          if (--FRefCount == 0)
+          {
+            delete this;
+            return 0;
+          }
+          return FRefCount;
+        }
+
+        template<class ElementType> inline CDataBuffer_ConstView<ElementType, N * 16> GetConstView(void)
+        { return FPool.GetConstView<ElementType>(); }
+        template<class ElementType> inline CDataBuffer_VarView<ElementType, N * 16> GetVarView(void)
+        { return FPool.GetVarView<ElementType>(); }
+
+        void *GetDataPointer(void) { return &FPool; }
+
+        static void *operator new(size_t size) { return _aligned_malloc(size, 16); }
+        static void operator delete(void *p) { _aligned_free(p); }
+    };
+
+    class CRandomBlockPtr
+    {
+      private:
+        CRandomBlock *FBlock;
+      protected:
+      public:
+        CRandomBlockPtr(void) { FBlock = new CRandomBlock(); }
+        CRandomBlockPtr(CRandomBlock *Src) : FBlock(Src) { /* No AddRef */ }
+        CRandomBlockPtr(const CRandomBlockPtr &Src) : FBlock(Src.FBlock) { FBlock->AddRef(); }
+        ~CRandomBlockPtr(void) { FBlock->Release(); }
+        int GetRefCount(void) { return FBlock->GetRefCount(); }
+
+        template<class ElementType> inline CDataBuffer_ConstView<ElementType, N * 16> GetConstView(void)
+        { return FBlock->GetConstView<ElementType>(); }
+        template<class ElementType> inline CDataBuffer_VarView<ElementType, N * 16> GetVarView(void)
+        { return FBlock->GetVarView<ElementType>(); }
+
+        void *GetDataPointer(void) { return FBlock->GetDataPointer(); }
+
+        void MakeUnique(void)
+        {
+          if (GetRefCount() != 1)
+          {
+            #ifndef CFG_TIMETRACK_DISABLE
+            Metrics.poolmoves++;
+            #endif
+            CRandomBlock *NewBlock = new CRandomBlock;
+            memcpy(NewBlock->GetDataPointer(), FBlock->GetDataPointer(), N * sizeof(uint128_t));
+            FBlock->Release();
+            FBlock = NewBlock;
+          }
+        }
+    };
+  protected:
+    // The 128-bit internal state array
+    CRandomBlockPtr FPool;
+  private:
+    // A function used in the initialization (init_by_array).
+    static inline uint32_t func1(uint32_t x)
+    {
+      return (x ^ (x >> 27)) * (uint32_t)1664525UL;
+    }
+
+    // A function used in the initialization (init_by_array).
+    static inline uint32_t func2(uint32_t x)
+    {
+      return (x ^ (x >> 27)) * (uint32_t)1566083941UL;
+    }
+
+    // A function used in the initialization (init_gen_rand).
+    static inline uint32_t func3(uint32_t x, uint32_t i)
+    {
+      return 1812433253UL * (x ^ (x >> 30)) + i;
+    }
+
+    // This function corrects for byte ordering on big endian machines. Note
+    // that this function does slow things down a bit so should be avoided where
+    // performance is important.
+    static inline size_t IdxOf32(size_t LittleEndianIdx)
+    {
+      return EndianFix<2>(LittleEndianIdx);
+    }
+
+    #if (CFG_RANDPOOL_IMPL == CFG_RANDPOOL_IMPL_32BITSLOW)
+    // -------------------------------------------------------------------------
+    // Implementation for register-challenged 32-bit architectures. In other
+    // words, x86. There simply isn't enough register to go around to buffer the
+    // C and D values, so we have to pull them from memory (hopefully the cache)
+    // instead. Note that this is really only needed if the compiler is not
+    // supported by the inline assembler MMX version, which is faster.
+    // 
+    // This also serves a double duty as the "default" implementation in case we
+    // don't have anything better to use. There's currently two architectures
+    // that are not fully optimal (and use this implementation): 32-bit SPARC,
+    // and 32-bit PPC systems that don't support AltiVec (such as POWER). There
+    // should be a register-buffering 32-bit implementation for these
+    // architectures.
+    // -------------------------------------------------------------------------
+
+    static std::string GetRandpoolImpl(void) { return "32bitslow"; }
+
+    // Emulation of 128-bit shifts using 32-bit integer operations.
+    template<int NumBits, int Idx, int SrcIdx> static inline uint32_t Shr128_sub(uint32_t *SrcPtr)
+    {
+      // Low bit of SrcIdx ends up at SrcIdx * 32 - NumBits.
+      // Get position relative to the low bit of Idx (= Idx * 32).
+      static const int SrcLow = SrcIdx * 32 - NumBits - Idx * 32;
+      static const int UseLeftShift = ((SrcLow > 0) && (SrcLow < 32)) ? 1 : 0;
+      static const int UseRightShift = ((SrcLow < 0) && (SrcLow > -32)) ? 1 : 0;
+      static const int UseNoShift = (SrcLow == 0) ? 1 : 0;
+      static const int LShiftBits = (UseLeftShift == 1) ? SrcLow : 0;
+      static const int RShiftBits = (UseRightShift == 1) ? -SrcLow : 0;
+      if (UseLeftShift == 1) return SrcPtr[EndianFix_static_int<2, SrcIdx>::Value] << LShiftBits;
+      if (UseRightShift == 1) return SrcPtr[EndianFix_static_int<2, SrcIdx>::Value] >> RShiftBits;
+      if (UseNoShift == 1) return SrcPtr[EndianFix_static_int<2, SrcIdx>::Value];
+      return 0;
+    }
+
+    template<int NumBits, int Idx, int SrcIdx> static inline uint32_t Shl128_sub(uint32_t *SrcPtr)
+    {
+      return Shr128_sub<-NumBits, Idx, SrcIdx>(SrcPtr);
+    }
+
+    template<int NumBits, int Idx> static uint32_t inline Shr128Xor(uint32_t x, uint32_t *Y128Ptr)
+    {
+      return x ^
+        Shr128_sub<NumBits, Idx, 0>(Y128Ptr) ^ Shr128_sub<NumBits, Idx, 1>(Y128Ptr) ^
+        Shr128_sub<NumBits, Idx, 2>(Y128Ptr) ^ Shr128_sub<NumBits, Idx, 3>(Y128Ptr);
+    }
+
+    template<int NumBits, int Idx> static uint32_t inline Shl128Xor(uint32_t x, uint32_t *Y128Ptr)
+    {
+      return x ^
+        Shl128_sub<NumBits, Idx, 0>(Y128Ptr) ^ Shl128_sub<NumBits, Idx, 1>(Y128Ptr) ^
+        Shl128_sub<NumBits, Idx, 2>(Y128Ptr) ^ Shl128_sub<NumBits, Idx, 3>(Y128Ptr);
+    }
+
+    // The recursion function for 32-bit architectures with high register
+    // pressure (ie: x86). Zero registers are used for caching.
+    template<int COffset, int DOffset>
+    static void inline mm_recursion_32_0(uint32_t *BufA, uint32_t *BufB)
+    {
+      uint32_t A0Res;
+      A0Res = Shl128Xor<SFMTConsts::SL2 * 8, 0>(BufA[EndianFix_static_int<2, 0>::Value], BufA);
+      A0Res ^= (BufB[EndianFix_static_int<2, 0>::Value] >> SFMTConsts::SR1) & SFMTConsts::MSK1;
+      A0Res = Shr128Xor<SFMTConsts::SR2 * 8, 0>(A0Res, BufA + COffset * 4);
+      A0Res ^= BufA[EndianFix_static_int<2, 0>::Value + DOffset * 4] << SFMTConsts::SL1;
+      if (SFMTConsts::SL2 == 0) BufA[EndianFix_static_int<2, 0>::Value] = A0Res;
+
+      uint32_t A1Res;
+      A1Res = Shl128Xor<SFMTConsts::SL2 * 8, 1>(BufA[EndianFix_static_int<2, 1>::Value], BufA);
+      A1Res ^= (BufB[EndianFix_static_int<2, 1>::Value] >> SFMTConsts::SR1) & SFMTConsts::MSK2;
+      A1Res = Shr128Xor<SFMTConsts::SR2 * 8, 1>(A1Res, BufA + COffset * 4);
+      A1Res ^= BufA[EndianFix_static_int<2, 1>::Value + DOffset * 4] << SFMTConsts::SL1;
+      if ((SFMTConsts::SL2 > 0) && (SFMTConsts::SL2 <= 32)) BufA[EndianFix_static_int<2, 0>::Value] = A0Res;
+      if (SFMTConsts::SL2 == 0) BufA[EndianFix_static_int<2, 1>::Value] = A1Res;
+
+      uint32_t A2Res;
+      A2Res = Shl128Xor<SFMTConsts::SL2 * 8, 2>(BufA[EndianFix_static_int<2, 2>::Value], BufA);
+      A2Res ^= (BufB[EndianFix_static_int<2, 2>::Value] >> SFMTConsts::SR1) & SFMTConsts::MSK3;
+      A2Res = Shr128Xor<SFMTConsts::SR2 * 8, 2>(A2Res, BufA + COffset * 4);
+      A2Res ^= BufA[EndianFix_static_int<2, 2>::Value + DOffset * 4] << SFMTConsts::SL1;
+      if ((SFMTConsts::SL2 > 32) && (SFMTConsts::SL2 <= 64)) BufA[EndianFix_static_int<2, 0>::Value] = A0Res;
+      if ((SFMTConsts::SL2 > 0) && (SFMTConsts::SL2 <= 32)) BufA[EndianFix_static_int<2, 1>::Value] = A1Res;
+      if (SFMTConsts::SL2 == 0) BufA[EndianFix_static_int<2, 2>::Value] = A2Res;
+
+      uint32_t A3Res;
+      A3Res = Shl128Xor<SFMTConsts::SL2 * 8, 3>(BufA[EndianFix_static_int<2, 3>::Value], BufA);
+      A3Res ^= (BufB[EndianFix_static_int<2, 3>::Value] >> SFMTConsts::SR1) & SFMTConsts::MSK4;
+      A3Res = Shr128Xor<SFMTConsts::SR2 * 8, 3>(A3Res, BufA + COffset * 4);
+      A3Res ^= BufA[EndianFix_static_int<2, 3>::Value + DOffset * 4] << SFMTConsts::SL1;
+      if (SFMTConsts::SL2 > 64) BufA[EndianFix_static_int<2, 0>::Value] = A0Res;
+      if (SFMTConsts::SL2 > 32) BufA[EndianFix_static_int<2, 1>::Value] = A1Res;
+      if (SFMTConsts::SL2 > 0) BufA[EndianFix_static_int<2, 2>::Value] = A2Res;
+      BufA[EndianFix_static_int<2, 3>::Value] = A3Res;
+    }
+
+    NOINLINE void gen_rand_all(void)
+    {
+      #ifndef CFG_TIMETRACK_DISABLE
+      CTimedScope ScopeTimer(Metrics.gen_rand_all_time);
+      Metrics.gen_rand_all_count++;
+      #endif
+
+      uint32_t *APtr = FPool.template GetVarView<uint32_t>().GetPointer();
+      uint32_t *BPtr = APtr + SFMTConsts::POS1 * 4;
+
+      // The two initial loops (unusual C and D offsets).
+      mm_recursion_32_0<N - 2, N - 1>(APtr, BPtr);
+      mm_recursion_32_0<N - 2, -1>(APtr + 4, BPtr + 4);
+
+      int NumLoops = N - SFMTConsts::POS1 - 2;
+      APtr += (NumLoops + 2) * 4;
+      BPtr += (NumLoops + 2) * 4;
+
+      // The main loop. No unrolling.
+      int RepLoop = 0;
+      for (;;)
+      {
+        for (int MainLoop = -NumLoops; MainLoop != 0; MainLoop++)
+          mm_recursion_32_0<-2, -1>(APtr + MainLoop * 4, BPtr + MainLoop * 4);
+        if (RepLoop == 0)
+        {
+          // Need to adjust BPtr to handle wrapping of the buffer.
+          RepLoop = 1;
+          NumLoops = SFMTConsts::POS1;
+          APtr += NumLoops * 4;
+          BPtr += (NumLoops - N) * 4;
+        }
+        else
+          break;
+      }
+    }
+    #endif
+
+    #if (CFG_RANDPOOL_IMPL == CFG_RANDPOOL_IMPL_MMX)
+    // -------------------------------------------------------------------------
+    // MMX implementation. Since current compilers can't handle the register
+    // pressure for this implementation, it has to be done via assembler (inline
+    // if we're using MSVC, external if we're using something else). All we do
+    // is bounce out to the correct function.
+    // -------------------------------------------------------------------------
+    static std::string GetRandpoolImpl(void) { return "mmx"; }
+    NOINLINE void gen_rand_all(void)
+    {
+      #ifndef CFG_TIMETRACK_DISABLE
+      CTimedScope ScopeTimer(Metrics.gen_rand_all_time);
+      Metrics.gen_rand_all_count++;
+      #endif
+
+      SFMT_recursion_mmx<SFMTConsts>::SFMT_recursion(FPool.GetDataPointer());
+    }
+    #endif
+
+    #if (CFG_RANDPOOL_IMPL == CFG_RANDPOOL_IMPL_64BIT)
+    // -------------------------------------------------------------------------
+    // Implementation for 64 bit architectures. Here, we buffer C and D in
+    // registers. It is assumed that there are sufficient registers that this
+    // can be done. In every 64-bit platform of relevance (x86-64, SPARC, PPC,
+    // and IA64) this is the case. Note that in the case of x86-64 we'd probably
+    // be using SSE2 anyhow.
+    // -------------------------------------------------------------------------
+
+    static std::string GetRandpoolImpl(void) { return "64bit"; }
+
+    // Emulation of 128-bit shifts using 64-bit integer operations.
+    template<int NumBits, int Idx, int SrcIdx> FORCEINLINE uint64_t Shr128_sub(uint64_t YVal)
+    {
+      // Low bit of SrcIdx ends up at SrcIdx * 64 - NumBits.
+      // Get position relative to the low bit of Idx (= Idx * 64).
+      static const int SrcLow = SrcIdx * 64 - NumBits - Idx * 64;
+      static const int UseLeftShift = ((SrcLow > 0) && (SrcLow < 64)) ? 1 : 0;
+      static const int UseRightShift = ((SrcLow < 0) && (SrcLow > -64)) ? 1 : 0;
+      static const int UseNoShift = (SrcLow == 0) ? 1 : 0;
+      static const int LShiftBits = (UseLeftShift == 1) ? SrcLow : 0;
+      static const int RShiftBits = (UseRightShift == 1) ? -SrcLow : 0;
+      if (UseLeftShift == 1) return YVal << LShiftBits;
+      if (UseRightShift == 1) return YVal >> RShiftBits;
+      if (UseNoShift == 1) return YVal;
+      return 0;
+    }
+
+    template<int NumBits, int Idx, int SrcIdx> FORCEINLINE uint64_t Shl128_sub(uint64_t YVal)
+    {
+      return Shr128_sub<-NumBits, Idx, SrcIdx>(YVal);
+    }
+
+    template<int NumBits, int Idx> uint64_t FORCEINLINE Shr128Xor(uint64_t x, uint64_t YLow, uint64_t YHigh)
+    {
+      return x ^ Shr128_sub<NumBits, Idx, 0>(YLow) ^ Shr128_sub<NumBits, Idx, 1>(YHigh);
+    }
+
+    template<int NumBits, int Idx> uint64_t FORCEINLINE Shl128Xor(uint64_t x, uint64_t YLow, uint64_t YHigh)
+    {
+      return x ^ Shl128_sub<NumBits, Idx, 0>(YLow) ^ Shl128_sub<NumBits, Idx, 1>(YHigh);
+    }
+
+    // The recursion function for 64-bit architectures. It's assumed that there
+    // are enough registers, which is true for any architecture worth worrying
+    // about (x86-64, SPARC, IA64, PPC).
+    void FORCEINLINE mm_recursion(uint128_t *BufA, uint128_t *BufB, uint64_t &ALowOut, uint64_t &AHighOut,
+      uint64_t CLow, uint64_t CHigh, uint64_t DLow, uint64_t DHigh)
+    {
+      uint64_t ALowIn = BufA->GetU64<0>();
+      uint64_t AHighIn = BufA->GetU64<1>();
+
+      uint64_t A0Res;
+      A0Res = Shl128Xor<SFMTConsts::SL2 * 8, 0>(ALowIn, ALowIn, AHighIn);
+      A0Res ^= (BufB->GetU64<0>() >> SFMTConsts::SR1) &
+        (static_cast<uint64_t>(SFMTConsts::MSK1) | (static_cast<uint64_t>(SFMTConsts::MSK2) << 32)) &
+        U64_Shr32Mask<SFMTConsts::SR1>::Value;
+      A0Res = Shr128Xor<SFMTConsts::SR2 * 8, 0>(A0Res, CLow, CHigh);
+      A0Res ^= (DLow << SFMTConsts::SL1) & U64_Shl32Mask<SFMTConsts::SL1>::Value;
+      if (SFMTConsts::SL2 == 0) { ALowOut = A0Res; BufA->SetU64<0>(A0Res); }
+
+      uint64_t A1Res;
+      A1Res = Shl128Xor<SFMTConsts::SL2 * 8, 1>(AHighIn, ALowIn, AHighIn);
+      A1Res ^= (BufB->GetU64<1>() >> SFMTConsts::SR1) &
+        (static_cast<uint64_t>(SFMTConsts::MSK3) | (static_cast<uint64_t>(SFMTConsts::MSK4) << 32)) &
+        U64_Shr32Mask<SFMTConsts::SR1>::Value;
+      A1Res = Shr128Xor<SFMTConsts::SR2 * 8, 1>(A1Res, CLow, CHigh);
+      A1Res ^= (DHigh << SFMTConsts::SL1) & U64_Shl32Mask<SFMTConsts::SL1>::Value;
+      if (SFMTConsts::SL2 > 0) { ALowOut = A0Res; BufA->SetU64<0>(A0Res); }
+      AHighOut = A1Res; BufA->SetU64<1>(A1Res);
+    }
+    #endif
+
+    #if (CFG_RANDPOOL_IMPL == CFG_RANDPOOL_IMPL_SSE2)
+    // -------------------------------------------------------------------------
+    // This is the SSE2 implementation. Implementing AltiVec in u128simd.h
+    // should allow this to work fine for AltiVec as well.
+    // -------------------------------------------------------------------------
+
+    static std::string GetRandpoolImpl(void) { return "sse2"; }
+
+    // The main recursion function.
+    uint128_t FORCEINLINE mm_recursion(uint128_t *BufA, uint128_t *BufB,
+      uint128_t ValC, uint128_t ValD, uint128_t Mask)
+    {
+      uint128_t ValA = *BufA;
+      
+      ValA = SIMDOP_xor(SIMDOP_xor(SIMDOP_xor(SIMDOP_xor(
+        ValA,
+        SIMDOps::Shl8<SFMTConsts::SL2>(ValA)),
+        SIMDOP_and(SIMDOps::Shr_u32<SFMTConsts::SR1>(BufB[0]), Mask)),
+        SIMDOps::Shr8<SFMTConsts::SR2>(ValC)),
+        SIMDOps::Shl_u32<SFMTConsts::SL1>(ValD));
+      *BufA = ValA;
+      return ValA;
+    }
+    #endif
+
+    #if (CFG_RANDPOOL_IMPL == CFG_RANDPOOL_IMPL_64BIT) || (CFG_RANDPOOL_IMPL == CFG_RANDPOOL_IMPL_SSE2)
+    // -------------------------------------------------------------------------
+    // This is the generic gen_rand for architectures where C and D are buffered
+    // in registers.
+    // -------------------------------------------------------------------------
+
+    static const int PartLoops1 = (N - SFMTConsts::POS1) % 3;
+    static const int Loops1 = (N - SFMTConsts::POS1) / 3;
+    static const int Loops2 = SFMTConsts::POS1 / 3;
+    static const int PartLoops2 = SFMTConsts::POS1 % 3;
+
+    NOINLINE void gen_rand_all(void)
+    {
+      #ifndef CFG_TIMETRACK_DISABLE
+      CTimedScope ScopeTimer(Metrics.gen_rand_all_time);
+      Metrics.gen_rand_all_count++;
+      #endif
+
+      #if (CFG_RANDPOOL_IMPL == CFG_RANDPOOL_IMPL_SSE2)
+      uint128_t Mask = SIMDOps::uint128_t_const<SFMTConsts::MSK1, SFMTConsts::MSK2, SFMTConsts::MSK3, SFMTConsts::MSK4>::Value();
+      uint128_t AVal, CVal, DVal;
+      #elif (CFG_RANDPOOL_IMPL == CFG_RANDPOOL_IMPL_64BIT)
+      uint64_t ALow, AHigh, CLow, CHigh, DLow, DHigh;
+      #endif
+
+      uint128_t *APtr = FPool.template GetVarView<uint128_t>().GetPointer();
+      uint128_t *BPtr;
+
+      // Now would be a perfect time to use Duff's device. Except that both GCC
+      // and MSVC choke badly on it and generate terrible code. So, we have to
+      // manually unroll the partial loops. Additionally, it appears to be
+      // impossible to express the functions in a way that makes everything work
+      // well in both GCC and MSVC in both SSE2 and 64-bit mode. So, the code
+      // has to be duplicated to coerce the compiler into not thrashing the
+      // stack. Also, we should be able to use "APtr + 1" etc, except MSVC is
+      // broken and emits C4328 on this construct.
+      #define COMPOSE(x, y) x##y
+      #if (CFG_RANDPOOL_IMPL == CFG_RANDPOOL_IMPL_SSE2)
+        #define MM_RECURSION(A, AOffset, BOffset, C, D) COMPOSE(A, Val) = mm_recursion(&APtr[AOffset], &BPtr[BOffset], COMPOSE(C, Val), COMPOSE(D, Val), Mask);
+        #define MM_LOAD(X, AOffset) COMPOSE(X, Val) = APtr[AOffset];
+      #elif (CFG_RANDPOOL_IMPL == CFG_RANDPOOL_IMPL_64BIT)
+        #define MM_RECURSION(A, AOffset, BOffset, C, D) mm_recursion(&APtr[AOffset], &BPtr[BOffset], COMPOSE(A, Low), COMPOSE(A, High), COMPOSE(C, Low), COMPOSE(C, High), COMPOSE(D, Low), COMPOSE(D, High));
+        #define MM_LOAD(X, AOffset) COMPOSE(X, Low) = APtr[AOffset].GetU64<0>(); COMPOSE(X, High) = APtr[AOffset].GetU64<1>();
+      #endif
+
+      BPtr = APtr;
+      if (PartLoops1 == 2)
+      {
+        MM_LOAD(D, N - 2)
+        MM_LOAD(A, N - 1)
+        MM_RECURSION(C, 0, SFMTConsts::POS1 + 0, D, A)
+        MM_RECURSION(D, 1, SFMTConsts::POS1 + 1, A, C)
+        APtr += 2;
+      }
+      if (PartLoops1 == 1)
+      {
+        MM_LOAD(A, N - 2)
+        MM_LOAD(C, N - 1)
+        MM_RECURSION(D, 0, SFMTConsts::POS1 + 0, A, C)
+        APtr += 1;
+      }
+
+      APtr += 3 * Loops1;
+      BPtr = APtr + SFMTConsts::POS1;
+      int LoopCount = -3 * Loops1;
+
+      for (;;)
+      {
+        for (; LoopCount < 0; LoopCount += 3)
+        {
+          MM_RECURSION(A, LoopCount + 0, LoopCount + 0, C, D)
+          MM_RECURSION(C, LoopCount + 1, LoopCount + 1, D, A)
+          MM_RECURSION(D, LoopCount + 2, LoopCount + 2, A, C)
+        }
+        if (BPtr == APtr + SFMTConsts::POS1)
+        {
+          // Handle BPtr wrapping around the end of the array.
+          LoopCount = -Loops2 * 3;
+          BPtr = APtr - N + 2 * SFMTConsts::POS1 - SFMTConsts::POS1 % 3;
+          APtr += Loops2 * 3;
+        }
+        else
+          break;
+      }
+
+      // Again, Duff's device would allow us to avoid this annoying manual
+      // unrolling (not to mention this rather harder to follow logic).
+      if (PartLoops2 >= 1) MM_RECURSION(A, LoopCount + 0, LoopCount + 0, C, D)
+      if (PartLoops2 >= 2) MM_RECURSION(C, LoopCount + 1, LoopCount + 1, D, A)
+    }
+    #endif
+
+    // Certifies the period (2^MEXP), potentially changing one of the bits to
+    // make sure.
+    void PeriodCertification(void)
+    {
+      CDataBuffer_VarView<uint128_t, N * 16> PoolU128 = FPool.template GetVarView<uint128_t>();
+      uint128_t ParityCheck = SIMDOps::Parity(SIMDOP_and(
+        SIMDOps::uint128_t_const<SFMTConsts::PARITY1, SFMTConsts::PARITY2, SFMTConsts::PARITY3, SFMTConsts::PARITY4>::Value(), PoolU128.Load(0)));
+      PoolU128.Store(0, SIMDOP_xor(PoolU128.Load(0), SIMDOps::AndNot(SIMDOps::uint128_t_const<
+        lowestbit_u128<SFMTConsts::PARITY1, SFMTConsts::PARITY2, SFMTConsts::PARITY3, SFMTConsts::PARITY4>::y0,
+        lowestbit_u128<SFMTConsts::PARITY1, SFMTConsts::PARITY2, SFMTConsts::PARITY3, SFMTConsts::PARITY4>::y1,
+        lowestbit_u128<SFMTConsts::PARITY1, SFMTConsts::PARITY2, SFMTConsts::PARITY3, SFMTConsts::PARITY4>::y2,
+        lowestbit_u128<SFMTConsts::PARITY1, SFMTConsts::PARITY2, SFMTConsts::PARITY3, SFMTConsts::PARITY4>::y3>::Value(),
+        ParityCheck)));
+    }
+  public:
+    CRandPool(void)
+    { 
+      #ifndef CFG_TIMETRACK_DISABLE
+      Metrics.ForceConstruction(); 
+      #endif
+    }
+    /**
+     * This function returns the identification string.
+     * The string shows the word size, the Mersenne exponent,
+     * and all parameters of this generator.
+     */
+    static std::string GetIDString(void)
+    {
+      std::ostringstream os;
+      os << "SFMT" << '-' << SFMTConsts::MEXP << ':' << SFMTConsts::POS1 << '-' << SFMTConsts::SL1 << '-' << SFMTConsts::SL2 <<
+        '-' << SFMTConsts::SR1 << '-' << SFMTConsts::SR2 << ':' << std::hex << std::setfill('0') <<
+        std::setw(8) << SFMTConsts::MSK1 << '-' <<
+        std::setw(8) << SFMTConsts::MSK2 << '-' <<
+        std::setw(8) << SFMTConsts::MSK3 << '-' <<
+        std::setw(8) << SFMTConsts::MSK4 << ':' << GetRandpoolImpl();
+      return os.str();
+    }
+    
+    /**
+     * This function initializes the internal state array with a 32-bit
+     * integer seed.
+     *
+     * @param seed a 32-bit integer used as the seed.
+     */
+     
+    NOINLINE void init_gen_rand(uint32_t seed)
+    {
+      CDataBuffer_VarView<uint32_t, N * 16> PoolU32 = FPool.template GetVarView<uint32_t>();
+      uint32_t x0 = seed;
+      for (uint32_t i = 0; i < N; i++)
+      {
+        uint32_t x1 = func3(x0, i * 4 + 1);
+        uint32_t x2 = func3(x1, i * 4 + 2);
+        uint32_t x3 = func3(x2, i * 4 + 3);
+        PoolU32.Store(i * 4 + EndianFix_static<2, 0>::Value, x0);
+        PoolU32.Store(i * 4 + EndianFix_static<2, 1>::Value, x1);
+        PoolU32.Store(i * 4 + EndianFix_static<2, 2>::Value, x2);
+        PoolU32.Store(i * 4 + EndianFix_static<2, 3>::Value, x3);
+        x0 = func3(x3, i * 4 + 4);
+      }
+      PeriodCertification();
+      SIMDOps::EmptyForFP();
+    }
+    
+    /**
+     * This function initializes the internal state array,
+     * with an array of 32-bit integers used as the seeds
+     * @param init_key the array of 32-bit integers, used as a seed.
+     * @param key_length the length of init_key.
+     */
+    NOINLINE void init_by_array(uint32_t *init_key, size_t key_length)
+    {
+      uint32_t *FPool32 = FPool.template GetVarView<uint32_t>().GetPointer();
+
+      size_t lag;
+      if (N32 >= 623)
+	      lag = 11;
+      else if (N32 >= 68)
+	      lag = 7;
+      else if (N32 >= 39)
+	      lag = 5;
+      else
+	      lag = 3;
+      size_t mid = (N32 - lag) / 2;
+
+      memset(FPool32, 0x8b, N * 16);
+
+      size_t count;
+      if (key_length + 1 > N32)
+        count = key_length + 1;
+      else
+	      count = N32;
+
+      uint32_t r = func1(FPool32[IdxOf32(0)] ^ FPool32[IdxOf32(mid)]
+        ^ FPool32[IdxOf32(N32 - 1)]);
+      FPool32[IdxOf32(mid)] += r;
+      r += key_length;
+      FPool32[IdxOf32(mid + lag)] += r;
+      FPool32[IdxOf32(0)] = r;
+
+      size_t i, j;
+      count--;
+      for (i = 1, j = 0; (j < count) && (j < key_length); j++)
+      {
+	      r = func1(FPool32[IdxOf32(i)] ^ FPool32[IdxOf32((i + mid) % N32)]
+          ^ FPool32[IdxOf32((i + N32 - 1) % N32)]);
+	      FPool32[IdxOf32((i + mid) % N32)] += r;
+	      r += init_key[j] + i;
+	      FPool32[IdxOf32((i + mid + lag) % N32)] += r;
+	      FPool32[IdxOf32(i)] = r;
+	      i = (i + 1) % N32;
+      }
+
+      for (; j < count; j++)
+      {
+	      r = func1(FPool32[IdxOf32(i)] ^ FPool32[IdxOf32((i + mid) % N32)]
+		      ^ FPool32[IdxOf32((i + N32 - 1) % N32)]);
+	      FPool32[IdxOf32((i + mid) % N32)] += r;
+	      r += i;
+	      FPool32[IdxOf32((i + mid + lag) % N32)] += r;
+	      FPool32[IdxOf32(i)] = r;
+	      i = (i + 1) % N32;
+      }
+      for (j = 0; j < N32; j++)
+      {
+	      r = func2(FPool32[IdxOf32(i)] + FPool32[IdxOf32((i + mid) % N32)]
+		      + FPool32[IdxOf32((i + N32 - 1) % N32)]);
+	      FPool32[IdxOf32((i + mid) % N32)] ^= r;
+	      r -= i;
+	      FPool32[IdxOf32((i + mid + lag) % N32)] ^= r;
+	      FPool32[IdxOf32(i)] = r;
+	      i = (i + 1) % N32;
+      }
+      PeriodCertification();
+      SIMDOps::EmptyForFP();
+    }
+
+    static const size_t BufSize = N;
+
+    inline CRandomBlockPtr GetRandomBlock(void)
+    {
+      FPool.MakeUnique();
+      gen_rand_all();
+      return FPool;
+    }
+};
+
+#ifndef CFG_TIMETRACK_DISABLE
+template<class SFMTParams> typename CRandPool<SFMTParams>::TMetrics CRandPool<SFMTParams>::Metrics;
+template<class SFMTParams> THREADVAR uint32_t CRandPool<SFMTParams>::TMetrics::poolmoves = 0;
+template<class SFMTParams> THREADVAR uint32_t CRandPool<SFMTParams>::TMetrics::gen_rand_all_count = 0;
+template<class SFMTParams> THREADVAR uint64_t CRandPool<SFMTParams>::TMetrics::gen_rand_all_time = 0;
+#endif
+
+#if CFG_COMPILER == CFG_COMPILER_MSVC
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/xpdeint/includes/solirte/u128simd.h b/xpdeint/includes/solirte/u128simd.h
new file mode 100644
index 0000000..f1544bc
--- /dev/null
+++ b/xpdeint/includes/solirte/u128simd.h
@@ -0,0 +1,1225 @@
+/* *****************************************************************************
+/
+/ This file is part of Solirte, a solenoid ion ray-tracing engine.
+/ (c) 2008 Michael Brown.
+/ michael.brown at anu.edu.au
+/
+/ One nice this to have would be a generic 128-bit SIMD-like class so that
+/ everything could be nicely ecapsulated, and SSE/AltiVec could be
+/ transparently used. Unfortunately, there's no compiler that will consistantly
+/ produce good code for such a type. So, things have to be done in a slightly
+/ more ugly way: global operators on the basic intrinsic types. Even the simple
+/ wrapping done here appears to be pushing the limit of code generation on
+/ some compilers (eg: MSVC, GCC 3.x).
+/
+/ Note also that most compilers implode on the MMX implementation and produce
+/ code that's worse than simple scalar code.
+/
+/ Finally, the unusual views-with-load/store concept for CDataBuffer is needed
+/ to help GCC. Without this construct, gcc's aliasing rules are violated and the
+/ compiler generates incorrect code.
+/ *************************************************************************** */
+
+#ifndef U128SIMD_H
+#define U128SIMD_H
+
+#include <iomanip>
+
+// intrinsic = hardware SIMD implementation (fast)
+// mmx = mmx (surprise!)
+// scalar = software SIMD implementation (slow)
+#define CFG_SIMD_INTRINSIC 1
+#define CFG_SIMD_MMX 2
+#define CFG_SIMD_SCALAR 3
+
+#if (CFG_COMPILER == CFG_COMPILER_MSVC)
+// Disable the "no EMMS instruction" warning - this is the responsibility of any
+// function that calls these functions.
+#pragma warning( push )
+#pragma warning(disable : 4799)
+#endif
+
+// -----------------------------------------------------------------------------
+// SIMD operations
+// -----------------------------------------------------------------------------
+
+#if (CFG_HAVE_SSE1 == 1)
+inline __m128 SIMDOP_add(const __m128 LHS, const __m128 RHS)
+{ return _mm_add_ps(LHS, RHS); }
+
+inline __m128 SIMDOP_sub(const __m128 LHS, const __m128 RHS)
+{ return _mm_sub_ps(LHS, RHS); }
+
+inline __m128 SIMDOP_mul(const __m128 LHS, const __m128 RHS)
+{ return _mm_mul_ps(LHS, RHS); }
+
+inline __m128 SIMDOP_or(const __m128 LHS, const __m128 RHS)
+{ return _mm_or_ps(LHS, RHS); }
+
+inline __m128 SIMDOP_and(const __m128 LHS, const __m128 RHS)
+{ return _mm_and_ps(LHS, RHS); }
+
+inline __m128 SIMDOP_xor(const __m128 LHS, const __m128 RHS)
+{ return _mm_xor_ps(LHS, RHS); }
+#endif
+
+#if (CFG_HAVE_SSE2 == 1)
+
+inline __m128i SIMDOP_or(__m128i LHS, __m128i RHS)
+{ return _mm_or_si128(LHS, RHS); }
+
+inline __m128i SIMDOP_and(__m128i LHS, __m128i RHS)
+{ return _mm_and_si128(LHS, RHS); }
+
+inline __m128i SIMDOP_xor(__m128i LHS, __m128i RHS)
+{ return _mm_xor_si128(LHS, RHS); }
+
+#if (CFG_ONLY_INTEGER_SSE2 == 0)
+inline __m128d SIMDOP_add(const __m128d LHS, const __m128d RHS)
+{ return _mm_add_pd(LHS, RHS); }
+
+inline __m128d SIMDOP_sub(const __m128d LHS, const __m128d RHS)
+{ return _mm_sub_pd(LHS, RHS); }
+
+inline __m128d SIMDOP_mul(const __m128d LHS, const __m128d RHS)
+{ return _mm_mul_pd(LHS, RHS); }
+
+inline __m128d SIMDOP_or(const __m128d LHS, const __m128d RHS)
+{ return _mm_or_pd(LHS, RHS); }
+
+inline __m128d SIMDOP_and(const __m128d LHS, const __m128d RHS)
+{ return _mm_and_pd(LHS, RHS); }
+
+inline __m128d SIMDOP_xor(const __m128d LHS, const __m128d RHS)
+{ return _mm_xor_pd(LHS, RHS); }
+#endif
+#endif
+
+// -----------------------------------------------------------------------------
+// Common functions
+// -----------------------------------------------------------------------------
+
+template<uint32_t x, int NumBits>
+struct lowestbit_u32
+{
+  static const uint32_t BitMask = (1 << (NumBits / 2)) - 1;
+  static const uint32_t LowPart = x & BitMask;
+  static const uint32_t HighPart = (x >> (NumBits / 2)) & BitMask;
+  static const uint32_t CalcVal = (LowPart == 0) ?
+    (lowestbit_u32<HighPart, NumBits / 2>::CalcVal << (NumBits / 2)) :
+    lowestbit_u32<LowPart, NumBits / 2>::CalcVal;
+};
+
+template<uint32_t x>
+struct lowestbit_u32<x, 1>
+{
+  static const uint32_t CalcVal = x;
+};
+
+template<uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3>
+struct lowestbit_u128
+{
+  static const int y0 = lowestbit_u32<x0, 32>::CalcVal;
+  static const int y1 = (y0 != 0) ? 0 : lowestbit_u32<x1, 32>::CalcVal;
+  static const int y2 = ((y0 | y1) != 0) ? 0 : lowestbit_u32<x2, 32>::CalcVal;
+  static const int y3 = ((y0 | y1 | y2) != 0) ? 0 : lowestbit_u32<x3, 32>::CalcVal;
+};
+
+template<int Bits> struct U64_Shr32Mask
+{
+  static const uint64_t SingleMask = 0xffffffff >> Bits;
+  static const uint64_t Value = SingleMask | (SingleMask << 32);
+};
+
+template<int Bits> struct U64_Shl32Mask
+{
+  static const uint64_t SingleMask = (0xffffffff << Bits) & 0xffffffff;
+  static const uint64_t Value = SingleMask | (SingleMask << 32);
+};
+
+#if CFG_HAVE_SSE2 == 1
+  #if (CFG_COMPILER == CFG_COMPILER_MSVC) || ((CFG_COMPILER == CFG_COMPILER_GCC) && (__GNUC__ < 4))
+    inline __m128 _mm_castsi128_ps(const __m128i &x) { return reinterpret_cast<const __m128 &>(x); } 
+    inline __m128d _mm_castsi128_pd(const __m128i &x) { return reinterpret_cast<const __m128d &>(x); } 
+
+    inline __m128i _mm_castps_si128(const __m128 &x) { return reinterpret_cast<const __m128i &>(x); }
+    inline __m128d _mm_castps_pd(const __m128 &x) { return reinterpret_cast<const __m128d &>(x); }
+
+    inline __m128i _mm_castpd_si128(const __m128d &x) { return reinterpret_cast<const __m128i &>(x); }
+    inline __m128 _mm_castpd_ps(const __m128d &x) { return reinterpret_cast<const __m128 &>(x); }
+  #endif
+#endif
+
+// -----------------------------------------------------------------------------
+// 128-bit register
+// -----------------------------------------------------------------------------
+
+#if (CFG_HAVE_SSE2 == 1)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// SSE2 implementation.
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#define CFG_HAVE_U128 CFG_SIMD_INTRINSIC
+
+typedef __m128i uint128_t;
+
+namespace SIMDOps
+{
+  inline __m128i AndNot(__m128i LHS, __m128i RHS)
+  { return _mm_andnot_si128(RHS, LHS); } // Note reversed order
+
+  template<int NumBytes> inline __m128i Shr8(__m128i Src)
+  { return _mm_srli_si128(Src, NumBytes); }
+
+  template<int NumBytes> __m128i Shl8(__m128i Src)
+  { return _mm_slli_si128(Src, NumBytes); }
+
+  template<int NumBits> __m128i Shr_u32(__m128i Src)
+  { return _mm_srli_epi32(Src, NumBits); }
+
+  template<int NumBits> __m128i Shl_u32(__m128i Src)
+  { return _mm_slli_epi32(Src, NumBits); }
+
+  inline __m128i Parity(__m128i Src)
+  {
+    __m128i x = Src;
+    x = _mm_xor_si128(_mm_slli_epi64(x, 1), x);
+    x = _mm_xor_si128(_mm_slli_epi64(x, 2), x);
+    x = _mm_xor_si128(_mm_slli_epi64(x, 4), x);
+    x = _mm_xor_si128(_mm_slli_epi64(x, 8), x);
+    x = _mm_xor_si128(_mm_slli_epi64(x, 16), x);
+    x = _mm_xor_si128(_mm_slli_epi64(x, 32), x);
+    x = _mm_xor_si128(_mm_shuffle_epi32(x, 0xFF), _mm_shuffle_epi32(x, 0x55));
+    x = _mm_srai_epi32(x, 31);
+    return x;
+  }
+
+  template<uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3> struct uint128_t_const
+  {
+    static inline __m128i Value(void)
+    {
+      static const union
+      {
+        uint32_t AsU32[4];
+        __m128i AsM128I;
+      } InitData = {{x0, x1, x2, x3}};
+      return InitData.AsM128I;
+    }
+  };
+
+  inline __m128i make_uint128_t(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3)
+  {
+    union
+    {
+      uint32_t AsU32[4];
+      __m128i AsM128I;
+    } InitData = {{x0, x1, x2, x3}};
+    return InitData.AsM128I;
+  }
+
+  inline void EmptyForFP(void) { }
+}
+#endif
+
+#if (CFG_HAVE_MMX == 1) && !defined(CFG_HAVE_U128)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// MMX implementation
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#define CFG_HAVE_U128 CFG_SIMD_MMX
+
+struct uint128_t
+{
+  __m64 VecData[2];
+};
+
+inline uint128_t SIMDOP_or(const uint128_t &LHS, const uint128_t &RHS)
+{
+  uint128_t RetVal = {{_mm_or_si64(LHS.VecData[0], RHS.VecData[0]), _mm_or_si64(LHS.VecData[1], RHS.VecData[1])}};
+  return RetVal;
+}
+
+inline uint128_t SIMDOP_and(const uint128_t &LHS, const uint128_t &RHS)
+{
+  uint128_t RetVal = {{_mm_and_si64(LHS.VecData[0], RHS.VecData[0]), _mm_and_si64(LHS.VecData[1], RHS.VecData[1])}};
+  return RetVal;
+}
+
+inline uint128_t SIMDOP_xor(const uint128_t &LHS, const uint128_t &RHS)
+{
+  uint128_t RetVal = {{_mm_xor_si64(LHS.VecData[0], RHS.VecData[0]), _mm_xor_si64(LHS.VecData[1], RHS.VecData[1])}};
+  return RetVal;
+}
+
+namespace SIMDOps
+{
+  inline __m64 AndNot(const __m64 LHS, const __m64 RHS)
+  {
+    // Note reversed order
+    return _mm_andnot_si64(RHS, LHS);
+  }
+
+  inline uint128_t AndNot(const uint128_t &LHS, const uint128_t &RHS)
+  {
+    uint128_t RetVal = {{AndNot(LHS.VecData[0], RHS.VecData[0]), AndNot(LHS.VecData[1], RHS.VecData[1])}};
+    return RetVal;
+  }
+
+  template<int NumBytes> inline uint128_t Shr8(const uint128_t &Src)
+  {
+    uint128_t RetVal = {{
+      _mm_or_si64(_mm_srli_si64(Src.VecData[0], NumBytes * 8), _mm_slli_si64(Src.VecData[1], 64 - NumBytes * 8)),
+      _mm_srli_si64(Src.VecData[1], NumBytes * 8)}};
+    return RetVal;
+  }
+
+  template<int NumBytes> inline uint128_t Shl8(const uint128_t &Src)
+  {
+    uint128_t RetVal = {{
+      _mm_slli_si64(Src.VecData[0], NumBytes * 8),
+      _mm_or_si64(_mm_slli_si64(Src.VecData[1], NumBytes * 8),  _mm_srli_si64(Src.VecData[0], 64 - NumBytes * 8))}};
+    return RetVal;
+  }
+
+  template<int NumBits> inline uint128_t Shr_u32(const uint128_t &Src)
+  {
+    uint128_t RetVal = {{
+      _mm_srli_pi32(Src.VecData[0], NumBits),
+      _mm_srli_pi32(Src.VecData[1], NumBits)}};
+    return RetVal;
+  }
+
+  template<int NumBits> inline uint128_t Shl_u32(const uint128_t &Src)
+  {
+    uint128_t RetVal = {{
+      _mm_slli_pi32(Src.VecData[0], NumBits),
+      _mm_slli_pi32(Src.VecData[1], NumBits)}};
+    return RetVal;
+  }
+
+  inline uint128_t Parity(const uint128_t &Src)
+  {
+    __m64 x = _mm_xor_si64(Src.VecData[0], Src.VecData[1]);
+    x = _mm_xor_si64(_mm_slli_si64(x, 1), x);
+    x = _mm_xor_si64(_mm_slli_si64(x, 2), x);
+    x = _mm_xor_si64(_mm_slli_si64(x, 4), x);
+    x = _mm_xor_si64(_mm_slli_si64(x, 8), x);
+    x = _mm_xor_si64(_mm_slli_si64(x, 16), x);
+    x = _mm_xor_si64(_mm_slli_si64(x, 32), x);
+    x = _mm_unpackhi_pi32(x, x);
+    x = _mm_srai_pi32(x, 31);
+    uint128_t RetVal = {{x, x}};
+    return RetVal;
+  }
+
+  template<uint32_t x0, uint32_t x1> struct __m64_const
+  {
+    static inline __m64 Value(void)
+    {
+      static const union
+      {
+        uint32_t AsU32[2];
+        __m64 AsM64;
+      } InitData = {{x0, x1}};
+      return InitData.AsM64;
+    }
+  };
+
+  template<uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3> struct uint128_t_const
+  {
+    static inline uint128_t Value(void)
+    {
+      static const union
+      {
+        uint32_t AsU32[4];
+        uint128_t AsU128;
+      } InitData = {{x0, x1, x2, x3}};
+      return InitData.AsU128;
+    }
+  };
+
+  inline uint128_t make_uint128_t(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3)
+  {
+    union
+    {
+      uint32_t AsU32[4];
+      uint128_t AsU128;
+    } InitData = {{x0, x1, x2, x3}};
+    return InitData.AsU128;
+  }
+
+  #if CFG_SUNCC_BROKEN_MM_EMPTY == 1
+  inline void EmptyForFP(void) { _mm_empty_sun(); }
+  #else
+  inline void EmptyForFP(void) { _mm_empty(); }
+  #endif
+}
+
+#endif
+
+#if !defined(CFG_HAVE_U128)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Scalar implementation
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#define CFG_HAVE_U128 CFG_SIMD_SCALAR
+
+#if CFG_BITS == 64
+// 64-bit implementation
+struct uint128_t
+{
+  int64_t VecData[2];
+  template<size_t Idx> inline uint64_t GetU64(void)
+  { return VecData[EndianFix_static<1, Idx>::Value]; }
+  template<size_t Idx> inline void SetU64(uint64_t x)
+  { VecData[EndianFix_static<1, Idx>::Value] = x; }
+};
+
+inline uint128_t SIMDOP_or(const uint128_t &LHS, const uint128_t &RHS)
+{
+  uint128_t RetVal = {{LHS.VecData[0] | RHS.VecData[0], LHS.VecData[1] | RHS.VecData[1]}};
+  return RetVal;
+}
+
+inline uint128_t SIMDOP_and(const uint128_t &LHS, const uint128_t &RHS)
+{
+  uint128_t RetVal = {{LHS.VecData[0] & RHS.VecData[0], LHS.VecData[1] & RHS.VecData[1]}};
+  return RetVal;
+}
+
+inline uint128_t SIMDOP_xor(const uint128_t &LHS, const uint128_t &RHS)
+{
+  uint128_t RetVal = {{LHS.VecData[0] ^ RHS.VecData[0], LHS.VecData[1] ^ RHS.VecData[1]}};
+  return RetVal;
+}
+
+namespace SIMDOps
+{
+  inline uint64_t AndNot(const uint64_t LHS, const uint64_t RHS)
+  {
+    return LHS & !RHS;
+  }
+
+  inline uint128_t AndNot(const uint128_t &LHS, const uint128_t &RHS)
+  {
+    uint128_t RetVal = {{AndNot(LHS.VecData[0], RHS.VecData[0]), AndNot(LHS.VecData[1], RHS.VecData[1])}};
+    return RetVal;
+  }
+
+  template<int NumBits, int Idx, int SrcIdx> inline uint64_t Shr128_sub(uint64_t Src)
+  {
+    // Low bit of SrcIdx ends up at SrcIdx * 64 - NumBits.
+    // Get position relative to the low bit of Idx (= Idx * 64).
+    static const int SrcLow = SrcIdx * 64 - NumBits - Idx * 64;
+    static const int UseLeftShift = ((SrcLow > 0) && (SrcLow < 64)) ? 1 : 0;
+    static const int UseRightShift = ((SrcLow < 0) && (SrcLow > -64)) ? 1 : 0;
+    static const int UseNoShift = (SrcLow == 0) ? 1 : 0;
+    static const int LShiftBits = (UseLeftShift == 1) ? SrcLow : 0;
+    static const int RShiftBits = (UseRightShift == 1) ? -SrcLow : 0;
+    if (UseLeftShift == 1) return Src << LShiftBits;
+    if (UseRightShift == 1) return Src >> RShiftBits;
+    if (UseNoShift == 1) return Src;
+    return 0;
+  }
+
+  template<int NumBytes> inline uint128_t Shr8(const uint128_t &Src)
+  {
+    uint128_t RetVal = {{
+      Shr128_sub<NumBytes * 8, EndianFix_static_int<1, 0>::Value, EndianFix_static_int<1, 0>::Value>(Src.VecData[0]) |
+      Shr128_sub<NumBytes * 8, EndianFix_static_int<1, 0>::Value, EndianFix_static_int<1, 1>::Value>(Src.VecData[1]),
+      Shr128_sub<NumBytes * 8, EndianFix_static_int<1, 1>::Value, EndianFix_static_int<1, 0>::Value>(Src.VecData[0]) |
+      Shr128_sub<NumBytes * 8, EndianFix_static_int<1, 1>::Value, EndianFix_static_int<1, 1>::Value>(Src.VecData[1])}};
+    return RetVal;
+  }
+
+  template<int NumBytes> inline uint128_t Shl8(const uint128_t &Src)
+  {
+    uint128_t RetVal = {{
+      Shr128_sub<-NumBytes * 8, EndianFix_static_int<1, 0>::Value, EndianFix_static_int<1, 0>::Value>(Src.VecData[0]) |
+      Shr128_sub<-NumBytes * 8, EndianFix_static_int<1, 0>::Value, EndianFix_static_int<1, 1>::Value>(Src.VecData[1]),
+      Shr128_sub<-NumBytes * 8, EndianFix_static_int<1, 1>::Value, EndianFix_static_int<1, 0>::Value>(Src.VecData[0]) |
+      Shr128_sub<-NumBytes * 8, EndianFix_static_int<1, 1>::Value, EndianFix_static_int<1, 1>::Value>(Src.VecData[1])}};
+    return RetVal;
+  }
+
+  template<int NumBits> inline uint128_t Shr_u32(const uint128_t &Src)
+  {
+    uint128_t RetVal = {{
+      (Src.VecData[0] >> NumBits) & U64_Shr32Mask<NumBits>::Value,
+      (Src.VecData[1] >> NumBits) & U64_Shr32Mask<NumBits>::Value}};
+    return RetVal;
+  }
+
+  template<int NumBits> inline uint128_t Shl_u32(const uint128_t &Src)
+  {
+    uint128_t RetVal = {{
+      (Src.VecData[0] << NumBits) & U64_Shr32Mask<NumBits>::Value,
+      (Src.VecData[1] << NumBits) & U64_Shr32Mask<NumBits>::Value}};
+    return RetVal;
+  }
+
+  inline uint128_t Parity(const uint128_t &Src)
+  {
+    uint64_t x = Src.VecData[0] ^ Src.VecData[1];
+    x ^= x << 1;
+    x ^= x << 2;
+    x ^= x << 4;
+    x ^= x << 8;
+    x ^= x << 16;
+    x ^= x << 32;
+    x = static_cast<uint64_t>(static_cast<int64_t>(x) >> 63);
+    uint128_t RetVal = {{x, x}};
+    return RetVal;
+  }
+
+  inline uint128_t make_uint128_t(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3)
+  {
+    #if CFG_ENDIAN == CFG_ENDIAN_LITTLE
+    uint128_t RetVal = {{
+      static_cast<uint64_t>(x0) | (static_cast<uint64_t>(x1) << 32),
+      static_cast<uint64_t>(x2) | (static_cast<uint64_t>(x3) << 32)}};
+    #else
+    uint128_t RetVal = {{
+      static_cast<uint64_t>(x2) | (static_cast<uint64_t>(x3) << 32),
+      static_cast<uint64_t>(x0) | (static_cast<uint64_t>(x1) << 32)}};
+    #endif
+    return RetVal;
+  }
+
+  template<uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3> struct uint128_t_const
+  {
+    static inline uint128_t Value(void)
+    {
+      return make_uint128_t(x0, x1, x2, x3);
+    }
+  };
+
+  inline void EmptyForFP(void) { }
+}
+#else
+// 32-bit implementation
+struct uint128_t
+{
+  uint32_t VecData[4];
+};
+
+inline uint128_t SIMDOP_or(const uint128_t &LHS, const uint128_t &RHS)
+{
+  uint128_t RetVal = {{
+    LHS.VecData[0] | RHS.VecData[0], LHS.VecData[1] | RHS.VecData[1],
+    LHS.VecData[2] | RHS.VecData[2], LHS.VecData[3] | RHS.VecData[3]}};
+  return RetVal;
+}
+
+inline uint128_t SIMDOP_and(const uint128_t &LHS, const uint128_t &RHS)
+{
+  uint128_t RetVal = {{
+    LHS.VecData[0] & RHS.VecData[0], LHS.VecData[1] & RHS.VecData[1],
+    LHS.VecData[2] & RHS.VecData[2], LHS.VecData[3] & RHS.VecData[3]}};
+  return RetVal;
+}
+
+inline uint128_t SIMDOP_xor(const uint128_t &LHS, const uint128_t &RHS)
+{
+  uint128_t RetVal = {{
+    LHS.VecData[0] ^ RHS.VecData[0], LHS.VecData[1] ^ RHS.VecData[1],
+    LHS.VecData[2] ^ RHS.VecData[2], LHS.VecData[3] ^ RHS.VecData[3]}};
+  return RetVal;
+}
+
+namespace SIMDOps
+{
+  inline uint32_t AndNot(const uint32_t LHS, const uint32_t RHS)
+  {
+    return LHS & !RHS;
+  }
+
+  inline uint128_t AndNot(const uint128_t &LHS, const uint128_t &RHS)
+  {
+    uint128_t RetVal = {{
+      AndNot(LHS.VecData[0], RHS.VecData[0]), AndNot(LHS.VecData[1], RHS.VecData[1]),
+      AndNot(LHS.VecData[2], RHS.VecData[2]), AndNot(LHS.VecData[3], RHS.VecData[3])}};
+    return RetVal;
+  }
+
+  template<int NumBits, int Idx, int SrcIdx> inline uint32_t Shr128_sub(uint32_t Src)
+  {
+    // Low bit of SrcIdx ends up at SrcIdx * 32 - NumBits.
+    // Get position relative to the low bit of Idx (= Idx * 32).
+    static const int SrcLow = SrcIdx * 32 - NumBits - Idx * 32;
+    static const int UseLeftShift = ((SrcLow > 0) && (SrcLow < 32)) ? 1 : 0;
+    static const int UseRightShift = ((SrcLow < 0) && (SrcLow > -32)) ? 1 : 0;
+    static const int UseNoShift = (SrcLow == 0) ? 1 : 0;
+    static const int LShiftBits = (UseLeftShift == 1) ? SrcLow : 0;
+    static const int RShiftBits = (UseRightShift == 1) ? -SrcLow : 0;
+    if (UseLeftShift == 1) return Src << LShiftBits;
+    if (UseRightShift == 1) return Src >> RShiftBits;
+    if (UseNoShift == 1) return Src;
+    return 0;
+  }
+
+  template<int NumBytes> inline uint128_t Shr8(const uint128_t &Src)
+  {
+    uint128_t RetVal = {{
+      Shr128_sub<NumBytes * 8, EndianFix_static_int<2, 0>::Value, EndianFix_static_int<2, 0>::Value>(Src.VecData[0]) |
+      Shr128_sub<NumBytes * 8, EndianFix_static_int<2, 0>::Value, EndianFix_static_int<2, 1>::Value>(Src.VecData[1]) |
+      Shr128_sub<NumBytes * 8, EndianFix_static_int<2, 0>::Value, EndianFix_static_int<2, 2>::Value>(Src.VecData[2]) |
+      Shr128_sub<NumBytes * 8, EndianFix_static_int<2, 0>::Value, EndianFix_static_int<2, 3>::Value>(Src.VecData[3]),
+      Shr128_sub<NumBytes * 8, EndianFix_static_int<2, 1>::Value, EndianFix_static_int<2, 0>::Value>(Src.VecData[0]) |
+      Shr128_sub<NumBytes * 8, EndianFix_static_int<2, 1>::Value, EndianFix_static_int<2, 1>::Value>(Src.VecData[1]) |
+      Shr128_sub<NumBytes * 8, EndianFix_static_int<2, 1>::Value, EndianFix_static_int<2, 2>::Value>(Src.VecData[2]) |
+      Shr128_sub<NumBytes * 8, EndianFix_static_int<2, 1>::Value, EndianFix_static_int<2, 3>::Value>(Src.VecData[3]),
+      Shr128_sub<NumBytes * 8, EndianFix_static_int<2, 2>::Value, EndianFix_static_int<2, 0>::Value>(Src.VecData[0]) |
+      Shr128_sub<NumBytes * 8, EndianFix_static_int<2, 2>::Value, EndianFix_static_int<2, 1>::Value>(Src.VecData[1]) |
+      Shr128_sub<NumBytes * 8, EndianFix_static_int<2, 2>::Value, EndianFix_static_int<2, 2>::Value>(Src.VecData[2]) |
+      Shr128_sub<NumBytes * 8, EndianFix_static_int<2, 2>::Value, EndianFix_static_int<2, 3>::Value>(Src.VecData[3]),
+      Shr128_sub<NumBytes * 8, EndianFix_static_int<2, 3>::Value, EndianFix_static_int<2, 0>::Value>(Src.VecData[0]) |
+      Shr128_sub<NumBytes * 8, EndianFix_static_int<2, 3>::Value, EndianFix_static_int<2, 1>::Value>(Src.VecData[1]) |
+      Shr128_sub<NumBytes * 8, EndianFix_static_int<2, 3>::Value, EndianFix_static_int<2, 2>::Value>(Src.VecData[2]) |
+      Shr128_sub<NumBytes * 8, EndianFix_static_int<2, 3>::Value, EndianFix_static_int<2, 3>::Value>(Src.VecData[3])}};
+    return RetVal;
+  }
+
+  template<int NumBytes> inline uint128_t Shl8(const uint128_t &Src)
+  {
+    uint128_t RetVal = {{
+      Shr128_sub<-NumBytes * 8, EndianFix_static_int<2, 0>::Value, EndianFix_static_int<2, 0>::Value>(Src.VecData[0]) |
+      Shr128_sub<-NumBytes * 8, EndianFix_static_int<2, 0>::Value, EndianFix_static_int<2, 1>::Value>(Src.VecData[1]) |
+      Shr128_sub<-NumBytes * 8, EndianFix_static_int<2, 0>::Value, EndianFix_static_int<2, 2>::Value>(Src.VecData[2]) |
+      Shr128_sub<-NumBytes * 8, EndianFix_static_int<2, 0>::Value, EndianFix_static_int<2, 3>::Value>(Src.VecData[3]),
+      Shr128_sub<-NumBytes * 8, EndianFix_static_int<2, 1>::Value, EndianFix_static_int<2, 0>::Value>(Src.VecData[0]) |
+      Shr128_sub<-NumBytes * 8, EndianFix_static_int<2, 1>::Value, EndianFix_static_int<2, 1>::Value>(Src.VecData[1]) |
+      Shr128_sub<-NumBytes * 8, EndianFix_static_int<2, 1>::Value, EndianFix_static_int<2, 2>::Value>(Src.VecData[2]) |
+      Shr128_sub<-NumBytes * 8, EndianFix_static_int<2, 1>::Value, EndianFix_static_int<2, 3>::Value>(Src.VecData[3]),
+      Shr128_sub<-NumBytes * 8, EndianFix_static_int<2, 2>::Value, EndianFix_static_int<2, 0>::Value>(Src.VecData[0]) |
+      Shr128_sub<-NumBytes * 8, EndianFix_static_int<2, 2>::Value, EndianFix_static_int<2, 1>::Value>(Src.VecData[1]) |
+      Shr128_sub<-NumBytes * 8, EndianFix_static_int<2, 2>::Value, EndianFix_static_int<2, 2>::Value>(Src.VecData[2]) |
+      Shr128_sub<-NumBytes * 8, EndianFix_static_int<2, 2>::Value, EndianFix_static_int<2, 3>::Value>(Src.VecData[3]),
+      Shr128_sub<-NumBytes * 8, EndianFix_static_int<2, 3>::Value, EndianFix_static_int<2, 0>::Value>(Src.VecData[0]) |
+      Shr128_sub<-NumBytes * 8, EndianFix_static_int<2, 3>::Value, EndianFix_static_int<2, 1>::Value>(Src.VecData[1]) |
+      Shr128_sub<-NumBytes * 8, EndianFix_static_int<2, 3>::Value, EndianFix_static_int<2, 2>::Value>(Src.VecData[2]) |
+      Shr128_sub<-NumBytes * 8, EndianFix_static_int<2, 3>::Value, EndianFix_static_int<2, 3>::Value>(Src.VecData[3])}};
+    return RetVal;
+  }
+
+  template<int NumBits> inline uint128_t Shr_u32(const uint128_t &Src)
+  {
+    uint128_t RetVal = {{
+      Src.VecData[0] >> NumBits, Src.VecData[1] >> NumBits,
+      Src.VecData[2] >> NumBits, Src.VecData[3] >> NumBits}};
+    return RetVal;
+  }
+
+  template<int NumBits> inline uint128_t Shl_u32(const uint128_t &Src)
+  {
+    uint128_t RetVal = {{
+      Src.VecData[0] << NumBits, Src.VecData[1] << NumBits,
+      Src.VecData[2] << NumBits, Src.VecData[3] << NumBits}};
+    return RetVal;
+  }
+
+  inline uint128_t Parity(const uint128_t &Src)
+  {
+    uint32_t x = Src.VecData[0] ^ Src.VecData[1] ^ Src.VecData[2] ^ Src.VecData[3];
+    x ^= x << 1;
+    x ^= x << 2;
+    x ^= x << 4;
+    x ^= x << 8;
+    x ^= x << 16;
+    x = static_cast<uint32_t>(static_cast<int32_t>(x) >> 31);
+    uint128_t RetVal = {{x, x, x, x}};
+    return RetVal;
+  }
+
+  inline uint128_t make_uint128_t(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3)
+  {
+    #if CFG_ENDIAN == CFG_ENDIAN_LITTLE
+    uint128_t RetVal = {{x0, x1, x2, x3}};
+    #else
+    uint128_t RetVal = {{x3, x2, x1, x0}};
+    #endif
+    return RetVal;
+  }
+
+  template<uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3> struct uint128_t_const
+  {
+    static inline uint128_t Value(void)
+    {
+      return make_uint128_t(x0, x1, x2, x3);
+    }
+  };
+
+  inline void EmptyForFP(void) { }
+}
+#endif
+
+#endif
+
+// -----------------------------------------------------------------------------
+// A vector of 4 FP32's.
+// -----------------------------------------------------------------------------
+
+#if (CFG_HAVE_SSE1 == 1) && !defined(CFG_HAVE_U128FP32)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// SSE1 implementation.
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#define CFG_HAVE_U128FP32 CFG_SIMD_INTRINSIC
+
+typedef __m128 uint128fp32_t;
+
+namespace SIMDOps
+{
+  #if (CFG_HAVE_U128 == CFG_SIMD_INTRINSIC)
+  inline __m128 simdcast_fp32(const uint128_t Src)
+  { return _mm_castsi128_ps(Src); }
+  #elif (CFG_HAVE_U128 == CFG_SIMD_MMX)
+  inline __m128 simdcast_fp32(const uint128_t &Src)
+  {
+    static const union
+    {
+      __m64 AsMMX[2];
+      __m128 AsM128;
+    } InitData = {{Src.VecData[0], Src.VecData[1]}};
+    return InitData.AsM128;
+  }
+  #elif CFG_BITS == 64
+  inline __m128 simdcast_fp32(const uint128_t &Src)
+  {
+    static const union
+    {
+      uint64_t AsU64[2];
+      __m128 AsM128;
+    } InitData = {{Src.VecData[0], Src.VecData[1]}};
+    return InitData.AsM128;
+  }
+  #else
+  inline __m128 simdcast_fp32(const uint128_t &Src)
+  {
+    static const union
+    {
+      uint64_t AsU32[4];
+      __m128 AsM128;
+    } InitData = {{Src.VecData[0], Src.VecData[1], Src.VecData[2], Src.VecData[3]}};
+    return InitData.AsM128;
+  }
+  #endif
+
+  template<uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3> struct uint128fp32_t_const
+  {
+    static __m128 Value(void)
+    {
+      static const union
+      {
+        uint32_t AsU32[4];
+        __m128 AsM128;
+      } InitData = {{x0, x1, x2, x3}};
+      return InitData.AsM128;
+    }
+  };
+}
+#endif
+
+#if !defined(CFG_HAVE_U128FP32)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Scalar implementation.
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#define CFG_HAVE_U128FP32 CFG_SIMD_SCALAR
+
+struct uint128fp32_t
+{
+  float VecData[4];
+};
+
+inline uint128fp32_t SIMDOP_add(const uint128fp32_t &LHS, const uint128fp32_t &RHS)
+{
+  uint128fp32_t RetVal = {{
+    LHS.VecData[0] + RHS.VecData[0], LHS.VecData[1] + RHS.VecData[1],
+    LHS.VecData[2] + RHS.VecData[2], LHS.VecData[3] + RHS.VecData[3]}};
+  return RetVal;
+}
+
+inline uint128fp32_t SIMDOP_sub(const uint128fp32_t &LHS, const uint128fp32_t &RHS)
+{
+  uint128fp32_t RetVal = {{
+    LHS.VecData[0] - RHS.VecData[0], LHS.VecData[1] - RHS.VecData[1],
+    LHS.VecData[2] - RHS.VecData[2], LHS.VecData[3] - RHS.VecData[3]}};
+  return RetVal;
+}
+
+inline uint128fp32_t SIMDOP_mul(const uint128fp32_t &LHS, const uint128fp32_t &RHS)
+{
+  uint128fp32_t RetVal = {{
+    LHS.VecData[0] * RHS.VecData[0], LHS.VecData[1] * RHS.VecData[1],
+    LHS.VecData[2] * RHS.VecData[2], LHS.VecData[3] * RHS.VecData[3]}};
+  return RetVal;
+}
+
+inline uint128fp32_t SIMDOP_or(const uint128fp32_t &LHS, const uint128fp32_t &RHS)
+{
+  union
+  {
+    uint128fp32_t AsU128FP32[2];
+    uint128_t AsU128[2];
+  } ConvData;
+  ConvData.AsU128FP32[0] = LHS; ConvData.AsU128FP32[1] = RHS;
+  ConvData.AsU128[0] = SIMDOP_or(ConvData.AsU128[0], ConvData.AsU128[1]);
+  return ConvData.AsU128FP32[0];
+}
+
+inline uint128fp32_t SIMDOP_and(const uint128fp32_t &LHS, const uint128fp32_t &RHS)
+{
+  union
+  {
+    uint128fp32_t AsU128FP32[2];
+    uint128_t AsU128[2];
+  } ConvData;
+  ConvData.AsU128FP32[0] = LHS; ConvData.AsU128FP32[1] = RHS;
+  ConvData.AsU128[0] = SIMDOP_and(ConvData.AsU128[0], ConvData.AsU128[1]);
+  return ConvData.AsU128FP32[0];
+}
+
+inline uint128fp32_t SIMDOP_xor(const uint128fp32_t &LHS, const uint128fp32_t &RHS)
+{
+  union
+  {
+    uint128fp32_t AsU128FP32[2];
+    uint128_t AsU128[2];
+  } ConvData;
+  ConvData.AsU128FP32[0] = LHS; ConvData.AsU128FP32[1] = RHS;
+  ConvData.AsU128[0] = SIMDOP_xor(ConvData.AsU128[0], ConvData.AsU128[1]);
+  return ConvData.AsU128FP32[0];
+}
+
+namespace SIMDOps
+{
+  inline uint128fp32_t simdcast_fp32(const uint128_t &Src)
+  {
+    union
+    {
+      uint128_t AsU128;
+      uint128fp32_t AsU128FP32;
+    } ConvData;
+    ConvData.AsU128 = Src;
+    return ConvData.AsU128FP32;
+  }
+
+  template<uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3> struct uint128fp32_t_const
+  {
+    static uint128fp32_t Value(void)
+    {
+      static const union
+      {
+        uint32_t AsU32[4];
+        uint128fp32_t AsU128FP32;
+      } InitData =
+      #if CFG_ENDIAN == CFG_ENDIAN_LITTLE
+        {{x0, x1, x2, x3}};
+      #else
+        {{x3, x2, x1, x0}};
+      #endif
+      return InitData.AsU128FP32;
+    }
+  };
+}
+#endif
+
+// -----------------------------------------------------------------------------
+// A vector of 2 FP64's.
+// -----------------------------------------------------------------------------
+
+#if (CFG_HAVE_SSE2 == 1) && (CFG_ONLY_INTEGER_SSE2 == 0)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// SSE2 implementation.
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#define CFG_HAVE_U128FP64 CFG_SIMD_INTRINSIC
+
+typedef __m128d uint128fp64_t;
+
+namespace SIMDOps
+{
+  inline __m128d CmpLT(__m128d LHS, __m128d RHS)
+  { return _mm_cmplt_pd(LHS, RHS); }
+
+  inline __m128d CmpGE(__m128d LHS, __m128d RHS)
+  { return _mm_cmpge_pd(LHS, RHS); }
+
+  inline __m128d simdcast_fp64(const uint128_t &Src)
+  { return _mm_castsi128_pd(Src); }
+
+  template<uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3> struct uint128fp64_t_const
+  {
+    static __m128d Value(void)
+    {
+      static const union
+      {
+        uint32_t AsU32[4];
+        __m128d AsM128D;
+      } InitData = {{x0, x1, x2, x3}};
+      return InitData.AsM128D;
+    }
+  };
+
+  inline __m128d make_uint128fp64_t(double x0, double x1)
+  {
+    union
+    {
+      double AsFP64[2];
+      __m128d AsM128D;
+    } InitData = {{x0, x1}};
+    return InitData.AsM128D;
+  }
+
+  // Approximate reciprocal.
+  inline __m128d recip_a(__m128d x)
+  {
+    return _mm_cvtps_pd(_mm_rcp_ps(_mm_cvtpd_ps(x)));
+  }
+}
+
+#endif
+
+#if !defined(CFG_HAVE_U128FP64)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Scalar implementation
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#define CFG_HAVE_U128FP64 CFG_SIMD_SCALAR
+
+struct uint128fp64_t
+{
+  double VecData[2];
+};
+
+inline uint128fp64_t SIMDOP_add(const uint128fp64_t &LHS, const uint128fp64_t &RHS)
+{
+  uint128fp64_t RetVal = {{
+    LHS.VecData[0] + RHS.VecData[0], LHS.VecData[1] + RHS.VecData[1]}};
+  return RetVal;
+}
+
+inline uint128fp64_t SIMDOP_sub(const uint128fp64_t &LHS, const uint128fp64_t &RHS)
+{
+  uint128fp64_t RetVal = {{
+    LHS.VecData[0] - RHS.VecData[0], LHS.VecData[1] - RHS.VecData[1]}};
+  return RetVal;
+}
+
+inline uint128fp64_t SIMDOP_mul(const uint128fp64_t &LHS, const uint128fp64_t &RHS)
+{
+  uint128fp64_t RetVal = {{
+    LHS.VecData[0] * RHS.VecData[0], LHS.VecData[1] * RHS.VecData[1]}};
+  return RetVal;
+}
+
+inline uint128fp64_t SIMDOP_or(const uint128fp64_t &LHS, const uint128fp64_t &RHS)
+{
+  union
+  {
+    uint128fp64_t AsU128FP64[2];
+    uint128_t AsU128[2];
+  } ConvData;
+  ConvData.AsU128FP64[0] = LHS; ConvData.AsU128FP64[1] = RHS;
+  ConvData.AsU128[0] = SIMDOP_or(ConvData.AsU128[0], ConvData.AsU128[1]);
+  return ConvData.AsU128FP64[0];
+}
+
+inline uint128fp64_t SIMDOP_and(const uint128fp64_t &LHS, const uint128fp64_t &RHS)
+{
+  union
+  {
+    uint128fp64_t AsU128FP64[2];
+    uint128_t AsU128[2];
+  } ConvData;
+  ConvData.AsU128FP64[0] = LHS; ConvData.AsU128FP64[1] = RHS;
+  ConvData.AsU128[0] = SIMDOP_and(ConvData.AsU128[0], ConvData.AsU128[1]);
+  return ConvData.AsU128FP64[0];
+}
+
+inline uint128fp64_t SIMDOP_xor(const uint128fp64_t &LHS, const uint128fp64_t &RHS)
+{
+  union
+  {
+    uint128fp64_t AsU128FP64[2];
+    uint128_t AsU128[2];
+  } ConvData;
+  ConvData.AsU128FP64[0] = LHS; ConvData.AsU128FP64[1] = RHS;
+  ConvData.AsU128[0] = SIMDOP_xor(ConvData.AsU128[0], ConvData.AsU128[1]);
+  return ConvData.AsU128FP64[0];
+}
+
+namespace SIMDOps
+{
+  inline uint128fp64_t simdcast_fp64(const uint128_t &Src)
+  {
+    union
+    {
+      uint128_t AsU128;
+      uint128fp64_t AsU128FP64;
+    } ConvData;
+    ConvData.AsU128 = Src;
+    return ConvData.AsU128FP64;
+  }
+
+  template<uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3> struct uint128fp64_t_const
+  {
+    static uint128fp64_t Value(void)
+    {
+      static const union
+      {
+        uint32_t AsU32[4];
+        uint128fp64_t AsU128FP64;
+      } InitData =
+      #if CFG_ENDIAN == CFG_ENDIAN_LITTLE
+        {{x0, x1, x2, x3}};
+      #else
+        {{x3, x2, x1, x0}};
+      #endif
+      return InitData.AsU128FP64;
+    }
+  };
+}
+#endif
+
+// -----------------------------------------------------------------------------
+// Generic buffer type.
+// -----------------------------------------------------------------------------
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// The views of the main class.
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+template<int NumBytes> class CDataBuffer;
+
+template<class ElementType, int NumBytes> class CDataBuffer_ConstView
+{
+  private:
+    CDataBuffer_ConstView(void);
+};
+
+template<class ElementType, int NumBytes> class CDataBuffer_VarView
+{
+  private:
+    CDataBuffer_VarView(void);
+};
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Template implementations.
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#define BUFVIEWIMPL2(ElementType, Suffix, StoreType)                                              \
+template<int NumBytes> class CDataBuffer_ConstView<ElementType, NumBytes>                         \
+{                                                                                                 \
+  private:                                                                                        \
+    const CDataBuffer<NumBytes> &FDataBuffer;                                                     \
+    CDataBuffer_ConstView<ElementType, NumBytes> &operator=(const CDataBuffer_ConstView<ElementType, NumBytes> &Src);\
+  public:                                                                                         \
+    inline CDataBuffer_ConstView(const CDataBuffer<NumBytes> &DataBuffer) : FDataBuffer(DataBuffer) { } \
+    inline CDataBuffer_ConstView(const CDataBuffer_ConstView<ElementType, NumBytes> &Src) : FDataBuffer(Src.FDataBuffer) { } \
+    inline ElementType Load(size_t Idx) const { return FDataBuffer.Load##Suffix(Idx); }           \
+    inline const ElementType *GetPointer(void) const { return FDataBuffer.GetPointer##Suffix(); } \
+};                                                                                                \
+                                                                                                  \
+template<int NumBytes> class CDataBuffer_VarView<ElementType, NumBytes>                           \
+{                                                                                                 \
+  private:                                                                                        \
+    CDataBuffer<NumBytes> &FDataBuffer;                                                           \
+    CDataBuffer_VarView<ElementType, NumBytes> &operator=(const CDataBuffer_VarView<ElementType, NumBytes> &Src);\
+  public:                                                                                         \
+    inline CDataBuffer_VarView(CDataBuffer<NumBytes> &DataBuffer) : FDataBuffer(DataBuffer) { }   \
+    inline CDataBuffer_VarView(const CDataBuffer_VarView<ElementType, NumBytes> &Src) : FDataBuffer(Src.FDataBuffer) { } \
+    inline ElementType Load(size_t Idx) const { return FDataBuffer.Load##Suffix(Idx); }           \
+    inline void Store(size_t Idx, const StoreType Src) { FDataBuffer.Store##Suffix(Idx, Src); }   \
+    inline ElementType *GetPointer(void) { return FDataBuffer.GetPointer##Suffix(); }             \
+};
+
+#define BUFVIEWIMPL(ElementType, Suffix) BUFVIEWIMPL2(ElementType, Suffix, ElementType)
+
+BUFVIEWIMPL( uint8_t, U8)
+BUFVIEWIMPL(  int8_t, I8)
+BUFVIEWIMPL(uint16_t, U16)
+BUFVIEWIMPL( int16_t, I16)
+BUFVIEWIMPL(uint32_t, U32)
+BUFVIEWIMPL( int32_t, I32)
+BUFVIEWIMPL(uint64_t, U64)
+BUFVIEWIMPL( int64_t, I64)
+BUFVIEWIMPL(double, FP64)
+BUFVIEWIMPL(float, FP32)
+BUFVIEWIMPL2(uint128_t, U128, uint128_t &)
+BUFVIEWIMPL2(uint128fp32_t, U128FP32, uint128fp32_t &)
+BUFVIEWIMPL2(uint128fp64_t, U128FP64, uint128fp64_t &)
+
+#if (CFG_HAVE_MMX == 1)
+  BUFVIEWIMPL(   __m64, M64)
+#endif
+/*
+#if (CFG_HAVE_SSE1 == 1)
+  BUFVIEWIMPL(  __m128, M128)
+#endif
+#if (CFG_HAVE_SSE2 == 1)
+  BUFVIEWIMPL( __m128i, M128I)
+  BUFVIEWIMPL( __m128d, M128D)
+#endif
+*/
+#undef BUFVIEWIMPL
+#undef BUFVIEWIMPL2
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// The main class
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if (CFG_COMPILER == CFG_COMPILER_MSVC)
+// MSVC emits spurious C4328 errors on CDataBuffer, so squish them.
+#pragma warning(disable : 4328)
+#endif
+
+template<int NumBytes> class CDataBuffer
+{
+  private:
+    union TAllData
+    {
+      #if (CFG_HAVE_SSE2 == 1)
+      __m128i     AsM128I[NumBytes / 16];
+      #if (CFG_ONLY_INTEGER_SSE2 == 0)
+      __m128d     AsM128D[NumBytes / 16];
+      #endif
+      #endif
+      #if (CFG_HAVE_SSE1 == 1)
+      __m128    AsM128[NumBytes / 16];
+      #endif
+      #if (CFG_HAVE_MMX == 1)
+      __m64     AsM64[NumBytes / 8];
+      #endif
+       uint8_t  AsU8 [NumBytes    ];
+        int8_t  AsI8 [NumBytes    ];
+      uint16_t  AsU16[NumBytes / 2];
+       int16_t  AsI16[NumBytes / 2];
+      uint32_t  AsU32[NumBytes / 4];
+       int32_t  AsI32[NumBytes / 4];
+      uint64_t  AsU64[NumBytes / 8];
+       int64_t  AsI64[NumBytes / 8];
+      double    AsFP64[NumBytes / 8];
+      float     AsFP32[NumBytes / 4];
+      uint128_t AsU128[NumBytes / 16];
+      uint128fp32_t AsU128FP32[NumBytes / 16];
+      uint128fp64_t AsU128FP64[NumBytes / 16];
+    };
+    ALIGN_16(TAllData, FVecData);
+  public:
+      inline uint8_t LoadU8(size_t Idx) const { return FVecData.AsU8[Idx]; }
+      inline void StoreU8(size_t Idx, const uint8_t Src) { FVecData.AsU8[Idx] = Src; }
+      inline int8_t LoadI8(size_t Idx) const { return FVecData.AsI8[Idx]; }
+      inline void StoreI8(size_t Idx, const int8_t Src) { FVecData.AsI8[Idx] = Src; }
+
+      inline uint16_t LoadU16(size_t Idx) const { return FVecData.AsU16[Idx]; }
+      inline void StoreU16(size_t Idx, const uint16_t Src) { FVecData.AsU16[Idx] = Src; }
+      inline int16_t LoadI16(size_t Idx) const { return FVecData.AsI16[Idx]; }
+      inline void StoreI16(size_t Idx, const int16_t Src) { FVecData.AsI16[Idx] = Src; }
+
+      inline uint32_t LoadU32(size_t Idx) const { return FVecData.AsU32[Idx]; }
+      inline void StoreU32(size_t Idx, const uint32_t Src) { FVecData.AsU32[Idx] = Src; }
+      inline int32_t LoadI32(size_t Idx) const { return FVecData.AsI32[Idx]; }
+      inline void StoreI32(size_t Idx, const int32_t Src) { FVecData.AsI32[Idx] = Src; }
+
+      inline uint64_t LoadU64(size_t Idx) const { return FVecData.AsU64[Idx]; }
+      inline void StoreU64(size_t Idx, const uint64_t Src) { FVecData.AsU64[Idx] = Src; }
+      inline int64_t LoadI64(size_t Idx) const { return FVecData.AsI64[Idx]; }
+      inline void StoreI64(size_t Idx, const int64_t Src) { FVecData.AsI64[Idx] = Src; }
+
+      inline float LoadFP32(size_t Idx) const { return FVecData.AsFP32[Idx]; }
+      inline void StoreFP32(size_t Idx, const float Src) { FVecData.AsFP32[Idx] = Src; }
+
+      inline double LoadFP64(size_t Idx) const { return FVecData.AsFP64[Idx]; }
+      inline void StoreFP64(size_t Idx, const double Src) { FVecData.AsFP64[Idx] = Src; }
+
+      inline uint128_t LoadU128(size_t Idx) const { return FVecData.AsU128[Idx]; }
+      inline void StoreU128(size_t Idx, const uint128_t &Src) { FVecData.AsU128[Idx] = Src; }
+
+      inline uint128fp32_t LoadU128FP32(size_t Idx) const { return FVecData.AsU128FP32[Idx]; }
+      inline void StoreU128FP32(size_t Idx, const uint128fp32_t &Src) { FVecData.AsU128FP32[Idx] = Src; }
+
+      inline uint128fp64_t LoadU128FP64(size_t Idx) const { return FVecData.AsU128FP64[Idx]; }
+      inline void StoreU128FP64(size_t Idx, const uint128fp64_t &Src) { FVecData.AsU128FP64[Idx] = Src; }
+
+      #if (CFG_HAVE_MMX == 1)
+      inline __m64 LoadM64(size_t Idx) const { return FVecData.AsM64[Idx]; }
+      inline void StoreM64(size_t Idx, const __m64 Src) { FVecData.AsM64[Idx] = Src; }
+      #endif
+
+      #if (CFG_HAVE_SSE1 == 1)
+      inline __m128 LoadM128(size_t Idx) const { return FVecData.AsM128[Idx]; }
+      inline void StoreM128(size_t Idx, const __m128 Src) { FVecData.AsM128[Idx] = Src; }
+      #endif
+
+      #if (CFG_HAVE_SSE2 == 1)
+      inline __m128i LoadM128I(size_t Idx) const { return FVecData.AsM128I[Idx]; }
+      inline void StoreM128I(size_t Idx, const __m128i Src) { FVecData.AsM128I[Idx] = Src; }
+      #if (CFG_ONLY_INTEGER_SSE2 == 0)
+      inline __m128d LoadM128D(size_t Idx) const { return FVecData.AsM128D[Idx]; }
+      inline void StoreM128D(size_t Idx, const __m128d Src) { FVecData.AsM128D[Idx] = Src; }
+      #endif
+      #endif
+
+      inline void *GetPointerVoid(void) { return FVecData.AsU8; }
+      inline const void *GetPointerVoid(void) const { return FVecData.AsU8; }
+
+      inline uint8_t *GetPointerU8(void) { return FVecData.AsU8; }
+      inline const uint8_t *GetPointerU8(void) const { return FVecData.AsU8; }
+      inline int8_t *GetPointerI8(void) { return FVecData.AsI8; }
+      inline const int8_t *GetPointerI8(void) const { return FVecData.AsI8; }
+
+      inline uint16_t *GetPointerU16(void) { return FVecData.AsU16; }
+      inline const uint16_t *GetPointerU16(void) const { return FVecData.AsU16; };
+      inline int16_t *GetPointerI16(void) { return FVecData.AsI16; };
+      inline const int16_t *GetPointerI16(void) const { return FVecData.AsI16; };
+
+      inline uint32_t *GetPointerU32(void) { return FVecData.AsU32; };
+      inline const uint32_t *GetPointerU32(void) const { return FVecData.AsU32; };
+      inline int32_t *GetPointerI32(void) { return FVecData.AsI32; };
+      inline const int32_t *GetPointerI32(void) const { return FVecData.AsI32; };
+
+      inline uint64_t *GetPointerU64(void) { return FVecData.AsU64; };
+      inline const uint64_t *GetPointerU64(void) const { return FVecData.AsU64; };
+      inline int64_t *GetPointerI64(void) { return FVecData.AsI64; };
+      inline const int64_t *GetPointerI64(void) const { return FVecData.AsI64; };
+
+      inline double *GetPointerFP64(void) { return FVecData.AsFP64; };
+      inline const double *GetPointerFP64(void) const { return FVecData.AsFP64; };
+
+      inline float *GetPointerFP32(void) { return FVecData.AsFP32; };
+      inline const float *GetPointerFP32(void) const { return FVecData.AsFP32; };
+
+      #if (CFG_HAVE_MMX == 1)
+      inline __m64 *GetPointerM64(void) { return FVecData.AsM64; };
+      inline const __m64 *GetPointerM64(void) const { return FVecData.AsM64; };
+      #endif
+
+      #if (CFG_HAVE_SSE1 == 1)
+      inline __m128 *GetPointerM128(void) { return FVecData.AsM128; };
+      inline const __m128 *GetPointerM128(void) const { return FVecData.AsM128; };
+      #endif
+
+      #if (CFG_HAVE_SSE2 == 1)
+      inline __m128i *GetPointerM128I(void) { return FVecData.AsM128I; };
+      inline const __m128i *GetPointerM128I(void) const { return FVecData.AsM128I; };
+      #if (CFG_ONLY_INTEGER_SSE2 == 0)
+      inline __m128d *GetPointerM128D(void) { return FVecData.AsM128D; };
+      inline const __m128d *GetPointerM128D(void) const { return FVecData.AsM128D; };
+      #endif
+      #endif
+
+      inline uint128_t *GetPointerU128(void) { return FVecData.AsU128; };
+      inline const uint128_t *GetPointerU128(void) const { return FVecData.AsU128; };
+
+      inline uint128fp32_t *GetPointerU128FP32(void) { return FVecData.AsU128FP32; };
+      inline const uint128fp32_t *GetPointerU128FP32(void) const { return FVecData.AsU128FP32; };
+
+      inline uint128fp64_t *GetPointerU128FP64(void) { return FVecData.AsU128FP64; };
+      inline const uint128fp64_t *GetPointerU128FP64(void) const { return FVecData.AsU128FP64; };
+
+      template<class ElementType> inline CDataBuffer_ConstView<ElementType, NumBytes> GetConstView(void) const
+      { return CDataBuffer_ConstView<ElementType, NumBytes>(*this); }
+      template<class ElementType> inline CDataBuffer_VarView<ElementType, NumBytes> GetVarView(void)
+      { return CDataBuffer_VarView<ElementType, NumBytes>(*this); }
+};
+
+#if CFG_COMPILER == CFG_COMPILER_MSVC
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/xpdeint/includes/solirte/ziggurat.cpp b/xpdeint/includes/solirte/ziggurat.cpp
new file mode 100644
index 0000000..28d594f
--- /dev/null
+++ b/xpdeint/includes/solirte/ziggurat.cpp
@@ -0,0 +1,814 @@
+/* *****************************************************************************
+/
+/ This file is part of Solirte, a solenoid ion ray-tracing engine.
+/ (c) 2008 Michael Brown.
+/ michael.brown at anu.edu.au
+/
+/ This file contains the raw Ziggurat table data.
+/ *************************************************************************** */
+
+#include "ziggurat.h"
+
+// Gaussian ziggurat:
+//  128 bins:
+//    DIGITS = 32 gives r = 3.442619852328124412387060404999
+//    DIGITS = 48 gives r = 3.442619855896652123156699485478
+//    DIGITS = 64 gives r = 3.442619855896652121424320491467
+//    DIGITS = 80 gives r = 3.442619855896652121424320491467
+//    DIGITS = 96 gives r = 3.442619855896652121424320491467
+//    3.44261985589665212142432049146733971
+//  256 bins:
+//    DIGITS = 32 gives r = 3.654152877891919476822964862999
+//    DIGITS = 48 gives r = 3.654152885361008775196442582742
+//    DIGITS = 64 gives r = 3.654152885361008771645429720399
+//    DIGITS = 80 gives r = 3.654152885361008771645429720399
+//    DIGITS = 96 gives r = 3.654152885361008771645429720399
+//    3.6541528853610087716454297203996
+const CZigguratGaussian_FP32::TBinData CZigguratGaussian_FP32::Bins[CZigguratGaussian_FP32::NumBins] = {
+  {0x7799ec, 3.91075802e+000f, 0, 0},
+  {0x78d2d2, 3.65415287e+000f, 1.26028596e-003f, 1.34878687e-003f},
+  {0x7b3630, 3.44927835e+000f, 2.60907272e-003f, 1.42889982e-003f},
+  {0x7c4fd2, 3.32024479e+000f, 4.03797254e-003f, 1.48443074e-003f},
+  {0x7cf4b9, 3.22457504e+000f, 5.52240340e-003f, 1.52847217e-003f},
+  {0x7d6203, 3.14788938e+000f, 7.05087557e-003f, 1.56570727e-003f},
+  {0x7db036, 3.08352613e+000f, 8.61658249e-003f, 1.59838866e-003f},
+  {0x7deb2c, 3.02783775e+000f, 1.02149714e-002f, 1.62778643e-003f},
+  {0x7e1959, 2.97860336e+000f, 1.18427575e-002f, 1.65469269e-003f},
+  {0x7e3e93, 2.93436694e+000f, 1.34974504e-002f, 1.67963770e-003f},
+  {0x7e5d47, 2.89412117e+000f, 1.51770879e-002f, 1.70299481e-003f},
+  {0x7e7710, 2.85713863e+000f, 1.68800838e-002f, 1.72503816e-003f},
+  {0x7e8d0d, 2.82287741e+000f, 1.86051205e-002f, 1.74597499e-003f},
+  {0x7ea00a, 2.79092121e+000f, 2.03510970e-002f, 1.76596653e-003f},
+  {0x7eb09d, 2.76094389e+000f, 2.21170634e-002f, 1.78514060e-003f},
+  {0x7ebf37, 2.73268533e+000f, 2.39022039e-002f, 1.80360069e-003f},
+  {0x7ecc2f, 2.70593357e+000f, 2.57058032e-002f, 1.82143168e-003f},
+  {0x7ed7c8, 2.68051457e+000f, 2.75272354e-002f, 1.83870411e-003f},
+  {0x7ee237, 2.65628314e+000f, 2.93659400e-002f, 1.85547746e-003f},
+  {0x7eeba8, 2.63311648e+000f, 3.12214177e-002f, 1.87180226e-003f},
+  {0x7ef43e, 2.61091042e+000f, 3.30932178e-002f, 1.88772206e-003f},
+  {0x7efc16, 2.58957601e+000f, 3.49809416e-002f, 1.90327421e-003f},
+  {0x7f0346, 2.56903553e+000f, 3.68842147e-002f, 1.91849167e-003f},
+  {0x7f09e4, 2.54922152e+000f, 3.88027057e-002f, 1.93340320e-003f},
+  {0x7f1000, 2.53007531e+000f, 4.07361090e-002f, 1.94803427e-003f},
+  {0x7f15a9, 2.51154447e+000f, 4.26841453e-002f, 1.96240726e-003f},
+  {0x7f1aea, 2.49358296e+000f, 4.46465537e-002f, 1.97654264e-003f},
+  {0x7f1fce, 2.47615004e+000f, 4.66230959e-002f, 1.99045823e-003f},
+  {0x7f245f, 2.45920849e+000f, 4.86135520e-002f, 2.00417056e-003f},
+  {0x7f28a4, 2.44272542e+000f, 5.06177247e-002f, 2.01769453e-003f},
+  {0x7f2ca4, 2.42667103e+000f, 5.26354201e-002f, 2.03104294e-003f},
+  {0x7f3065, 2.41101837e+000f, 5.46664596e-002f, 2.04422884e-003f},
+  {0x7f33ed, 2.39574313e+000f, 5.67106903e-002f, 2.05726293e-003f},
+  {0x7f3741, 2.38082290e+000f, 5.87679520e-002f, 2.07015546e-003f},
+  {0x7f3a64, 2.36623716e+000f, 6.08381070e-002f, 2.08291598e-003f},
+  {0x7f3d5a, 2.35196733e+000f, 6.29210249e-002f, 2.09555356e-003f},
+  {0x7f4028, 2.33799624e+000f, 6.50165752e-002f, 2.10807589e-003f},
+  {0x7f42cf, 2.32430792e+000f, 6.71246573e-002f, 2.12049065e-003f},
+  {0x7f4553, 2.31088829e+000f, 6.92451447e-002f, 2.13280460e-003f},
+  {0x7f47b6, 2.29772329e+000f, 7.13779479e-002f, 2.14502471e-003f},
+  {0x7f49fa, 2.28480077e+000f, 7.35229701e-002f, 2.15715659e-003f},
+  {0x7f4c22, 2.27210903e+000f, 7.56801292e-002f, 2.16920627e-003f},
+  {0x7f4e2f, 2.25963712e+000f, 7.78493360e-002f, 2.18117912e-003f},
+  {0x7f5022, 2.24737501e+000f, 8.00305158e-002f, 2.19308003e-003f},
+  {0x7f51fe, 2.23531342e+000f, 8.22235942e-002f, 2.20491365e-003f},
+  {0x7f53c4, 2.22344327e+000f, 8.44285116e-002f, 2.21668486e-003f},
+  {0x7f5575, 2.21175671e+000f, 8.66451934e-002f, 2.22839764e-003f},
+  {0x7f5713, 2.20024562e+000f, 8.88735950e-002f, 2.24005594e-003f},
+  {0x7f589e, 2.18890285e+000f, 9.11136493e-002f, 2.25166394e-003f},
+  {0x7f5a17, 2.17772150e+000f, 9.33653116e-002f, 2.26322492e-003f},
+  {0x7f5b7f, 2.16669512e+000f, 9.56285372e-002f, 2.27474235e-003f},
+  {0x7f5cd8, 2.15581775e+000f, 9.79032815e-002f, 2.28621974e-003f},
+  {0x7f5e21, 2.14508367e+000f, 1.00189500e-001f, 2.29766010e-003f},
+  {0x7f5f5d, 2.13448715e+000f, 1.02487162e-001f, 2.30906671e-003f},
+  {0x7f608a, 2.12402320e+000f, 1.04796223e-001f, 2.32044212e-003f},
+  {0x7f61ab, 2.11368704e+000f, 1.07116669e-001f, 2.33178935e-003f},
+  {0x7f62c0, 2.10347414e+000f, 1.09448455e-001f, 2.34311097e-003f},
+  {0x7f63c8, 2.09337974e+000f, 1.11791566e-001f, 2.35440978e-003f},
+  {0x7f64c6, 2.08339977e+000f, 1.14145979e-001f, 2.36568786e-003f},
+  {0x7f65b8, 2.07353020e+000f, 1.16511665e-001f, 2.37694778e-003f},
+  {0x7f66a1, 2.06376743e+000f, 1.18888617e-001f, 2.38819211e-003f},
+  {0x7f677f, 2.05410790e+000f, 1.21276803e-001f, 2.39942269e-003f},
+  {0x7f6854, 2.04454803e+000f, 1.23676226e-001f, 2.41064210e-003f},
+  {0x7f691f, 2.03508425e+000f, 1.26086876e-001f, 2.42185197e-003f},
+  {0x7f69e2, 2.02571392e+000f, 1.28508717e-001f, 2.43305485e-003f},
+  {0x7f6a9c, 2.01643372e+000f, 1.30941778e-001f, 2.44425260e-003f},
+  {0x7f6b4f, 2.00724077e+000f, 1.33386031e-001f, 2.45544687e-003f},
+  {0x7f6bf9, 1.99813247e+000f, 1.35841474e-001f, 2.46663997e-003f},
+  {0x7f6c9c, 1.98910606e+000f, 1.38308123e-001f, 2.47783330e-003f},
+  {0x7f6d37, 1.98015893e+000f, 1.40785947e-001f, 2.48902920e-003f},
+  {0x7f6dcb, 1.97128868e+000f, 1.43274978e-001f, 2.50022905e-003f},
+  {0x7f6e58, 1.96249306e+000f, 1.45775214e-001f, 2.51143472e-003f},
+  {0x7f6edf, 1.95376968e+000f, 1.48286641e-001f, 2.52264785e-003f},
+  {0x7f6f5f, 1.94511652e+000f, 1.50809288e-001f, 2.53387028e-003f},
+  {0x7f6fd9, 1.93653142e+000f, 1.53343156e-001f, 2.54510366e-003f},
+  {0x7f704d, 1.92801237e+000f, 1.55888259e-001f, 2.55634938e-003f},
+  {0x7f70bb, 1.91955733e+000f, 1.58444613e-001f, 2.56760931e-003f},
+  {0x7f7123, 1.91116452e+000f, 1.61012217e-001f, 2.57888483e-003f},
+  {0x7f7186, 1.90283215e+000f, 1.63591102e-001f, 2.59017758e-003f},
+  {0x7f71e3, 1.89455855e+000f, 1.66181281e-001f, 2.60148896e-003f},
+  {0x7f723a, 1.88634181e+000f, 1.68782771e-001f, 2.61282083e-003f},
+  {0x7f728d, 1.87818050e+000f, 1.71395600e-001f, 2.62417435e-003f},
+  {0x7f72da, 1.87007296e+000f, 1.74019769e-001f, 2.63555138e-003f},
+  {0x7f7323, 1.86201763e+000f, 1.76655322e-001f, 2.64695310e-003f},
+  {0x7f7366, 1.85401309e+000f, 1.79302275e-001f, 2.65838113e-003f},
+  {0x7f73a5, 1.84605789e+000f, 1.81960657e-001f, 2.66983686e-003f},
+  {0x7f73df, 1.83815062e+000f, 1.84630498e-001f, 2.68132170e-003f},
+  {0x7f7414, 1.83028996e+000f, 1.87311813e-001f, 2.69283750e-003f},
+  {0x7f7445, 1.82247460e+000f, 1.90004647e-001f, 2.70438520e-003f},
+  {0x7f7472, 1.81470323e+000f, 1.92709044e-001f, 2.71596666e-003f},
+  {0x7f749a, 1.80697465e+000f, 1.95425004e-001f, 2.72758305e-003f},
+  {0x7f74be, 1.79928756e+000f, 1.98152587e-001f, 2.73923599e-003f},
+  {0x7f74de, 1.79164100e+000f, 2.00891823e-001f, 2.75092688e-003f},
+  {0x7f74f9, 1.78403366e+000f, 2.03642756e-001f, 2.76265712e-003f},
+  {0x7f7511, 1.77646446e+000f, 2.06405401e-001f, 2.77442811e-003f},
+  {0x7f7524, 1.76893246e+000f, 2.09179834e-001f, 2.78624170e-003f},
+  {0x7f7534, 1.76143634e+000f, 2.11966082e-001f, 2.79809884e-003f},
+  {0x7f753f, 1.75397527e+000f, 2.14764178e-001f, 2.81000137e-003f},
+  {0x7f7547, 1.74654830e+000f, 2.17574179e-001f, 2.82195071e-003f},
+  {0x7f754b, 1.73915422e+000f, 2.20396131e-001f, 2.83394824e-003f},
+  {0x7f754a, 1.73179233e+000f, 2.23230079e-001f, 2.84599559e-003f},
+  {0x7f7546, 1.72446156e+000f, 2.26076066e-001f, 2.85809417e-003f},
+  {0x7f753f, 1.71716094e+000f, 2.28934169e-001f, 2.87024537e-003f},
+  {0x7f7533, 1.70988965e+000f, 2.31804416e-001f, 2.88245105e-003f},
+  {0x7f7524, 1.70264685e+000f, 2.34686866e-001f, 2.89471261e-003f},
+  {0x7f7511, 1.69543171e+000f, 2.37581581e-001f, 2.90703145e-003f},
+  {0x7f74fb, 1.68824315e+000f, 2.40488604e-001f, 2.91940942e-003f},
+  {0x7f74e0, 1.68108070e+000f, 2.43408009e-001f, 2.93184817e-003f},
+  {0x7f74c3, 1.67394328e+000f, 2.46339858e-001f, 2.94434885e-003f},
+  {0x7f74a1, 1.66683030e+000f, 2.49284208e-001f, 2.95691355e-003f},
+  {0x7f747c, 1.65974081e+000f, 2.52241135e-001f, 2.96954392e-003f},
+  {0x7f7453, 1.65267420e+000f, 2.55210668e-001f, 2.98224133e-003f},
+  {0x7f7427, 1.64562953e+000f, 2.58192897e-001f, 2.99500790e-003f},
+  {0x7f73f6, 1.63860619e+000f, 2.61187911e-001f, 3.00784479e-003f},
+  {0x7f73c3, 1.63160348e+000f, 2.64195770e-001f, 3.02075432e-003f},
+  {0x7f738b, 1.62462056e+000f, 2.67216504e-001f, 3.03373812e-003f},
+  {0x7f7350, 1.61765683e+000f, 2.70250261e-001f, 3.04679759e-003f},
+  {0x7f7312, 1.61071157e+000f, 2.73297042e-001f, 3.05993529e-003f},
+  {0x7f72cf, 1.60378420e+000f, 2.76356995e-001f, 3.07315239e-003f},
+  {0x7f7289, 1.59687376e+000f, 2.79430151e-001f, 3.08645121e-003f},
+  {0x7f723f, 1.58997989e+000f, 2.82516599e-001f, 3.09983385e-003f},
+  {0x7f71f2, 1.58310175e+000f, 2.85616428e-001f, 3.11330170e-003f},
+  {0x7f71a1, 1.57623875e+000f, 2.88729727e-001f, 3.12685710e-003f},
+  {0x7f714c, 1.56939018e+000f, 2.91856587e-001f, 3.14050214e-003f},
+  {0x7f70f3, 1.56255543e+000f, 2.94997096e-001f, 3.15423892e-003f},
+  {0x7f7096, 1.55573404e+000f, 2.98151314e-001f, 3.16806929e-003f},
+  {0x7f7035, 1.54892504e+000f, 3.01319391e-001f, 3.18199582e-003f},
+  {0x7f6fd1, 1.54212821e+000f, 3.04501384e-001f, 3.19602061e-003f},
+  {0x7f6f68, 1.53534257e+000f, 3.07697415e-001f, 3.21014551e-003f},
+  {0x7f6efc, 1.52856767e+000f, 3.10907573e-001f, 3.22437356e-003f},
+  {0x7f6e8c, 1.52180302e+000f, 3.14131945e-001f, 3.23870638e-003f},
+  {0x7f6e17, 1.51504779e+000f, 3.17370623e-001f, 3.25314701e-003f},
+  {0x7f6d9e, 1.50830162e+000f, 3.20623785e-001f, 3.26769752e-003f},
+  {0x7f6d21, 1.50156367e+000f, 3.23891491e-001f, 3.28236050e-003f},
+  {0x7f6ca0, 1.49483347e+000f, 3.27173829e-001f, 3.29713849e-003f},
+  {0x7f6c1b, 1.48811054e+000f, 3.30470979e-001f, 3.31203453e-003f},
+  {0x7f6b91, 1.48139405e+000f, 3.33783031e-001f, 3.32705071e-003f},
+  {0x7f6b03, 1.47468352e+000f, 3.37110072e-001f, 3.34219029e-003f},
+  {0x7f6a70, 1.46797848e+000f, 3.40452254e-001f, 3.35745607e-003f},
+  {0x7f69d9, 1.46127820e+000f, 3.43809724e-001f, 3.37285083e-003f},
+  {0x7f693c, 1.45458210e+000f, 3.47182572e-001f, 3.38837761e-003f},
+  {0x7f689c, 1.44788969e+000f, 3.50570947e-001f, 3.40403942e-003f},
+  {0x7f67f6, 1.44120026e+000f, 3.53974968e-001f, 3.41983931e-003f},
+  {0x7f674c, 1.43451333e+000f, 3.57394814e-001f, 3.43578076e-003f},
+  {0x7f669c, 1.42782819e+000f, 3.60830605e-001f, 3.45186703e-003f},
+  {0x7f65e8, 1.42114437e+000f, 3.64282459e-001f, 3.46810161e-003f},
+  {0x7f652e, 1.41446126e+000f, 3.67750555e-001f, 3.48448800e-003f},
+  {0x7f646f, 1.40777826e+000f, 3.71235043e-001f, 3.50102945e-003f},
+  {0x7f63aa, 1.40109479e+000f, 3.74736100e-001f, 3.51773016e-003f},
+  {0x7f62e0, 1.39441013e+000f, 3.78253818e-001f, 3.53459362e-003f},
+  {0x7f6210, 1.38772380e+000f, 3.81788403e-001f, 3.55162402e-003f},
+  {0x7f613b, 1.38103521e+000f, 3.85340035e-001f, 3.56882508e-003f},
+  {0x7f605f, 1.37434363e+000f, 3.88908863e-001f, 3.58620146e-003f},
+  {0x7f5f7e, 1.36764860e+000f, 3.92495066e-001f, 3.60375713e-003f},
+  {0x7f5e96, 1.36094940e+000f, 3.96098822e-001f, 3.62149649e-003f},
+  {0x7f5da8, 1.35424531e+000f, 3.99720311e-001f, 3.63942422e-003f},
+  {0x7f5cb3, 1.34753585e+000f, 4.03359741e-001f, 3.65754520e-003f},
+  {0x7f5bb8, 1.34082031e+000f, 4.07017291e-001f, 3.67586385e-003f},
+  {0x7f5ab5, 1.33409810e+000f, 4.10693139e-001f, 3.69438576e-003f},
+  {0x7f59ac, 1.32736862e+000f, 4.14387524e-001f, 3.71311582e-003f},
+  {0x7f589c, 1.32063103e+000f, 4.18100655e-001f, 3.73205938e-003f},
+  {0x7f5784, 1.31388462e+000f, 4.21832711e-001f, 3.75122204e-003f},
+  {0x7f5664, 1.30712903e+000f, 4.25583929e-001f, 3.77060962e-003f},
+  {0x7f553d, 1.30036318e+000f, 4.29354548e-001f, 3.79022816e-003f},
+  {0x7f540d, 1.29358673e+000f, 4.33144778e-001f, 3.81008349e-003f},
+  {0x7f52d5, 1.28679872e+000f, 4.36954856e-001f, 3.83018213e-003f},
+  {0x7f5195, 1.27999842e+000f, 4.40785021e-001f, 3.85053083e-003f},
+  {0x7f504c, 1.27318525e+000f, 4.44635570e-001f, 3.87113611e-003f},
+  {0x7f4ef9, 1.26635826e+000f, 4.48506713e-001f, 3.89200542e-003f},
+  {0x7f4d9d, 1.25951684e+000f, 4.52398717e-001f, 3.91314598e-003f},
+  {0x7f4c38, 1.25266027e+000f, 4.56311852e-001f, 3.93456500e-003f},
+  {0x7f4ac8, 1.24578750e+000f, 4.60246414e-001f, 3.95627134e-003f},
+  {0x7f494e, 1.23889792e+000f, 4.64202702e-001f, 3.97827243e-003f},
+  {0x7f47ca, 1.23199058e+000f, 4.68180954e-001f, 4.00057714e-003f},
+  {0x7f463a, 1.22506464e+000f, 4.72181529e-001f, 4.02319431e-003f},
+  {0x7f449f, 1.21811938e+000f, 4.76204723e-001f, 4.04613325e-003f},
+  {0x7f42f8, 1.21115375e+000f, 4.80250865e-001f, 4.06940375e-003f},
+  {0x7f4145, 1.20416689e+000f, 4.84320283e-001f, 4.09301510e-003f},
+  {0x7f3f84, 1.19715774e+000f, 4.88413274e-001f, 4.11697896e-003f},
+  {0x7f3db7, 1.19012547e+000f, 4.92530257e-001f, 4.14130557e-003f},
+  {0x7f3bdc, 1.18306911e+000f, 4.96671557e-001f, 4.16600611e-003f},
+  {0x7f39f3, 1.17598760e+000f, 5.00837564e-001f, 4.19109268e-003f},
+  {0x7f37fb, 1.16887987e+000f, 5.05028665e-001f, 4.21657786e-003f},
+  {0x7f35f3, 1.16174483e+000f, 5.09245217e-001f, 4.24247468e-003f},
+  {0x7f33dc, 1.15458143e+000f, 5.13487697e-001f, 4.26879665e-003f},
+  {0x7f31b3, 1.14738846e+000f, 5.17756522e-001f, 4.29555727e-003f},
+  {0x7f2f7a, 1.14016485e+000f, 5.22052050e-001f, 4.32277238e-003f},
+  {0x7f2d2e, 1.13290930e+000f, 5.26374876e-001f, 4.35045734e-003f},
+  {0x7f2ad0, 1.12562048e+000f, 5.30725300e-001f, 4.37862799e-003f},
+  {0x7f285d, 1.11829722e+000f, 5.35103917e-001f, 4.40730201e-003f},
+  {0x7f25d7, 1.11093807e+000f, 5.39511263e-001f, 4.43649711e-003f},
+  {0x7f233a, 1.10354173e+000f, 5.43947756e-001f, 4.46623191e-003f},
+  {0x7f2087, 1.09610665e+000f, 5.48413992e-001f, 4.49652737e-003f},
+  {0x7f1dbd, 1.08863139e+000f, 5.52910507e-001f, 4.52740304e-003f},
+  {0x7f1ada, 1.08111441e+000f, 5.57437897e-001f, 4.55888221e-003f},
+  {0x7f17dc, 1.07355404e+000f, 5.61996758e-001f, 4.59098723e-003f},
+  {0x7f14c4, 1.06594872e+000f, 5.66587746e-001f, 4.62374371e-003f},
+  {0x7f118f, 1.05829644e+000f, 5.71211517e-001f, 4.65717632e-003f},
+  {0x7f0e3c, 1.05059564e+000f, 5.75868666e-001f, 4.69131302e-003f},
+  {0x7f0aca, 1.04284430e+000f, 5.80559969e-001f, 4.72618314e-003f},
+  {0x7f0736, 1.03504050e+000f, 5.85286200e-001f, 4.76181693e-003f},
+  {0x7f037f, 1.02718198e+000f, 5.90048015e-001f, 4.79824748e-003f},
+  {0x7effa3, 1.01926672e+000f, 5.94846249e-001f, 4.83550876e-003f},
+  {0x7efba0, 1.01129246e+000f, 5.99681735e-001f, 4.87363804e-003f},
+  {0x7ef774, 1.00325668e+000f, 6.04555368e-001f, 4.91267443e-003f},
+  {0x7ef31b, 9.95157003e-001f, 6.09468043e-001f, 4.95265890e-003f},
+  {0x7eee94, 9.86990750e-001f, 6.14420712e-001f, 4.99363663e-003f},
+  {0x7ee9dc, 9.78755176e-001f, 6.19414389e-001f, 5.03565511e-003f},
+  {0x7ee4ef, 9.70447302e-001f, 6.24450028e-001f, 5.07876417e-003f},
+  {0x7edfcb, 9.62064147e-001f, 6.29528761e-001f, 5.12301922e-003f},
+  {0x7eda6b, 9.53602433e-001f, 6.34651780e-001f, 5.16847800e-003f},
+  {0x7ed4cc, 9.45058703e-001f, 6.39820278e-001f, 5.21520339e-003f},
+  {0x7ecee8, 9.36429322e-001f, 6.45035505e-001f, 5.26326243e-003f},
+  {0x7ec8bc, 9.27710533e-001f, 6.50298715e-001f, 5.31272730e-003f},
+  {0x7ec243, 9.18898165e-001f, 6.55611455e-001f, 5.36367716e-003f},
+  {0x7ebb75, 9.09987926e-001f, 6.60975158e-001f, 5.41619631e-003f},
+  {0x7eb44e, 9.00975227e-001f, 6.66391373e-001f, 5.47037600e-003f},
+  {0x7eacc6, 8.91855061e-001f, 6.71861708e-001f, 5.52631635e-003f},
+  {0x7ea4d5, 8.82622242e-001f, 6.77388012e-001f, 5.58412541e-003f},
+  {0x7e9c72, 8.73271048e-001f, 6.82972133e-001f, 5.64392144e-003f},
+  {0x7e9395, 8.63795519e-001f, 6.88616097e-001f, 5.70583297e-003f},
+  {0x7e8a32, 8.54189157e-001f, 6.94321930e-001f, 5.77000203e-003f},
+  {0x7e803e, 8.44444931e-001f, 7.00091898e-001f, 5.83658321e-003f},
+  {0x7e75aa, 8.34555328e-001f, 7.05928504e-001f, 5.90574741e-003f},
+  {0x7e6a69, 8.24512184e-001f, 7.11834252e-001f, 5.97768370e-003f},
+  {0x7e5e67, 8.14306676e-001f, 7.17811942e-001f, 6.05260069e-003f},
+  {0x7e5193, 8.03929090e-001f, 7.23864555e-001f, 6.13073120e-003f},
+  {0x7e43d5, 7.93369055e-001f, 7.29995251e-001f, 6.21233368e-003f},
+  {0x7e3515, 7.82615006e-001f, 7.36207604e-001f, 6.29769824e-003f},
+  {0x7e2534, 7.71654427e-001f, 7.42505312e-001f, 6.38715085e-003f},
+  {0x7e1411, 7.60473430e-001f, 7.48892426e-001f, 6.48105936e-003f},
+  {0x7e0183, 7.49056637e-001f, 7.55373478e-001f, 6.57984056e-003f},
+  {0x7ded5d, 7.37387240e-001f, 7.61953354e-001f, 6.68396894e-003f},
+  {0x7dd767, 7.25446165e-001f, 7.68637300e-001f, 6.79398933e-003f},
+  {0x7dbf61, 7.13212311e-001f, 7.75431275e-001f, 6.91052759e-003f},
+  {0x7da4fc, 7.00661838e-001f, 7.82341838e-001f, 7.03431107e-003f},
+  {0x7d87db, 6.87767863e-001f, 7.89376140e-001f, 7.16618681e-003f},
+  {0x7d678b, 6.74499810e-001f, 7.96542346e-001f, 7.30715273e-003f},
+  {0x7d437f, 6.60822570e-001f, 8.03849459e-001f, 7.45839113e-003f},
+  {0x7d1b08, 6.46695733e-001f, 8.11307847e-001f, 7.62131717e-003f},
+  {0x7ced48, 6.32072210e-001f, 8.18929195e-001f, 7.79764215e-003f},
+  {0x7cb926, 6.16896987e-001f, 8.26726854e-001f, 7.98945874e-003f},
+  {0x7c7d33, 6.01104617e-001f, 8.34716320e-001f, 8.19936022e-003f},
+  {0x7c3788, 5.84616780e-001f, 8.42915654e-001f, 8.43060575e-003f},
+  {0x7be597, 5.67338228e-001f, 8.51346254e-001f, 8.68736301e-003f},
+  {0x7b83d4, 5.49151719e-001f, 8.60033631e-001f, 8.97506718e-003f},
+  {0x7b0d2f, 5.29909730e-001f, 8.69008660e-001f, 9.30096768e-003f},
+  {0x7a7a35, 5.09423316e-001f, 8.78309667e-001f, 9.67500452e-003f},
+  {0x79bf6b, 4.87443954e-001f, 8.87984633e-001f, 1.01112612e-002f},
+  {0x78ca38, 4.63634342e-001f, 8.98095906e-001f, 1.06305182e-002f},
+  {0x777a5c, 4.37518388e-001f, 9.08726454e-001f, 1.12650646e-002f},
+  {0x7592af, 4.08389121e-001f, 9.19991493e-001f, 1.20685706e-002f},
+  {0x728fb4, 3.75121325e-001f, 9.32060063e-001f, 1.31388772e-002f},
+  {0x6d1aa8, 3.35737526e-001f, 9.45198953e-001f, 1.46801388e-002f},
+  {0x6045f5, 2.86174595e-001f, 9.59879100e-001f, 1.72226094e-002f},
+  {0x0, 2.15241894e-001f, 9.77101684e-001f, 2.28982996e-002f}};
+
+const CZigguratGaussian_FP64::TBinData CZigguratGaussian_FP64::Bins[CZigguratGaussian_FP64::NumBins] = {{UINT64_C(0xed5a442469c86), 3.71308624674036340e+000, 0, 0},
+  {UINT64_C(0xefacc9cb3e7aa), 3.44261985589665190e+000, 2.66962908390250320e-003, 2.87936613691396670e-003},
+  {UINT64_C(0xf4e442ecd31e3), 3.22308498457861870e+000, 5.54899522081647030e-003, 3.07548919211400030e-003},
+  {UINT64_C(0xf75217b867632), 3.08322885821421360e+000, 8.62448441293047100e-003, 3.21499424505184260e-003},
+  {UINT64_C(0xf8c01e3503b07), 2.97869625264501710e+000, 1.18394786579823130e-002, 3.32781935268972860e-003},
+  {UINT64_C(0xf9b36957d7631), 2.89434400701867080e+000, 1.51672980106720420e-002, 3.42480472649377010e-003},
+  {UINT64_C(0xfa61c12ef4eb6), 2.82312535054596660e+000, 1.85921027371658140e-002, 3.51120187894578010e-003},
+  {UINT64_C(0xfae541f793634), 2.76116937238415390e+000, 2.21033046161115930e-002, 3.58998732003802410e-003},
+  {UINT64_C(0xfb4c343c9e1c4), 2.70611357311872250e+000, 2.56932919361496160e-002, 3.66302550410421270e-003},
+  {UINT64_C(0xfb9f18e44c3e0), 2.65640641125819240e+000, 2.93563174402538300e-002, 3.73156870625132590e-003},
+  {UINT64_C(0xfbe354bbf1765), 2.61097224842861310e+000, 3.30878861465051520e-002, 3.79650264046361850e-003},
+  {UINT64_C(0xfc1c7fea75fb0), 2.56903362592163910e+000, 3.68843887869687720e-002, 3.85847928782183080e-003},
+  {UINT64_C(0xfc4d185e5531a), 2.53000967238546660e+000, 4.07428680747906060e-002, 3.91799412608182480e-003},
+  {UINT64_C(0xfc76e6f466e49), 2.49345452209195080e+000, 4.46608622008724250e-002, 3.97543365941162210e-003},
+  {UINT64_C(0xfc9b3bdb13e7c), 2.45901817740835020e+000, 4.86362958602840550e-002, 4.03110604321911800e-003},
+  {UINT64_C(0xfcbb14343dfc6), 2.42642064553021180e+000, 5.26674019035031710e-002, 4.08526157803541440e-003},
+  {UINT64_C(0xfcd7326658ef5), 2.39543427800746760e+000, 5.67526634815385890e-002, 4.13810686702779150e-003},
+  {UINT64_C(0xfcf02e5177e25), 2.36587137011398770e+000, 6.08907703485663740e-002, 4.18981486506549760e-003},
+  {UINT64_C(0xfd068067ddaaa), 2.33757524133553090e+000, 6.50805852136318720e-002, 4.24053218054837920e-003},
+  {UINT64_C(0xfd1a8974e5beb), 2.31041368369500200e+000, 6.93211173941802590e-002, 4.29038449057464120e-003},
+  {UINT64_C(0xfd2c982d9aad3), 2.28427405967365700e+000, 7.36115018847548900e-002, 4.33948062989982130e-003},
+  {UINT64_C(0xfd3ced3f00194), 2.25905957386532960e+000, 7.79509825146547100e-002, 4.38791572830269420e-003},
+  {UINT64_C(0xfd4bbe4f6092c), 2.23468639558705680e+000, 8.23388982429574120e-002, 4.43577365258556070e-003},
+  {UINT64_C(0xfd593840d12ae), 2.21108140887472790e+000, 8.67746718955429710e-002, 4.48312893209174090e-003},
+  {UINT64_C(0xfd6580ea1b2bb), 2.18818043207202080e+000, 9.12578008276347110e-002, 4.53004829494344130e-003},
+  {UINT64_C(0xfd70b86ae561f), 2.16592679374484080e+000, 9.57878491225781640e-002, 4.57659190696738710e-003},
+  {UINT64_C(0xfd7afa35123bb), 2.14427018235626130e+000, 1.00364441029545550e-001, 4.62281438080900000e-003},
+  {UINT64_C(0xfd845ddde3917), 2.12316570866979020e+000, 1.04987255410354540e-001, 4.66876560546322130e-003},
+  {UINT64_C(0xfd8cf7c45b13c), 2.10257313518499880e+000, 1.09656021015817760e-001, 4.71449143407051340e-003},
+  {UINT64_C(0xfd94d996bb7b6), 2.08245623798772470e+000, 1.14370512449888270e-001, 4.76003425883031370e-003},
+  {UINT64_C(0xfd9c12be84a31), 2.06278227450396350e+000, 1.19130546708718590e-001, 4.80543349526315470e-003},
+  {UINT64_C(0xfda2b0b870f3c), 2.04352153665066940e+000, 1.23935980203981740e-001, 4.85072599312221830e-003},
+  {UINT64_C(0xfda8bf5ca5dda), 2.02464697337293400e+000, 1.28786706197103970e-001, 4.89594638754368030e-003},
+  {UINT64_C(0xfdae491a4e357), 2.00613386995896680e+000, 1.33682652584647650e-001, 4.94112740120339600e-003},
+  {UINT64_C(0xfdb357291a996), 1.98795957412306090e+000, 1.38623779985851040e-001, 4.98630010608195830e-003},
+  {UINT64_C(0xfdb7f1b297b7f), 1.97010326084971350e+000, 1.43610080091932990e-001, 5.03149415176397130e-003},
+  {UINT64_C(0xfdbc1ff4dff8a), 1.95254572954888930e+000, 1.48641574243696950e-001, 5.07673796588960480e-003},
+  {UINT64_C(0xfdbfe85fdcab9), 1.93526922829190040e+000, 1.53718312209586570e-001, 5.12205893134850750e-003},
+  {UINT64_C(0xfdc350ae0c352), 1.91825730085973170e+000, 1.58840371140935080e-001, 5.16748354399266910e-003},
+  {UINT64_C(0xfdc65df991f31), 1.90149465310031760e+000, 1.64007854684927760e-001, 5.21303755399700390e-003},
+  {UINT64_C(0xfdc914ce2e802), 1.88496703570286920e+000, 1.69220892238924750e-001, 5.25874609347757110e-003},
+  {UINT64_C(0xfdcb7938a0f83), 1.86866114098954220e+000, 1.74479638332402320e-001, 5.30463379255979170e-003},
+  {UINT64_C(0xfdcd8ed3da108), 1.85256451172308710e+000, 1.79784272124962120e-001, 5.35072488575131810e-003},
+  {UINT64_C(0xfdcf58d456e0c), 1.83666546025338380e+000, 1.85134997010713430e-001, 5.39704331020028890e-003},
+  {UINT64_C(0xfdd0da11e9f84), 1.82095299659100500e+000, 1.90532040320913730e-001, 5.44361279719669280e-003},
+  {UINT64_C(0xfdd215102d142), 1.80541676421404860e+000, 1.95975653118110410e-001, 5.49045695809282760e-003},
+  {UINT64_C(0xfdd30c05cbca7), 1.79004698259461900e+000, 2.01466110076203210e-001, 5.53759936567055880e-003},
+  {UINT64_C(0xfdd3c0e2cf5d4), 1.77483439558076930e+000, 2.07003709441873800e-001, 5.58506363186229980e-003},
+  {UINT64_C(0xfdd435560d34c), 1.75977022489423200e+000, 2.12588773073736110e-001, 5.63287348263449490e-003},
+  {UINT64_C(0xfdd46ad1d3fca), 1.74484612810837650e+000, 2.18221646556370580e-001, 5.68105283076329130e-003},
+  {UINT64_C(0xfdd4628feecae), 1.73005416055824360e+000, 2.23902699387133890e-001, 5.72962584716881630e-003},
+  {UINT64_C(0xfdd41d9511e20), 1.71538674070811670e+000, 2.29632325234302690e-001, 5.77861703142495270e-003},
+  {UINT64_C(0xfdd39cb3c16b7), 1.70083661856430090e+000, 2.35410942265727670e-001, 5.82805128202365950e-003},
+  {UINT64_C(0xfdd2e08ebfc9e), 1.68639684677348620e+000, 2.41238993547751300e-001, 5.87795396694542040e-003},
+  {UINT64_C(0xfdd1e99b0ed52), 1.67206075409185220e+000, 2.47116947514696760e-001, 5.92835099506912410e-003},
+  {UINT64_C(0xfdd0b8218d4e8), 1.65782192094820750e+000, 2.53045298509765870e-001, 5.97926888894488320e-003},
+  {UINT64_C(0xfdcf4c4038209), 1.64367415685698260e+000, 2.59024567398710770e-001, 6.03073485945119800e-003},
+  {UINT64_C(0xfdcda5eb15778), 1.62961147946467830e+000, 2.65055302258161930e-001, 6.08277688286333350e-003},
+  {UINT64_C(0xfdcbc4ecce607), 1.61562809503713290e+000, 2.71138079141025220e-001, 6.13542378087243800e-003},
+  {UINT64_C(0xfdc9a8e6fa665), 1.60171838021527700e+000, 2.77273502921897730e-001, 6.18870530411480630e-003},
+  {UINT64_C(0xfdc751521f7ce), 1.58787686488440060e+000, 2.83462208226012540e-001, 6.24265221979797970e-003},
+  {UINT64_C(0xfdc4bd7d677d5), 1.57409821601674960e+000, 2.89704860445810510e-001, 6.29729640404533880e-003},
+  {UINT64_C(0xfdc1ec8e0b749), 1.56037722235984070e+000, 2.96002156849855810e-001, 6.35267093962392590e-003},
+  {UINT64_C(0xfdbedd7e7400c), 1.54670877985350330e+000, 3.02354827789479810e-001, 6.40881021977215970e-003},
+  {UINT64_C(0xfdbb8f1d0d018), 1.53308787766755610e+000, 3.08763638009251940e-001, 6.46575005890559930e-003},
+  {UINT64_C(0xfdb8000ac9d97), 1.51950958475937090e+000, 3.15229388068157480e-001, 6.52352781105109810e-003},
+  {UINT64_C(0xfdb42eb9566fe), 1.50596903685655010e+000, 3.21752915879208620e-001, 6.58218249694377580e-003},
+  {UINT64_C(0xfdb01968f0057), 1.49246142377461540e+000, 3.28335098376152380e-001, 6.64175494081876550e-003},
+  {UINT64_C(0xfdabbe25dfb4c), 1.47898197698309790e+000, 3.34976853316971190e-001, 6.70228791804252260e-003},
+  {UINT64_C(0xfda71ac58f289), 1.46552595733579460e+000, 3.41679141235013640e-001, 6.76382631485878460e-003},
+  {UINT64_C(0xfda22ce32e93d), 1.45208864288221660e+000, 3.48442967549872470e-001, 6.82641730167467520e-003},
+  {UINT64_C(0xfd9cf1dbe152c), 1.43866531667746140e+000, 3.55269384851547130e-001, 6.89011052148606750e-003},
+  {UINT64_C(0xfd9766ca64bc2), 1.42525125450686160e+000, 3.62159495373033210e-001, 6.95495829524192790e-003},
+  {UINT64_C(0xfd91888222809), 1.41184171243976020e+000, 3.69114453668275110e-001, 7.02101584617929010e-003},
+  {UINT64_C(0xfd8b53899d846), 1.39843191412360630e+000, 3.76135469514454420e-001, 7.08834154542921630e-003},
+  {UINT64_C(0xfd84c414253d5), 1.38501703772514870e+000, 3.83223811059883680e-001, 7.15699718150584340e-003},
+  {UINT64_C(0xfd7dd5fab84c2), 1.37159220241973220e+000, 3.90380808241389490e-001, 7.22704825665306320e-003},
+  {UINT64_C(0xfd7684b3fb21d), 1.35815245432242280e+000, 3.97607856498042530e-001, 7.29856431344579930e-003},
+  {UINT64_C(0xfd6ecb4b22e88), 1.34469275174571300e+000, 4.04906420811488310e-001, 7.37161929553626930e-003},
+  {UINT64_C(0xfd66a455af7c7), 1.33120794965767650e+000, 4.12278040107024620e-001, 7.44629194701361410e-003},
+  {UINT64_C(0xfd5e09e7c8d03), 1.31769278320134300e+000, 4.19724332054038250e-001, 7.52266625552416420e-003},
+  {UINT64_C(0xfd54f5870c6c6), 1.30414185012042160e+000, 4.27246998309562360e-001, 7.60083194509949750e-003},
+  {UINT64_C(0xfd4b601b8e90b), 1.29054959191787310e+000, 4.34847830254661890e-001, 7.68088502558471850e-003},
+  {UINT64_C(0xfd4141dec7702), 1.27691027355169970e+000, 4.42528715280246620e-001, 7.76292840668034620e-003},
+  {UINT64_C(0xfd36924817bd2), 1.26321796144602820e+000, 4.50291643686926980e-001, 7.84707258594500440e-003},
+  {UINT64_C(0xfd2b47f67f96e), 1.24946649956433360e+000, 4.58138716272871950e-001, 7.93343642169901460e-003},
+  {UINT64_C(0xfd1f58970f524), 1.23564948325448110e+000, 4.66072152694570970e-001, 8.02214800367862490e-003},
+  {UINT64_C(0xfd12b8c7819d6), 1.22176023053096250e+000, 4.74094300698249590e-001, 8.11334563658908620e-003},
+  {UINT64_C(0xfd055bf4510cd), 1.20779175040675770e+000, 4.82207646334838700e-001, 8.20717895448294650e-003},
+  {UINT64_C(0xfcf7343176cb3), 1.19373670782377220e+000, 4.90414825289321680e-001, 8.30381018726268630e-003},
+  {UINT64_C(0xfce8320cd30d2), 1.17958738465446070e+000, 4.98718635476584290e-001, 8.40341560472026430e-003},
+  {UINT64_C(0xfcd8445907b15), 1.16533563615504690e+000, 5.07122051081304590e-001, 8.50618716856746220e-003},
+  {UINT64_C(0xfcc757ef46ebf), 1.15097284213897600e+000, 5.15628238249872030e-001, 8.61233442912074510e-003},
+  {UINT64_C(0xfcb557663edcd), 1.13648985200307550e+000, 5.24240572678992820e-001, 8.72208671099478950e-003},
+  {UINT64_C(0xfca22abbd9f85), 1.12187692257225400e+000, 5.32962659389987550e-001, 8.83569564173653480e-003},
+  {UINT64_C(0xfc8db6eefbc49), 1.10712364752353530e+000, 5.41798355031724130e-001, 8.95343808933115290e-003},
+  {UINT64_C(0xfc77dd85a7a76), 1.09221887689655370e+000, 5.50751793121055270e-001, 9.07561958963954040e-003},
+  {UINT64_C(0xfc607bfb0eb26), 1.07715062488193760e+000, 5.59827412710694810e-001, 9.20257836402679430e-003},
+  {UINT64_C(0xfc476b0fc6cb9), 1.06190596368361940e+000, 5.69029991074721520e-001, 9.33469005198070060e-003},
+  {UINT64_C(0xfc2c7df4cf4d5), 1.04647090075258030e+000, 5.78364681126702360e-001, 9.47237331511821200e-003},
+  {UINT64_C(0xfc0f8147e0d63), 1.03083023605645560e+000, 5.87837054441820550e-001, 9.61609650999175650e-003},
+  {UINT64_C(0xfbf039d4a3f47), 1.01496739523929950e+000, 5.97453150951812280e-001, 9.76638568079260350e-003},
+  {UINT64_C(0xfbce630a82c38), 9.98864233480643460e-001, 6.07219536632604860e-001, 9.92383419395760290e-003},
+  {UINT64_C(0xfba9ad117147f), 9.82500803502760370e-001, 6.17143370826562570e-001, 1.00891144312520770e-002},
+  {UINT64_C(0xfb81ba60a1dd6), 9.65855079388130530e-001, 6.27232485257814500e-001, 1.02629920853303090e-002},
+  {UINT64_C(0xfb561cafbb9ed), 9.48902625497911930e-001, 6.37495477343144930e-001, 1.04463437754059340e-002},
+  {UINT64_C(0xfb26510c6d071), 9.31616196601353750e-001, 6.47941821118550810e-001, 1.06401789401028710e-002},
+  {UINT64_C(0xfaf1bac8fa7f9), 9.13965251008801770e-001, 6.58582000058653750e-001, 1.08456672990524870e-002},
+  {UINT64_C(0xfab79cd957292), 8.95915352566238550e-001, 6.69427667357706200e-001, 1.10641736487081650e-002},
+  {UINT64_C(0xfa77110617069), 8.77427429097715760e-001, 6.80491841006414240e-001, 1.12973024396215200e-002},
+  {UINT64_C(0xfa2efc1667f11), 8.58456843178050820e-001, 6.91789143446035810e-001, 1.15469555797815640e-002},
+  {UINT64_C(0xf9ddfda5b286b), 8.38952214281207480e-001, 7.03336099025817400e-001, 1.18154083946596270e-002},
+  {UINT64_C(0xf98259adad18c), 8.18853906683317810e-001, 7.15151507420477060e-001, 1.21054109340288340e-002},
+  {UINT64_C(0xf919d8b6b9593), 7.98092060626274800e-001, 7.27256918354505900e-001, 1.24203253288322700e-002},
+  {UINT64_C(0xf8a199cebca78), 7.76583987876148350e-001, 7.39677243683338200e-001, 1.27643155023656530e-002},
+  {UINT64_C(0xf815ce44612cb), 7.54230664434510150e-001, 7.52441559185703770e-001, 1.31426147235321950e-002},
+  {UINT64_C(0xf771518c32c92), 7.30911910621881210e-001, 7.65584173909235940e-001, 1.35619120324671720e-002},
+  {UINT64_C(0xf6ad054c5acb0), 7.06479611313608040e-001, 7.79146085941703200e-001, 1.40309258421560460e-002},
+  {UINT64_C(0xf5bec53e6296a), 6.80747918645904230e-001, 7.93177011783859240e-001, 1.45612829122619030e-002},
+  {UINT64_C(0xf4979cba30c87), 6.53478638715042300e-001, 8.07738294696121130e-001, 1.51689166991408870e-002},
+  {UINT64_C(0xf3208b87a197a), 6.24358597309088270e-001, 8.22907211395262020e-001, 1.58763939153852250e-002},
+  {UINT64_C(0xf1344b7af4e41), 5.92962942441978000e-001, 8.38783605310647220e-001, 1.67170025744170610e-002},
+  {UINT64_C(0xee9243d6d8ea3), 5.58692178375517990e-001, 8.55500607885064210e-001, 1.77424410417893060e-002},
+  {UINT64_C(0xeac00a3a040d4), 5.20656038725144880e-001, 8.73243048926853560e-001, 1.90386018754491360e-002},
+  {UINT64_C(0xe4b68d43fed6a), 4.77437837253787860e-001, 8.92281650802302710e-001, 2.07619971897353390e-002},
+  {UINT64_C(0xd9c88f4d8196a), 4.26547986303305150e-001, 9.13043647992037970e-001, 2.32390337163330160e-002},
+  {UINT64_C(0xc01e36a71ab09), 3.62871431028418290e-001, 9.36282681708371030e-001, 2.73170114473965250e-002},
+  {UINT64_C(0x0000000000000), 2.72320864704663880e-001, 9.63599693155767540e-001, 3.64003068442324000e-002}};
+
+//  128 bins:
+//    DIGITS = 32 gives r = 6.898315115152075929700371759999
+//    DIGITS = 48 gives r = 6.898315116615642605754685885904
+//    DIGITS = 64 gives r = 6.898315116615642605754685885904
+//    DIGITS = 80 gives r = 6.898315116615642605754685885904
+//    DIGITS = 96 gives r = 6.898315116615642605754685885904
+//    Using 6.898315116615642605754685885905
+//  256 bins:
+//    DIGITS = 32 gives r = 7.697117467070213692186499485999
+//    DIGITS = 48 gives r = 7.697117470131049714044628048015
+//    DIGITS = 64 gives r = 7.697117470131049714044628048015
+//    DIGITS = 80 gives r = 7.697117470131049714044628048015
+//    DIGITS = 96 gives r = 7.697117470131049714044628048015
+//    Using 7.697117470131049714044628048016
+const CZigguratExponential_FP32::TBinData CZigguratExponential_FP32::Bins[CZigguratExponential_FP32::NumBins] = {
+  {0x714851, 8.69711781e+000f, 0, 0},
+  {0x736d37, 7.69711733e+000f, 4.54134366e-004f, 5.13134932e-004f},
+  {0x7777d9, 6.94103384e+000f, 9.67269298e-004f, 5.69030526e-004f},
+  {0x796587, 6.47837830e+000f, 1.53629982e-003f, 6.09667972e-004f},
+  {0x7a8a98, 6.14416456e+000f, 2.14596768e-003f, 6.42831030e-004f},
+  {0x7b4e33, 5.88214445e+000f, 2.78879888e-003f, 6.71465998e-004f},
+  {0x7bdabc, 5.66640997e+000f, 3.46026476e-003f, 6.97030337e-004f},
+  {0x7c44f8, 5.48289061e+000f, 4.15729498e-003f, 7.20360840e-004f},
+  {0x7c9851, 5.32309055e+000f, 4.87765577e-003f, 7.41986209e-004f},
+  {0x7cdb97, 5.18148708e+000f, 5.61964232e-003f, 7.62263720e-004f},
+  {0x7d131e, 5.05428839e+000f, 6.38190610e-003f, 7.81447219e-004f},
+  {0x7d41c9, 4.93877697e+000f, 7.16335326e-003f, 7.99724250e-004f},
+  {0x7d699a, 4.83293962e+000f, 7.96307717e-003f, 8.17237538e-004f},
+  {0x7d8c00, 4.73524284e+000f, 8.78031459e-003f, 8.34098668e-004f},
+  {0x7daa09, 4.64449167e+000f, 9.61441360e-003f, 8.50396522e-004f},
+  {0x7dc480, 4.55973721e+000f, 1.04648098e-002f, 8.66203394e-004f},
+  {0x7ddc03, 4.48021173e+000f, 1.13310134e-002f, 8.81578831e-004f},
+  {0x7df10a, 4.40528774e+000f, 1.22125922e-002f, 8.96572485e-004f},
+  {0x7e03f7, 4.33444357e+000f, 1.31091652e-002f, 9.11226496e-004f},
+  {0x7e1518, 4.26724243e+000f, 1.40203917e-002f, 9.25576605e-004f},
+  {0x7e24ac, 4.20331383e+000f, 1.49459681e-002f, 9.39653837e-004f},
+  {0x7e32e6, 4.14234066e+000f, 1.58856213e-002f, 9.53484967e-004f},
+  {0x7e3ff3, 4.08405113e+000f, 1.68391075e-002f, 9.67093569e-004f},
+  {0x7e4bf7, 4.02820873e+000f, 1.78062003e-002f, 9.80500365e-004f},
+  {0x7e570f, 3.97460604e+000f, 1.87867004e-002f, 9.93723632e-004f},
+  {0x7e6155, 3.92306256e+000f, 1.97804235e-002f, 1.00677973e-003f},
+  {0x7e6ae1, 3.87341762e+000f, 2.07872037e-002f, 1.01968343e-003f},
+  {0x7e73c5, 3.82552934e+000f, 2.18068883e-002f, 1.03244791e-003f},
+  {0x7e7c11, 3.77927089e+000f, 2.28393357e-002f, 1.04508514e-003f},
+  {0x7e83d4, 3.73452878e+000f, 2.38844212e-002f, 1.05760596e-003f},
+  {0x7e8b1a, 3.69120097e+000f, 2.49420255e-002f, 1.07002025e-003f},
+  {0x7e91ef, 3.64919543e+000f, 2.60120463e-002f, 1.08233711e-003f},
+  {0x7e985d, 3.60842872e+000f, 2.70943847e-002f, 1.09456503e-003f},
+  {0x7e9e6b, 3.56882524e+000f, 2.81889495e-002f, 1.10671145e-003f},
+  {0x7ea422, 3.53031588e+000f, 2.92956606e-002f, 1.11878372e-003f},
+  {0x7ea988, 3.49283767e+000f, 3.04144435e-002f, 1.13078824e-003f},
+  {0x7eaea4, 3.45633292e+000f, 3.15452330e-002f, 1.14273129e-003f},
+  {0x7eb37a, 3.42074847e+000f, 3.26879621e-002f, 1.15461869e-003f},
+  {0x7eb811, 3.38603544e+000f, 3.38425823e-002f, 1.16645556e-003f},
+  {0x7ebc6d, 3.35214901e+000f, 3.50090377e-002f, 1.17824704e-003f},
+  {0x7ec091, 3.31904745e+000f, 3.61872837e-002f, 1.18999800e-003f},
+  {0x7ec481, 3.28669214e+000f, 3.73772830e-002f, 1.20171276e-003f},
+  {0x7ec841, 3.25504732e+000f, 3.85789946e-002f, 1.21339550e-003f},
+  {0x7ecbd3, 3.22407961e+000f, 3.97923924e-002f, 1.22505031e-003f},
+  {0x7ecf3b, 3.19375801e+000f, 4.10174429e-002f, 1.23668101e-003f},
+  {0x7ed27b, 3.16405344e+000f, 4.22541238e-002f, 1.24829111e-003f},
+  {0x7ed595, 3.13493896e+000f, 4.35024127e-002f, 1.25988421e-003f},
+  {0x7ed88c, 3.10638905e+000f, 4.47622985e-002f, 1.27146335e-003f},
+  {0x7edb61, 3.07838011e+000f, 4.60337624e-002f, 1.28303189e-003f},
+  {0x7ede16, 3.05088997e+000f, 4.73167934e-002f, 1.29459263e-003f},
+  {0x7ee0ae, 3.02389741e+000f, 4.86113839e-002f, 1.30614871e-003f},
+  {0x7ee329, 2.99738288e+000f, 4.99175340e-002f, 1.31770282e-003f},
+  {0x7ee589, 2.97132778e+000f, 5.12352362e-002f, 1.32925750e-003f},
+  {0x7ee7cf, 2.94571447e+000f, 5.25644943e-002f, 1.34081556e-003f},
+  {0x7ee9fd, 2.92052627e+000f, 5.39053120e-002f, 1.35237945e-003f},
+  {0x7eec13, 2.89574766e+000f, 5.52576892e-002f, 1.36395160e-003f},
+  {0x7eee14, 2.87136412e+000f, 5.66216409e-002f, 1.37553434e-003f},
+  {0x7eefff, 2.84736085e+000f, 5.79971746e-002f, 1.38713000e-003f},
+  {0x7ef1d6, 2.82372522e+000f, 5.93843050e-002f, 1.39874080e-003f},
+  {0x7ef39a, 2.80044436e+000f, 6.07830472e-002f, 1.41036895e-003f},
+  {0x7ef54b, 2.77750611e+000f, 6.21934161e-002f, 1.42201665e-003f},
+  {0x7ef6ea, 2.75489926e+000f, 6.36154339e-002f, 1.43368577e-003f},
+  {0x7ef878, 2.73261261e+000f, 6.50491193e-002f, 1.44537864e-003f},
+  {0x7ef9f6, 2.71063614e+000f, 6.64944947e-002f, 1.45709701e-003f},
+  {0x7efb64, 2.68895960e+000f, 6.79515898e-002f, 1.46884308e-003f},
+  {0x7efcc3, 2.66757393e+000f, 6.94204345e-002f, 1.48061861e-003f},
+  {0x7efe13, 2.64647007e+000f, 7.09010586e-002f, 1.49242568e-003f},
+  {0x7eff56, 2.62563896e+000f, 7.23934844e-002f, 1.50426617e-003f},
+  {0x7f008b, 2.60507298e+000f, 7.38977492e-002f, 1.51614170e-003f},
+  {0x7f01b2, 2.58476377e+000f, 7.54138902e-002f, 1.52805448e-003f},
+  {0x7f02cd, 2.56470418e+000f, 7.69419447e-002f, 1.54000602e-003f},
+  {0x7f03dc, 2.54488659e+000f, 7.84819499e-002f, 1.55199831e-003f},
+  {0x7f04df, 2.52530432e+000f, 8.00339505e-002f, 1.56403321e-003f},
+  {0x7f05d6, 2.50595069e+000f, 8.15979838e-002f, 1.57611235e-003f},
+  {0x7f06c2, 2.48681927e+000f, 8.31740946e-002f, 1.58823747e-003f},
+  {0x7f07a4, 2.46790409e+000f, 8.47623274e-002f, 1.60041056e-003f},
+  {0x7f087b, 2.44919896e+000f, 8.63627419e-002f, 1.61263335e-003f},
+  {0x7f0947, 2.43069839e+000f, 8.79753754e-002f, 1.62490748e-003f},
+  {0x7f0a0a, 2.41239691e+000f, 8.96002799e-002f, 1.63723470e-003f},
+  {0x7f0ac3, 2.39428902e+000f, 9.12375152e-002f, 1.64961687e-003f},
+  {0x7f0b73, 2.37637019e+000f, 9.28871334e-002f, 1.66205585e-003f},
+  {0x7f0c19, 2.35863495e+000f, 9.45491865e-002f, 1.67455315e-003f},
+  {0x7f0cb7, 2.34107924e+000f, 9.62237418e-002f, 1.68711075e-003f},
+  {0x7f0d4c, 2.32369781e+000f, 9.79108512e-002f, 1.69973040e-003f},
+  {0x7f0dd8, 2.30648685e+000f, 9.96105820e-002f, 1.71241374e-003f},
+  {0x7f0e5c, 2.28944182e+000f, 1.01323001e-001f, 1.72516273e-003f},
+  {0x7f0ed7, 2.27255893e+000f, 1.03048161e-001f, 1.73797912e-003f},
+  {0x7f0f4b, 2.25583386e+000f, 1.04786143e-001f, 1.75086479e-003f},
+  {0x7f0fb7, 2.23926282e+000f, 1.06537007e-001f, 1.76382135e-003f},
+  {0x7f101b, 2.22284245e+000f, 1.08300827e-001f, 1.77685090e-003f},
+  {0x7f1077, 2.20656896e+000f, 1.10077679e-001f, 1.78995531e-003f},
+  {0x7f10cc, 2.19043899e+000f, 1.11867629e-001f, 1.80313620e-003f},
+  {0x7f111a, 2.17444897e+000f, 1.13670766e-001f, 1.81639567e-003f},
+  {0x7f1160, 2.15859580e+000f, 1.15487166e-001f, 1.82973559e-003f},
+  {0x7f119f, 2.14287639e+000f, 1.17316902e-001f, 1.84315792e-003f},
+  {0x7f11d8, 2.12728763e+000f, 1.19160056e-001f, 1.85666466e-003f},
+  {0x7f1209, 2.11182666e+000f, 1.21016718e-001f, 1.87025766e-003f},
+  {0x7f1233, 2.09649014e+000f, 1.22886978e-001f, 1.88393902e-003f},
+  {0x7f1257, 2.08127594e+000f, 1.24770917e-001f, 1.89771084e-003f},
+  {0x7f1274, 2.06618071e+000f, 1.26668632e-001f, 1.91157509e-003f},
+  {0x7f128b, 2.05120230e+000f, 1.28580198e-001f, 1.92553387e-003f},
+  {0x7f129b, 2.03633809e+000f, 1.30505741e-001f, 1.93958939e-003f},
+  {0x7f12a4, 2.02158523e+000f, 1.32445320e-001f, 1.95374386e-003f},
+  {0x7f12a7, 2.00694180e+000f, 1.34399071e-001f, 1.96799915e-003f},
+  {0x7f12a4, 1.99240494e+000f, 1.36367068e-001f, 1.98235805e-003f},
+  {0x7f129a, 1.97797275e+000f, 1.38349429e-001f, 1.99682219e-003f},
+  {0x7f128a, 1.96364272e+000f, 1.40346244e-001f, 2.01139436e-003f},
+  {0x7f1274, 1.94941270e+000f, 1.42357647e-001f, 2.02607666e-003f},
+  {0x7f1258, 1.93528080e+000f, 1.44383729e-001f, 2.04087165e-003f},
+  {0x7f1235, 1.92124474e+000f, 1.46424592e-001f, 2.05578166e-003f},
+  {0x7f120c, 1.90730250e+000f, 1.48480371e-001f, 2.07080925e-003f},
+  {0x7f11dd, 1.89345217e+000f, 1.50551185e-001f, 2.08595698e-003f},
+  {0x7f11a8, 1.87969184e+000f, 1.52637139e-001f, 2.10122741e-003f},
+  {0x7f116d, 1.86601949e+000f, 1.54738367e-001f, 2.11662287e-003f},
+  {0x7f112b, 1.85243356e+000f, 1.56854987e-001f, 2.13214662e-003f},
+  {0x7f10e4, 1.83893192e+000f, 1.58987135e-001f, 2.14780099e-003f},
+  {0x7f1096, 1.82551312e+000f, 1.61134943e-001f, 2.16358877e-003f},
+  {0x7f1042, 1.81217527e+000f, 1.63298532e-001f, 2.17951322e-003f},
+  {0x7f0fe8, 1.79891682e+000f, 1.65478036e-001f, 2.19557667e-003f},
+  {0x7f0f88, 1.78573596e+000f, 1.67673618e-001f, 2.21178262e-003f},
+  {0x7f0f21, 1.77263117e+000f, 1.69885397e-001f, 2.22813408e-003f},
+  {0x7f0eb4, 1.75960088e+000f, 1.72113538e-001f, 2.24463386e-003f},
+  {0x7f0e41, 1.74664366e+000f, 1.74358174e-001f, 2.26128544e-003f},
+  {0x7f0dc8, 1.73375785e+000f, 1.76619455e-001f, 2.27809208e-003f},
+  {0x7f0d48, 1.72094202e+000f, 1.78897545e-001f, 2.29505682e-003f},
+  {0x7f0cc2, 1.70819473e+000f, 1.81192607e-001f, 2.31218361e-003f},
+  {0x7f0c36, 1.69551456e+000f, 1.83504790e-001f, 2.32947571e-003f},
+  {0x7f0ba3, 1.68290007e+000f, 1.85834259e-001f, 2.34693661e-003f},
+  {0x7f0b09, 1.67034996e+000f, 1.88181207e-001f, 2.36457027e-003f},
+  {0x7f0a69, 1.65786290e+000f, 1.90545768e-001f, 2.38238042e-003f},
+  {0x7f09c2, 1.64543748e+000f, 1.92928150e-001f, 2.40037078e-003f},
+  {0x7f0914, 1.63307238e+000f, 1.95328519e-001f, 2.41854554e-003f},
+  {0x7f0860, 1.62076652e+000f, 1.97747067e-001f, 2.43690866e-003f},
+  {0x7f07a4, 1.60851848e+000f, 2.00183973e-001f, 2.45546433e-003f},
+  {0x7f06e2, 1.59632707e+000f, 2.02639446e-001f, 2.47421721e-003f},
+  {0x7f0618, 1.58419108e+000f, 2.05113649e-001f, 2.49317149e-003f},
+  {0x7f0548, 1.57210922e+000f, 2.07606822e-001f, 2.51233159e-003f},
+  {0x7f0470, 1.56008053e+000f, 2.10119158e-001f, 2.53170263e-003f},
+  {0x7f0391, 1.54810357e+000f, 2.12650865e-001f, 2.55128904e-003f},
+  {0x7f02aa, 1.53617740e+000f, 2.15202153e-001f, 2.57109618e-003f},
+  {0x7f01bb, 1.52430093e+000f, 2.17773244e-001f, 2.59112869e-003f},
+  {0x7f00c5, 1.51247287e+000f, 2.20364377e-001f, 2.61139218e-003f},
+  {0x7effc7, 1.50069213e+000f, 2.22975761e-001f, 2.63189198e-003f},
+  {0x7efec1, 1.48895776e+000f, 2.25607663e-001f, 2.65263370e-003f},
+  {0x7efdb2, 1.47726870e+000f, 2.28260294e-001f, 2.67362315e-003f},
+  {0x7efc9c, 1.46562374e+000f, 2.30933920e-001f, 2.69486615e-003f},
+  {0x7efb7d, 1.45402181e+000f, 2.33628780e-001f, 2.71636900e-003f},
+  {0x7efa55, 1.44246209e+000f, 2.36345157e-001f, 2.73813773e-003f},
+  {0x7ef924, 1.43094325e+000f, 2.39083290e-001f, 2.76017911e-003f},
+  {0x7ef7eb, 1.41946459e+000f, 2.41843462e-001f, 2.78249965e-003f},
+  {0x7ef6a8, 1.40802491e+000f, 2.44625971e-001f, 2.80510657e-003f},
+  {0x7ef55c, 1.39662325e+000f, 2.47431070e-001f, 2.82800663e-003f},
+  {0x7ef406, 1.38525856e+000f, 2.50259072e-001f, 2.85120774e-003f},
+  {0x7ef2a7, 1.37392998e+000f, 2.53110290e-001f, 2.87471712e-003f},
+  {0x7ef13d, 1.36263645e+000f, 2.55985022e-001f, 2.89854268e-003f},
+  {0x7eefc9, 1.35137689e+000f, 2.58883536e-001f, 2.92269303e-003f},
+  {0x7eee4a, 1.34015059e+000f, 2.61806250e-001f, 2.94717611e-003f},
+  {0x7eecc1, 1.32895637e+000f, 2.64753431e-001f, 2.97200121e-003f},
+  {0x7eeb2d, 1.31779337e+000f, 2.67725408e-001f, 2.99717695e-003f},
+  {0x7ee98d, 1.30666065e+000f, 2.70722598e-001f, 3.02271289e-003f},
+  {0x7ee7e2, 1.29555714e+000f, 2.73745298e-001f, 3.04861879e-003f},
+  {0x7ee62a, 1.28448200e+000f, 2.76793927e-001f, 3.07490490e-003f},
+  {0x7ee466, 1.27343428e+000f, 2.79868841e-001f, 3.10158124e-003f},
+  {0x7ee296, 1.26241291e+000f, 2.82970428e-001f, 3.12865921e-003f},
+  {0x7ee0b8, 1.25141716e+000f, 2.86099076e-001f, 3.15614976e-003f},
+  {0x7edece, 1.24044585e+000f, 2.89255232e-001f, 3.18406476e-003f},
+  {0x7edcd5, 1.22949815e+000f, 2.92439282e-001f, 3.21241608e-003f},
+  {0x7edace, 1.21857321e+000f, 2.95651704e-001f, 3.24121676e-003f},
+  {0x7ed8b9, 1.20766985e+000f, 2.98892915e-001f, 3.27047962e-003f},
+  {0x7ed694, 1.19678736e+000f, 3.02163392e-001f, 3.30021861e-003f},
+  {0x7ed460, 1.18592465e+000f, 3.05463612e-001f, 3.33044771e-003f},
+  {0x7ed21c, 1.17508066e+000f, 3.08794081e-001f, 3.36118182e-003f},
+  {0x7ecfc7, 1.16425467e+000f, 3.12155247e-001f, 3.39243654e-003f},
+  {0x7ecd61, 1.15344548e+000f, 3.15547675e-001f, 3.42422770e-003f},
+  {0x7ecae9, 1.14265227e+000f, 3.18971902e-001f, 3.45657207e-003f},
+  {0x7ec85e, 1.13187397e+000f, 3.22428495e-001f, 3.48948734e-003f},
+  {0x7ec5c1, 1.12110960e+000f, 3.25917959e-001f, 3.52299190e-003f},
+  {0x7ec310, 1.11035812e+000f, 3.29440951e-001f, 3.55710438e-003f},
+  {0x7ec04b, 1.09961855e+000f, 3.32998067e-001f, 3.59184528e-003f},
+  {0x7ebd71, 1.08888996e+000f, 3.36589903e-001f, 3.62723507e-003f},
+  {0x7eba80, 1.07817113e+000f, 3.40217143e-001f, 3.66329565e-003f},
+  {0x7eb779, 1.06746125e+000f, 3.43880445e-001f, 3.70004983e-003f},
+  {0x7eb45a, 1.05675900e+000f, 3.47580492e-001f, 3.73752182e-003f},
+  {0x7eb123, 1.04606342e+000f, 3.51318002e-001f, 3.77573632e-003f},
+  {0x7eadd1, 1.03537345e+000f, 3.55093747e-001f, 3.81472008e-003f},
+  {0x7eaa66, 1.02468789e+000f, 3.58908474e-001f, 3.85450036e-003f},
+  {0x7ea6de, 1.01400566e+000f, 3.62762988e-001f, 3.89510649e-003f},
+  {0x7ea33a, 1.00332558e+000f, 3.66658092e-001f, 3.93656874e-003f},
+  {0x7e9f77, 9.92646396e-001f, 3.70594651e-001f, 3.97891924e-003f},
+  {0x7e9b95, 9.81967032e-001f, 3.74573559e-001f, 4.02219174e-003f},
+  {0x7e9793, 9.71286237e-001f, 3.78595769e-001f, 4.06642212e-003f},
+  {0x7e936d, 9.60602701e-001f, 3.82662177e-001f, 4.11164761e-003f},
+  {0x7e8f24, 9.49915171e-001f, 3.86773825e-001f, 4.15790780e-003f},
+  {0x7e8ab6, 9.39222336e-001f, 3.90931726e-001f, 4.20524506e-003f},
+  {0x7e8620, 9.28522766e-001f, 3.95136982e-001f, 4.25370270e-003f},
+  {0x7e8160, 9.17815208e-001f, 3.99390697e-001f, 4.30332823e-003f},
+  {0x7e7c76, 9.07098055e-001f, 4.03694004e-001f, 4.35417052e-003f},
+  {0x7e775d, 8.96369994e-001f, 4.08048183e-001f, 4.40628268e-003f},
+  {0x7e7215, 8.85629475e-001f, 4.12454456e-001f, 4.45972057e-003f},
+  {0x7e6c9b, 8.74874890e-001f, 4.16914195e-001f, 4.51454241e-003f},
+  {0x7e66ec, 8.64104629e-001f, 4.21428740e-001f, 4.57081199e-003f},
+  {0x7e6104, 8.53317022e-001f, 4.25999552e-001f, 4.62859636e-003f},
+  {0x7e5ae2, 8.42510343e-001f, 4.30628151e-001f, 4.68796585e-003f},
+  {0x7e5481, 8.31682861e-001f, 4.35316116e-001f, 4.74899774e-003f},
+  {0x7e4ddf, 8.20832610e-001f, 4.40065116e-001f, 4.81177261e-003f},
+  {0x7e46f6, 8.09957743e-001f, 4.44876879e-001f, 4.87637753e-003f},
+  {0x7e3fc4, 7.99056172e-001f, 4.49753255e-001f, 4.94290609e-003f},
+  {0x7e3843, 7.88125873e-001f, 4.54696149e-001f, 5.01145795e-003f},
+  {0x7e306f, 7.77164638e-001f, 4.59707618e-001f, 5.08214068e-003f},
+  {0x7e2842, 7.66170084e-001f, 4.64789748e-001f, 5.15506882e-003f},
+  {0x7e1fb6, 7.55140007e-001f, 4.69944835e-001f, 5.23036765e-003f},
+  {0x7e16c6, 7.44071722e-001f, 4.75175202e-001f, 5.30817080e-003f},
+  {0x7e0d69, 7.32962668e-001f, 4.80483353e-001f, 5.38862357e-003f},
+  {0x7e0399, 7.21810102e-001f, 4.85872000e-001f, 5.47188241e-003f},
+  {0x7df94d, 7.10611045e-001f, 4.91343856e-001f, 5.55811776e-003f},
+  {0x7dee7c, 6.99362457e-001f, 4.96901989e-001f, 5.64751448e-003f},
+  {0x7de31c, 6.88061118e-001f, 5.02549529e-001f, 5.74027468e-003f},
+  {0x7dd722, 6.76703572e-001f, 5.08289754e-001f, 5.83661720e-003f},
+  {0x7dca82, 6.65286124e-001f, 5.14126420e-001f, 5.93678374e-003f},
+  {0x7dbd2d, 6.53804958e-001f, 5.20063162e-001f, 6.04103645e-003f},
+  {0x7daf15, 6.42255962e-001f, 5.26104212e-001f, 6.14966638e-003f},
+  {0x7da028, 6.30634665e-001f, 5.32253861e-001f, 6.26299158e-003f},
+  {0x7d9053, 6.18936479e-001f, 5.38516879e-001f, 6.38136547e-003f},
+  {0x7d7f82, 6.07156217e-001f, 5.44898212e-001f, 6.50517875e-003f},
+  {0x7d6d9b, 5.95288575e-001f, 5.51403403e-001f, 6.63486589e-003f},
+  {0x7d5a84, 5.83327711e-001f, 5.58038294e-001f, 6.77091070e-003f},
+  {0x7d461d, 5.71267307e-001f, 5.64809203e-001f, 6.91385567e-003f},
+  {0x7d3043, 5.59100568e-001f, 5.71723044e-001f, 7.06430990e-003f},
+  {0x7d18cd, 5.46820104e-001f, 5.78787386e-001f, 7.22295977e-003f},
+  {0x7cff8c, 5.34417868e-001f, 5.86010337e-001f, 7.39058340e-003f},
+  {0x7ce449, 5.21885037e-001f, 5.93400896e-001f, 7.56806461e-003f},
+  {0x7cc6c6, 5.09211957e-001f, 6.00968957e-001f, 7.75641575e-003f},
+  {0x7ca6b8, 4.96388048e-001f, 6.08725369e-001f, 7.95679912e-003f},
+  {0x7c83c8, 4.83401477e-001f, 6.16682172e-001f, 8.17055814e-003f},
+  {0x7c5d8e, 4.70239282e-001f, 6.24852717e-001f, 8.39925557e-003f},
+  {0x7c338c, 4.56886828e-001f, 6.33251965e-001f, 8.64472240e-003f},
+  {0x7c052e, 4.43327874e-001f, 6.41896725e-001f, 8.90911743e-003f},
+  {0x7bd1bb, 4.29543942e-001f, 6.50805831e-001f, 9.19500738e-003f},
+  {0x7b9853, 4.15514171e-001f, 6.60000861e-001f, 9.50547587e-003f},
+  {0x7b57dc, 4.01214689e-001f, 6.69506311e-001f, 9.84425563e-003f},
+  {0x7b0ef4, 3.86617988e-001f, 6.79350555e-001f, 1.02159241e-002f},
+  {0x7abbd7, 3.71692151e-001f, 6.89566493e-001f, 1.06261587e-002f},
+  {0x7a5c37, 3.56399775e-001f, 7.00192630e-001f, 1.10821053e-002f},
+  {0x79ed08, 3.40696484e-001f, 7.11274743e-001f, 1.15928985e-002f},
+  {0x796a2c, 3.24529111e-001f, 7.22867668e-001f, 1.21704331e-002f},
+  {0x78cdee, 3.07832956e-001f, 7.35038102e-001f, 1.28305294e-002f},
+  {0x781027, 2.90527970e-001f, 7.47868598e-001f, 1.35947671e-002f},
+  {0x7724d3, 2.72513181e-001f, 7.61463404e-001f, 1.44934636e-002f},
+  {0x75f96f, 2.53658354e-001f, 7.75956869e-001f, 1.55707849e-002f},
+  {0x746ff9, 2.33790487e-001f, 7.91527629e-001f, 1.68940146e-002f},
+  {0x725474, 2.12671503e-001f, 8.08421671e-001f, 1.85716450e-002f},
+  {0x6f44a0, 1.89958692e-001f, 8.26993287e-001f, 2.07922049e-002f},
+  {0x6a6edd, 1.65127620e-001f, 8.47785473e-001f, 2.39188317e-002f},
+  {0x61bbd6, 1.37304977e-001f, 8.71704340e-001f, 2.87655983e-002f},
+  {0x4df56f, 1.04838505e-001f, 9.00469959e-001f, 3.76737528e-002f},
+  {0x0, 6.38521612e-002f, 9.38143671e-001f, 6.18563183e-002f}};
+
+const CZigguratExponential_FP64::TBinData CZigguratExponential_FP64::Bins[CZigguratExponential_FP64::NumBins] = {
+  {UINT64_C(0xdf9688bda95ce), 7.89831511661564360e+000, 0, 0},
+  {UINT64_C(0xe3ae1dd040148), 6.89831511661564270e+000, 1.00948486124341270e-003, 1.15582274870986290e-003},
+  {UINT64_C(0xec622f1fa45a8), 6.13519284450123870e+000, 2.16530760995327540e-003, 1.29958906616922730e-003},
+  {UINT64_C(0xf0986fbcf7b9d), 5.66507246608574010e+000, 3.46489667612250290e-003, 1.40743646039581260e-003},
+  {UINT64_C(0xf31d0df9c0ba1), 5.32418237313749910e+000, 4.87233313651831530e-003, 1.49755004257206310e-003},
+  {UINT64_C(0xf4cd07fce550a), 5.05617414879851080e+000, 6.36988317909037770e-003, 1.57692937484128270e-003},
+  {UINT64_C(0xf6041c9638b3e), 4.83498436732483940e+000, 7.94681255393166020e-003, 1.64907038654294920e-003},
+  {UINT64_C(0xf6ef857588626), 4.64642113286248290e+000, 9.59588294047461140e-003, 1.71599373185561590e-003},
+  {UINT64_C(0xf7a83deabe527), 4.48190207226268540e+000, 1.13118766723302260e-002, 1.77898343404192480e-003},
+  {UINT64_C(0xf83d3ed29599f), 4.33584099408585730e+000, 1.30908601063721520e-002, 1.83891188593610260e-003},
+  {UINT64_C(0xf8b8130bfc254), 4.20439793932874740e+000, 1.49297719923082530e-002, 1.89640220897512230e-003},
+  {UINT64_C(0xf91f1c567ee1c), 4.08481961680575440e+000, 1.68261742012833780e-002, 1.95191716832489970e-003},
+  {UINT64_C(0xf976ca7a48218), 3.97506444137807560e+000, 1.87780913696082750e-002, 2.00581139177440130e-003},
+  {UINT64_C(0xf9c24ca169e08), 3.87357649759723400e+000, 2.07839027613826760e-002, 2.05836377427921120e-003},
+  {UINT64_C(0xfa03fbabd9d1b), 3.77914266375610140e+000, 2.28422665356618860e-002, 2.10979850430649630e-003},
+  {UINT64_C(0xfa3d9cac6f264), 3.69079869307661830e+000, 2.49520650399683820e-002, 2.16029922046685060e-003},
+  {UINT64_C(0xfa708bfdf3bd7), 3.60776540937242010e+000, 2.71123642604352360e-002, 2.21001884403023130e-003},
+  {UINT64_C(0xfa9dda0b0986d), 3.52940412612390550e+000, 2.93223831044654650e-002, 2.25908659213529170e-003},
+  {UINT64_C(0xfac65f0c34b84), 3.45518473239647680e+000, 3.15814696966007570e-002, 2.30761309657193020e-003},
+  {UINT64_C(0xfaeac8e3f5d2f), 3.38466235796156270e+000, 3.38890827931726880e-002, 2.35569421593810740e-003},
+  {UINT64_C(0xfb0ba50d2a39b), 3.31745999056962320e+000, 3.62447770091107940e-002, 2.40341392578014190e-003},
+  {UINT64_C(0xfb2967da3f4c6), 3.25325531138591820e+000, 3.86481909348909340e-002, 2.45084654488946860e-003},
+  {UINT64_C(0xfb4471d5357b1), 3.19177057673762210e+000, 4.10990374797804080e-002, 2.49805847502457440e-003},
+  {UINT64_C(0xfb5d13cb52430), 3.13276473738663300e+000, 4.35970959548049810e-002, 2.54510957825859450e-003},
+  {UINT64_C(0xfb7391e31b451), 3.07602722648897760e+000, 4.61422055330635780e-002, 2.59205428056443090e-003},
+  {UINT64_C(0xfb8825fe3adea), 3.02137300929172260e+000, 4.87342598136280000e-002, 2.63894246590314030e-003},
+  {UINT64_C(0xfb9b019596d34), 2.96863859890389170e+000, 5.13732022795311410e-002, 2.68582020812416870e-003},
+  {UINT64_C(0xfbac4f30bc228), 2.91767882028667460e+000, 5.40590224876553100e-002, 2.73273037598089230e-003},
+  {UINT64_C(0xfbbc3390ae103), 2.86836415985974290e+000, 5.67917528636362050e-002, 2.77971313793830280e-003},
+  {UINT64_C(0xfbcace9fc7b92), 2.82057857791505380e+000, 5.95714660015745080e-002, 2.82680638716586650e-003},
+  {UINT64_C(0xfbd83c33d7f71), 2.77421769006790030e+000, 6.23982723887403780e-002, 2.87404610247379020e-003},
+  {UINT64_C(0xfbe494ac5c145), 2.72918724542131490e+000, 6.52723184912141620e-002, 2.92146665749298300e-003},
+  {UINT64_C(0xfbefed745d03c), 2.68540184513682600e+000, 6.81937851487071510e-002, 2.96910108779166370e-003},
+  {UINT64_C(0xfbfa596db2206), 2.64278385719113860e+000, 7.11628862364988150e-002, 3.01698132363642210e-003},
+  {UINT64_C(0xfc03e94a1e604), 2.60126249230736000e+000, 7.41798675601352260e-002, 3.06513839458051520e-003},
+  {UINT64_C(0xfc0cabd5c1b9f), 2.56077301312943820e+000, 7.72450059547157420e-002, 3.11360261088102550e-003},
+  {UINT64_C(0xfc14ae3599ebe), 2.52125605419779400e+000, 8.03586085655967760e-002, 3.16240372582482060e-003},
+  {UINT64_C(0xfc1bfc1c3c0c0), 2.48265703457377860e+000, 8.35210122914215870e-002, 3.21157108231920210e-003},
+  {UINT64_C(0xfc229ff67fd7c), 2.44492564833780920e+000, 8.67325833737407900e-002, 3.26113374653094930e-003},
+  {UINT64_C(0xfc28a3117e5b9), 2.40801542086344610e+000, 8.99937171202717380e-002, 3.31112063090298470e-003},
+  {UINT64_C(0xfc2e0dbb012bf), 2.37188332090636770e+000, 9.33048377511747350e-002, 3.36156060851538040e-003},
+  {UINT64_C(0xfc32e75d49877), 2.33648942026299180e+000, 9.66663983596901120e-002, 3.41248262046743400e-003},
+  {UINT64_C(0xfc373696ec00a), 2.30179659413941360e+000, 1.00078880980157530e-001, 3.46391577772513310e-003},
+  {UINT64_C(0xfc3b014f5b379), 2.26777025649706990e+000, 1.03542796757882680e-001, 3.51588945869208290e-003},
+  {UINT64_C(0xfc3e4cc8a0cc8), 2.23437812556076800e+000, 1.07058686216574760e-001, 3.56843340361310880e-003},
+  {UINT64_C(0xfc411daead9e7), 2.20159001542912370e+000, 1.10627119620187880e-001, 3.62157780680131970e-003},
+  {UINT64_C(0xfc4378249879d), 2.16937765034949680e+000, 1.14248697426989200e-001, 3.67535340758625650e-003},
+  {UINT64_C(0xfc455fd013b6b), 2.13771449873480890e+000, 1.17924050834575440e-001, 3.72979158080856410e-003},
+  {UINT64_C(0xfc46d7e35643b), 2.10657562442829520e+000, 1.21653842415384000e-001, 3.78492442763233390e-003},
+  {UINT64_C(0xfc47e325aab2d), 2.07593755308033500e+000, 1.25438766843016330e-001, 3.84078486740730040e-003},
+  {UINT64_C(0xfc4883face9e4), 2.04577815180181450e+000, 1.29279551710423660e-001, 3.89740673128759640e-003},
+  {UINT64_C(0xfc48bc6945e5d), 2.01607652051125990e+000, 1.33176958441711240e-001, 3.95482485830029280e-003},
+  {UINT64_C(0xfc488e1fbf79e), 1.98681289360651370e+000, 1.37131783300011550e-001, 4.01307519455457090e-003},
+  {UINT64_C(0xfc47fa79a48e9), 1.95796855077274130e+000, 1.41144858494566120e-001, 4.07219489629020730e-003},
+  {UINT64_C(0xfc470282e6ea1), 1.92952573589244110e+000, 1.45217053390856330e-001, 4.13222243748188460e-003},
+  {UINT64_C(0xfc45a6fb1f6eb), 1.90146758315441720e+000, 1.49349275828338210e-001, 4.19319772274339560e-003},
+  {UINT64_C(0xfc43e8580aefa), 1.87377804957094020e+000, 1.53542473551081610e-001, 4.25516220631318080e-003},
+  {UINT64_C(0xfc41c6c770a2f), 1.84644185320861750e+000, 1.57797635757394750e-001, 4.31815901795021010e-003},
+  {UINT64_C(0xfc3f42307b264), 1.81944441652128620e+000, 1.62115794775344990e-001, 4.38223309662738940e-003},
+  {UINT64_C(0xfc3c5a348ad9d), 1.79277181424456500e+000, 1.66498027871972380e-001, 4.44743133297933680e-003},
+  {UINT64_C(0xfc390e2f8661f), 1.76641072537331660e+000, 1.70945459204951720e-001, 4.51380272154337790e-003},
+  {UINT64_C(0xfc355d37ac44a), 1.74034838879653100e+000, 1.75459261926495080e-001, 4.58139852392833950e-003},
+  {UINT64_C(0xfc31461ce6dba), 1.71457256221030410e+000, 1.80040660450423410e-001, 4.65027244415656180e-003},
+  {UINT64_C(0xfc2cc767a2205), 1.68907148396960040e+000, 1.84690932894579970e-001, 4.72048081755253260e-003},
+  {UINT64_C(0xfc27df5721292), 1.66383383757420830e+000, 1.89411413712132520e-001, 4.79208281469866230e-003},
+  {UINT64_C(0xfc228bdf4f7c8), 1.63884871851443630e+000, 1.94203496526831190e-001, 4.86514066214785610e-003},
+  {UINT64_C(0xfc1ccaa6089b0), 1.61410560322821440e+000, 1.99068637188979020e-001, 4.93971988177664080e-003},
+  {UINT64_C(0xfc1698ffce480), 1.58959431994388960e+000, 2.04008357070755680e-001, 5.01588955088549510e-003},
+  {UINT64_C(0xfc0ff3ebe4175), 1.56530502120252320e+000, 2.09024246621641180e-001, 5.09372258540905390e-003},
+  {UINT64_C(0xfc08d80fc49ee), 1.54122815787027710e+000, 2.14117969207050230e-001, 5.17329604889335550e-003},
+  {UINT64_C(0xfc0141b1e23f7), 1.51735445446579090e+000, 2.19291265255943580e-001, 5.25469149023627060e-003},
+  {UINT64_C(0xfbf92cb3a2c8e), 1.49367488563953700e+000, 2.24545956746179860e-001, 5.33799531357832550e-003},
+  {UINT64_C(0xfbf0948a8235a), 1.47018065365220570e+000, 2.29883952059758170e-001, 5.42329918418290020e-003},
+  {UINT64_C(0xfbe77438453c7), 1.44686316670733060e+000, 2.35307251243941060e-001, 5.51070047466783230e-003},
+  {UINT64_C(0xfbddc642207f1), 1.42371401799975960e+000, 2.40817951718608920e-001, 5.60030275655741710e-003},
+  {UINT64_C(0xfbd384a6b47ac), 1.40072496534626720e+000, 2.46418254475166330e-001, 5.69221634282963090e-003},
+  {UINT64_C(0xfbc8a8d2b9055), 1.37788791126762610e+000, 2.52110470817995980e-001, 5.78655888795649290e-003},
+  {UINT64_C(0xfbbd2b942cd1d), 1.35519488339283130e+000, 2.57897029705952460e-001, 5.88345605289765890e-003},
+  {UINT64_C(0xfbb1050bd61b2), 1.33263801505584100e+000, 2.63780485758850100e-001, 5.98304224363537410e-003},
+  {UINT64_C(0xfba42c9cd8d17), 1.31020952595313790e+000, 2.69763528002485490e-001, 6.08546143316520720e-003},
+  {UINT64_C(0xfb9698da1c50e), 1.28790170272645010e+000, 2.75848989435650730e-001, 6.19086807842119960e-003},
+  {UINT64_C(0xfb883f712e4df), 1.26570687932901430e+000, 2.82039857514071900e-001, 6.29942814546470470e-003},
+  {UINT64_C(0xfb79151241e2e), 1.24361741702554250e+000, 2.88339285659536590e-001, 6.41132025846316050e-003},
+  {UINT64_C(0xfb690d54d7ebc), 1.22162568386532850e+000, 2.94750605917999730e-001, 6.52673699060215150e-003},
+  {UINT64_C(0xfb581a9888793), 1.19972403345431930e+000, 3.01277342908601920e-001, 6.64588631820309250e-003},
+  {UINT64_C(0xfb462de14b349), 1.17790478283506840e+000, 3.07923229226805040e-001, 6.76899326307422830e-003},
+  {UINT64_C(0xfb3336ae7cff8), 1.15616018926267890e+000, 3.14692222489879270e-001, 6.89630175264750990e-003},
+  {UINT64_C(0xfb1f22cbba83f), 1.13448242563946720e+000, 3.21588524242526760e-001, 7.02807673292890710e-003},
+  {UINT64_C(0xfb09de1a78032), 1.11286355434023990e+000, 3.28616600975455640e-001, 7.16460657594309660e-003},
+  {UINT64_C(0xfaf352530427d), 1.09129549912268640e+000, 3.35781207551398730e-001, 7.30620583147582190e-003},
+  {UINT64_C(0xfadb66bb5b083), 1.06977001477206410e+000, 3.43087413382874570e-001, 7.45321838288049740e-003},
+  {UINT64_C(0xfac1ffd1d3e21), 1.04827865407435320e+000, 3.50540631765755060e-001, 7.60602107899829240e-003},
+  {UINT64_C(0xfaa6fee942756), 1.02681273164522140e+000, 3.58146652844753390e-001, 7.76502792946314610e-003},
+  {UINT64_C(0xfa8a41b395670), 1.00536328406062330e+000, 3.65911680774216540e-001, 7.93069496963319170e-003},
+  {UINT64_C(0xfa6ba1b744e76), 9.83921025635170590e-001, 3.73842375743849710e-001, 8.10352592516901290e-003},
+  {UINT64_C(0xfa4af3aafbf46), 9.62476299071922560e-001, 3.81945901669018710e-001, 8.28407883627031370e-003},
+  {UINT64_C(0xfa2806b1bac80), 9.41019020056089730e-001, 3.90229980505289010e-001, 8.47297383965548750e-003},
+  {UINT64_C(0xfa02a3702c5db), 9.19538614677599670e-001, 3.98702954344944520e-001, 8.67090235503485860e-003},
+  {UINT64_C(0xf9da8af1ed14a), 8.98023948333463220e-001, 4.07373856699979390e-001, 8.87863798549032820e-003},
+  {UINT64_C(0xf9af7552e35eb), 8.76463244467077240e-001, 4.16252494685469710e-001, 9.09704952248341530e-003},
+  {UINT64_C(0xf981101d522e1), 8.54843991130224020e-001, 4.25349544207953120e-001, 9.32711655259079420e-003},
+  {UINT64_C(0xf94efc48a3eb6), 8.33152832880709400e-001, 4.34676660760543900e-001, 9.56994830346462320e-003},
+  {UINT64_C(0xf918cbbe9c8e6), 8.11375444921901830e-001, 4.44246609064008540e-001, 9.82680655355665230e-003},
+  {UINT64_C(0xf8ddfe43fc48e), 7.89496385605450550e-001, 4.54073415617565150e-001, 1.00991336818330880e-002},
+  {UINT64_C(0xf89dfd95a2c92), 7.67498922393608280e-001, 4.64172549299398220e-001, 1.03885872760410940e-002},
+  {UINT64_C(0xf858187a78cc3), 7.45364825026504470e-001, 4.74561136575439410e-001, 1.06970831891214730e-002},
+  {UINT64_C(0xf80b7c728a3fd), 7.23074117839883180e-001, 4.85258219764560790e-001, 1.10268495896005400e-002},
+  {UINT64_C(0xf7b72d8957ded), 7.00604780753902530e-001, 4.96285069354161390e-001, 1.13804954784546360e-002},
+  {UINT64_C(0xf759fb9f0ef30), 6.77932385146246540e-001, 5.07665564832616050e-001, 1.17610984727237520e-002},
+  {UINT64_C(0xf6f274315eb5e), 6.55029646251399590e-001, 5.19426663305339710e-001, 1.21723185892159950e-002},
+  {UINT64_C(0xf67ecf3aeb50f), 6.31865867316897760e-001, 5.31598981894555790e-001, 1.26185476253217220e-002},
+  {UINT64_C(0xf5fcd51051c5e), 6.08406241612121760e-001, 5.44217529519877450e-001, 1.31051080581068030e-002},
+  {UINT64_C(0xf569ba0af05ef), 5.84610965138341210e-001, 5.57322637577984280e-001, 1.36385220514410300e-002},
+  {UINT64_C(0xf4c1eb0d23f12), 5.60434093304459480e-001, 5.70961159629425290e-001, 1.42268816883379390e-002},
+  {UINT64_C(0xf400c2f84ef38), 5.35822045250432090e-001, 5.85188041317763250e-001, 1.48803686041453710e-002},
+  {UINT64_C(0xf3201c17ff745), 5.10711613728867640e-001, 6.00068409921908570e-001, 1.56119996593349630e-002},
+  {UINT64_C(0xf217a773ccddd), 4.85027265694870590e-001, 6.15680409581243590e-001, 1.64387243841450930e-002},
+  {UINT64_C(0xf0dbe31ebf97d), 4.58677399489966220e-001, 6.32119133965388660e-001, 1.73830878705152070e-002},
+  {UINT64_C(0xef5c67c8061dd), 4.31549022036835210e-001, 6.49502221835903890e-001, 1.84758373496509250e-002},
+  {UINT64_C(0xed81024b4fe39), 4.03499951515524150e-001, 6.67978059185554860e-001, 1.97601747152793130e-002},
+  {UINT64_C(0xeb2479ca95862), 3.74346987428728790e-001, 6.87738233900834110e-001, 2.12990348722159740e-002},
+  {UINT64_C(0xe80a830ae6bb6), 3.43847188566281770e-001, 7.09037268773050070e-001, 2.31882935346918730e-002},
+  {UINT64_C(0xe3cac9d1f6974), 3.11666667258660050e-001, 7.32225562307742050e-001, 2.55825546237715110e-002},
+  {UINT64_C(0xdda058265f4b6), 2.77325069275912110e-001, 7.57808116931513510e-001, 2.87504824586228940e-002},
+  {UINT64_C(0xd3e7a257e0685), 2.40088052723822300e-001, 7.86558599390136390e-001, 3.32096055971816480e-002},
+  {UINT64_C(0xc2735d80dc305), 1.98733655529202440e-001, 8.19768204987318060e-001, 4.01201775226334640e-002},
+  {UINT64_C(0x9ae6fc6f3abd3), 1.50952685936872420e-001, 8.59888382509951480e-001, 5.28193949651737240e-002},
+  {UINT64_C(0x0), 9.13395181029036110e-002, 9.12707777475125210e-001, 8.72922225248747710e-002}};
diff --git a/xpdeint/includes/solirte/ziggurat.h b/xpdeint/includes/solirte/ziggurat.h
new file mode 100644
index 0000000..95cd357
--- /dev/null
+++ b/xpdeint/includes/solirte/ziggurat.h
@@ -0,0 +1,56 @@
+#ifndef ZIGGURAT_H
+#define ZIGGURAT_H
+
+class CZigguratGaussian_FP32
+{
+  public:
+    struct TBinData
+    {
+      uint32_t THold;
+      float XScale, YOffset, YScale;
+    };
+
+    static const int NumBins = 256;
+    static const TBinData Bins[NumBins];
+};
+
+class CZigguratGaussian_FP64
+{
+  public:
+    struct TBinData
+    {
+      uint64_t THold;
+      double XScale, YOffset, YScale;
+    };
+
+    static const int NumBins = 128;
+    static const TBinData Bins[NumBins];
+};
+
+class CZigguratExponential_FP32
+{
+  public:
+    struct TBinData
+    {
+      uint32_t THold;
+      float XScale, YOffset, YScale;
+    };
+
+    static const int NumBins = 256;
+    static const TBinData Bins[NumBins];
+};
+
+class CZigguratExponential_FP64
+{
+  public:
+    struct TBinData
+    {
+      uint64_t THold;
+      double XScale, YOffset, YScale;
+    };
+
+    static const int NumBins = 128;
+    static const TBinData Bins[NumBins];
+};
+
+#endif
diff --git a/xpdeint/includes/xpdeint.h b/xpdeint/includes/xpdeint.h
new file mode 100644
index 0000000..33d7715
--- /dev/null
+++ b/xpdeint/includes/xpdeint.h
@@ -0,0 +1,53 @@
+/*
+ * xpdeint.h
+ * Copyright (C) 2008-2012 Graham Dennis (graham.dennis at anu.edu.au) and Joe Hope. All rights reserved.
+ *
+*/
+
+#ifndef xpdeint_h
+#define xpdeint_h
+
+#ifndef _xmds_malloc
+  #define _xmds_malloc(n) _aligned_malloc(n, 16)
+#endif
+
+#ifndef xmds_free
+  #define xmds_free   _aligned_free
+#endif
+
+inline XMDSComplexType::value_type mod(const XMDSComplexType& _t) { return std::abs(_t); }
+inline XMDSComplexType::value_type mod2(const XMDSComplexType& _t) { return std::norm(_t); }
+inline XMDSComplexType cis(const real& _t) { return std::polar((real)1.0, _t); }
+
+namespace std {
+  inline complex<float> operator*(const complex<float>& a, const double b) { return a*float(b); }
+  inline complex<float> operator*(const double b, const complex<float>& a) { return a*float(b); }
+  inline complex<float> operator/(const complex<float>& a, const double b) { return a/float(b); }
+  inline complex<float> operator/(const double b, const complex<float>& a) { return float(b)/a; }
+  inline complex<float> operator+(const complex<float>& a, const double b) { return a + float(b); }
+  inline complex<float> operator+(const double b, const complex<float>& a) { return a + float(b); }
+  inline complex<float> operator-(const complex<float>& a, const double b) { return a - float(b); }
+  inline complex<float> operator-(const double b, const complex<float>& a) { return float(b) - a; }
+};
+
+inline XMDSComplexType operator*(const XMDSComplexType& a, const int b) { return a*XMDSComplexType::value_type(b); }
+inline XMDSComplexType operator*(const int b, const XMDSComplexType& a) { return a*XMDSComplexType::value_type(b); }
+inline XMDSComplexType operator/(const XMDSComplexType& a, const int b) { return a/XMDSComplexType::value_type(b); }
+inline XMDSComplexType operator/(const int b, const XMDSComplexType& a) { return XMDSComplexType::value_type(b)/a; }
+inline XMDSComplexType operator+(const XMDSComplexType& a, const int b) { return a + XMDSComplexType::value_type(b); }
+inline XMDSComplexType operator+(const int b, const XMDSComplexType& a) { return a + XMDSComplexType::value_type(b); }
+inline XMDSComplexType operator-(const XMDSComplexType& a, const int b) { return a - XMDSComplexType::value_type(b); }
+inline XMDSComplexType operator-(const int b, const XMDSComplexType& a) { return XMDSComplexType::value_type(b) - a; }
+
+
+extern bool initialiseFieldFromXSILFile(const char *filename,
+   const char *mgName, unsigned long dimension, char **dimNames,
+   char **componentNames,
+   // output variables
+   char**binaryDataFilename, int *unsignedLongSize,
+   bool *dataEncodingIsNative, bool *isPrecisionDouble,
+   unsigned long *nDataComponents, unsigned long **inputLattice,
+   int **componentIndicesPtr);
+
+#endif // xpdeint_h
+
diff --git a/xpdeint/includes/xpdeint_platform.h b/xpdeint/includes/xpdeint_platform.h
new file mode 100644
index 0000000..ee81980
--- /dev/null
+++ b/xpdeint/includes/xpdeint_platform.h
@@ -0,0 +1,754 @@
+/* *****************************************************************************
+/
+/ This file is a modified version of 'compilercompat.h' from Solirte.
+/ This file is part of Solirte, a solenoid ion ray-tracing engine.
+/ (c) 2008 Michael Brown.
+/ michael.brown at anu.edu.au
+/ Modified by Graham Dennis.
+/
+/ No platform is like any other. This file tries to get a (mostly) consistant
+/ environment across all supported platforms.
+/ *************************************************************************** */
+
+#ifndef XPDEINT_PLATFORM_H
+#define XPDEINT_PLATFORM_H
+
+// -----------------------------------------------------------------------------
+// Configuration constants.
+// -----------------------------------------------------------------------------
+
+#define CFG_COMPILER_MSVC 1
+#define CFG_COMPILER_SUNCC 2
+#define CFG_COMPILER_GCC 3
+#define CFG_COMPILER_ICC 4
+
+#define CFG_PLATFORM_WIN32 1
+#define CFG_PLATFORM_LINUX 2
+#define CFG_PLATFORM_SOLARIS 3
+#define CFG_PLATFORM_CYGWIN 4
+#define CFG_PLATFORM_OSX 5
+#define CFG_PLATFORM_FREEBSD 6
+
+#define CFG_ENDIAN_LITTLE 1234
+#define CFG_ENDIAN_BIG 4321
+
+#define CFG_OSAPI_WIN32 1
+#define CFG_OSAPI_POSIX 2
+
+#define CFG_THREADAPI_WIN32 1
+#define CFG_THREADAPI_PTHREADS 2
+
+// -----------------------------------------------------------------------------
+// External compiler- and system-specific options.
+// -----------------------------------------------------------------------------
+#ifndef CFG_HAVE_COMPILER_CONFIG_H
+  #define CFG_HAVE_COMPILER_CONFIG_H 0
+#endif
+
+#if CFG_HAVE_COMPILER_CONFIG_H == 1
+  #include "compiler_config.h"
+#endif
+
+// -----------------------------------------------------------------------------
+// Compiler identification.
+// -----------------------------------------------------------------------------
+
+#ifndef CFG_COMPILER
+  #if defined(_MSC_VER)
+    #define CFG_COMPILER CFG_COMPILER_MSVC
+  #endif
+
+  #if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+    #define CFG_COMPILER CFG_COMPILER_SUNCC
+  #endif
+
+  #if defined(__GNUC__) && !defined(__INTEL_COMPILER)
+    #define CFG_COMPILER CFG_COMPILER_GCC
+  #endif
+
+  #if defined(__INTEL_COMPILER)
+    #define CFG_COMPILER CFG_COMPILER_ICC
+  #endif
+
+  #ifndef CFG_COMPILER
+    #error Cannot detect compiler.
+  #endif
+#endif
+
+// -----------------------------------------------------------------------------
+// Platform identification.
+// -----------------------------------------------------------------------------
+
+#ifndef CFG_PLATFORM
+  #if defined(_WIN32)
+    #define CFG_PLATFORM CFG_PLATFORM_WIN32
+  #endif
+
+  #if defined(__linux__)
+    #define CFG_PLATFORM CFG_PLATFORM_LINUX
+  #endif
+
+  #if defined(__CYGWIN__)
+    #define CFG_PLATFORM CFG_PLATFORM_CYGWIN
+  #endif
+
+  #if defined(__SVR4) && defined(__sun)
+    #define CFG_PLATFORM CFG_PLATFORM_SOLARIS
+  #endif
+  
+  #if defined(__APPLE__)
+    #define CFG_PLATFORM CFG_PLATFORM_OSX
+  #endif
+  
+  #if defined(__FreeBSD__)
+    #define CFG_PLATFORM CFG_PLATFORM_FREEBSD
+  #endif
+
+  #ifndef CFG_PLATFORM
+    #error Cannot detect platform.
+  #endif
+#endif
+
+// -----------------------------------------------------------------------------
+// All the basic include files.
+// -----------------------------------------------------------------------------
+#if (CFG_PLATFORM == CFG_PLATFORM_LINUX) && (CFG_COMPILER == CFG_COMPILER_GCC)
+  #ifndef CFG_COMPILER 
+    #define _XOPEN_SOURCE 600
+  #endif
+#endif
+
+#if CFG_COMPILER == CFG_COMPILER_MSVC
+  // Stop MSVC from nerfing std::Vector performance.
+  #define _SECURE_SCL 0
+
+  // Needed for M_PI
+  #define _USE_MATH_DEFINES
+  #ifdef _DEBUG                   // Turn on heap tracing if we're debugging.
+    #define CRTDBG_MAP_ALLOC
+  #endif
+#endif
+
+#include <stdlib.h>
+#if (CFG_PLATFORM == CFG_PLATFORM_WIN32)
+  #include <malloc.h>
+  #ifdef _DEBUG
+  #include <crtdbg.h>
+  #endif
+#endif
+#if (CFG_COMPILER != CFG_COMPILER_MSVC)
+  // For endian/bits.
+  #include <sys/param.h>
+#endif
+
+// -----------------------------------------------------------------------------
+// Endian detection.
+// -----------------------------------------------------------------------------
+#ifndef CFG_ENDIAN
+  #ifdef __BYTE_ORDER
+    #if (__BYTE_ORDER == __LITTLE_ENDIAN)
+      #define CFG_ENDIAN CFG_ENDIAN_LITTLE
+    #endif
+    #if (__BYTE_ORDER == __BIG_ENDIAN)
+      #define CFG_ENDIAN CFG_ENDIAN_BIG
+    #endif
+  #endif
+#endif
+
+#ifndef CFG_ENDIAN
+  #ifdef BYTE_ORDER
+    #if (BYTE_ORDER == LITTLE_ENDIAN)
+      #define CFG_ENDIAN CFG_ENDIAN_LITTLE
+    #endif
+    #if (BYTE_ORDER == BIG_ENDIAN)
+      #define CFG_ENDIAN CFG_ENDIAN_BIG
+    #endif
+  #endif
+#endif
+
+#ifndef CFG_ENDIAN
+  #ifdef _BIG_ENDIAN
+    #define CFG_ENDIAN CFG_ENDIAN_BIG
+  #endif
+  #ifdef _LITTLE_ENDIAN
+    #define CFG_ENDIAN CFG_ENDIAN_LITTLE
+  #endif
+#endif
+
+#if CFG_COMPILER == CFG_COMPILER_MSVC
+  #if defined(_M_X64) || defined(_M_IX86)
+    #define CFG_ENDIAN CFG_ENDIAN_LITTLE
+  #endif
+#endif
+
+#ifndef CFG_ENDIAN
+  #error Cannot detect endian.
+#endif
+
+// -----------------------------------------------------------------------------
+// 32/64 bit detection.
+// -----------------------------------------------------------------------------
+#ifndef CFG_BITS
+  #if CFG_COMPILER == CFG_COMPILER_MSVC
+    #ifdef _M_X64
+      #define CFG_BITS 64
+    #endif
+    #ifdef _M_IX86
+      #define CFG_BITS 32
+    #endif
+  #endif
+
+  #if CFG_COMPILER == CFG_COMPILER_SUNCC
+    #if defined(__amd64__) || defined(__sparc64__) || defined(__x86_64__)
+      #define CFG_BITS 64
+    #else
+      #define CFG_BITS 32
+    #endif
+  #endif
+
+  #if (CFG_COMPILER == CFG_COMPILER_GCC) || (CFG_COMPILER == CFG_COMPILER_ICC)
+    #if defined(_LP64) || defined(_ILP64) || defined(__LP64__) || defined(__ILP64__) 
+      #define CFG_BITS 64
+    #else
+      #define CFG_BITS 32
+    #endif
+  #endif
+#endif
+
+#ifndef CFG_BITS
+  #error Cannot detect 32/64 bit mode.
+#endif
+
+// -----------------------------------------------------------------------------
+// SSE detection.
+// -----------------------------------------------------------------------------
+
+#if CFG_COMPILER == CFG_COMPILER_MSVC
+  // Processor settings.
+  #ifdef _M_X64
+    #ifdef CFG_HAVE_MMX
+      #undef CFG_HAVE_MMX
+    #endif
+    #define CFG_HAVE_MMX 0
+    #ifndef CFG_HAVE_SSE1
+      #define CFG_HAVE_SSE1 1
+    #endif
+    #ifndef CFG_HAVE_SSE2
+      #define CFG_HAVE_SSE2 1
+    #endif
+  #elif defined(_M_IX86)
+    #if ((_M_IX86 >= 6) && !defined(CFG_HAVE_MMX))
+      #define CFG_HAVE_MMX 1
+    #endif
+    #if ((_M_IX86_FP >= 1) && !defined(CFG_HAVE_SSE1))
+      #define CFG_HAVE_SSE1 1
+    #endif
+    #if ((_M_IX86_FP >= 2) && !defined(CFG_HAVE_SSE2))
+      #define CFG_HAVE_SSE2 1
+    #endif
+  #endif
+#endif
+
+#if (defined(__MMX__) && !defined(CFG_HAVE_MMX))
+  #define CFG_HAVE_MMX 1
+#endif
+
+#if (defined(__SSE__) && !defined(CFG_HAVE_SSE1))
+  #define CFG_HAVE_SSE1 1
+#endif
+
+#if (defined(__SSE2__) && !defined(CFG_HAVE_SSE2))
+  #define CFG_HAVE_SSE2 1
+#endif
+
+#if (defined(__SSE3__) && !defined(CFG_HAVE_SSE3))
+  #define CFG_HAVE_SSE3 1
+#endif
+
+#if (defined(__ALTIVEC__) && !defined(CFG_HAVE_ALTIVEC))
+  #define CFG_HAVE_ALTIVEC 1
+#endif
+
+#ifndef CFG_HAVE_MMX
+  #define CFG_HAVE_MMX 0
+#endif
+
+#ifndef CFG_HAVE_SSE1
+  #define CFG_HAVE_SSE1 0
+#endif
+
+#ifndef CFG_HAVE_SSE2
+  #define CFG_HAVE_SSE2 0
+#endif
+
+#ifndef CFG_HAVE_SSE3
+  #define CFG_HAVE_SSE3 0
+#endif
+
+#ifndef CFG_HAVE_ALTIVEC
+  #define CFG_HAVE_ALTIVEC 0
+#endif
+
+// -----------------------------------------------------------------------------
+// Cache size (SMP performance tweak).
+// -----------------------------------------------------------------------------
+
+#ifndef CFG_CACHELINE
+  #define CFG_CACHELINE 128
+#endif
+
+// -----------------------------------------------------------------------------
+// Compiler-specific configuration/fixes.
+// -----------------------------------------------------------------------------
+
+// Define UNREFERENCED_PARAMETER if it's not already done.
+#ifndef UNREFERENCED_PARAMETER
+  #ifndef _MSC_VER
+    #define UNREFERENCED_PARAMETER(P) (void)(P)
+  #endif
+#endif
+
+#if (CFG_PLATFORM == CFG_PLATFORM_OSX) || (CFG_PLATFORM == CFG_PLATFORM_FREEBSD)
+  inline void *_aligned_malloc(size_t size, size_t alignment)
+  {
+    UNREFERENCED_PARAMETER(alignment);
+    return malloc(size);
+  }
+
+  inline void _aligned_free(void *memblock)
+  {
+    free(memblock);
+  }
+#elif (CFG_PLATFORM == CFG_PLATFORM_SOLARIS)
+  inline void *_aligned_malloc(size_t size, size_t alignment)
+  {
+    return memalign(alignment, size);
+  }
+
+  inline void _aligned_free(void *memblock)
+  {
+    free(memblock);
+  }
+#elif (CFG_PLATFORM == CFG_PLATFORM_LINUX)
+  inline void *_aligned_malloc(size_t size, size_t alignment)
+  {
+    void *RetVal = NULL;
+    
+    // Need to collect the result of the posix_memalign call otherwise
+    // we get a "warn_unused_result" warning. We don't actually need to
+    // check the result, since on failure (i != 0) RetVal will be null.
+    int i = posix_memalign(&RetVal, alignment, size);
+    return RetVal;
+  }
+
+  inline void _aligned_free(void *memblock)
+  {
+    free(memblock);
+  }
+#elif (CFG_PLATFORM == CFG_PLATFORM_WIN32)
+  // _aligned_malloc and _aligned_free are native.
+#else
+  #warning No aligned malloc support. Please implement.
+#endif
+
+// Choose compiler-specific fixes.
+#if CFG_COMPILER == CFG_COMPILER_MSVC
+  // Replacement for stdint.h
+  typedef __int8 int8_t;
+  typedef __int16 int16_t;
+  typedef __int32 int32_t;
+  typedef __int64 int64_t;
+  typedef unsigned __int8 uint8_t;
+  typedef unsigned __int16 uint16_t;
+  typedef unsigned __int32 uint32_t;
+  typedef unsigned __int64 uint64_t;
+
+  // Fix up nonstandard case-insensitive compare naming
+  #include <string.h>
+  inline int strcasecmp(const char *s1, const char *s2)
+  { return _stricmp(s1, s2); }
+
+  // Note what's supported
+  #define THREADVAR __declspec(thread)
+
+  #define CFG_HAVE_TCHAR_H 1
+  #define CFG_HAVE_SECURECRT 1
+
+  #define ALIGN_8(atype, avar) __declspec(align(8)) atype avar
+  #define ALIGN_16(atype, avar) __declspec(align(16)) atype avar
+  #define ALIGN_CACHE(atype, avar) __declspec(align(CFG_CACHELINE)) atype avar
+
+  #define NOINLINE __declspec(noinline)
+  #define FORCEINLINE __forceinline
+#endif
+
+#if (CFG_COMPILER == CFG_COMPILER_GCC) || (CFG_COMPILER == CFG_COMPILER_ICC)
+  #include <stdint.h>
+  
+  #define CFG_HAVE_LRINT 1
+  #define CFG_HAVE_LRINTF 1
+  #define CFG_HAVE_NAN 1
+
+  #define ALIGN_8(atype, avar) atype __attribute__((aligned(8))) avar
+  #define ALIGN_16(atype, avar) atype avar __attribute__((aligned(16)))
+  #define ALIGN_CACHE(atype, avar) atype avar __attribute__((aligned(CFG_CACHELINE)))
+
+  #define NOINLINE __attribute__ ((noinline))
+  #define FORCEINLINE __attribute__ ((always_inline))
+#endif
+
+#if CFG_COMPILER == CFG_COMPILER_SUNCC
+  #include <stdint.h>
+
+  // Note what's supported
+  #define CFG_HAVE_LRINT 1
+  #define CFG_HAVE_LRINTF 1
+  #define CFG_HAVE_NAN 1
+
+  #if __SUNPRO_CC >= 0x590
+    #define NOINLINE __attribute__ ((noinline))
+    #define FORCEINLINE __attribute__ ((always_inline))
+
+    #define ALIGN_8(atype, avar) atype __attribute__((aligned(8))) avar
+    #define ALIGN_16(atype, avar) atype __attribute__((aligned(16))) avar
+    #define ALIGN_CACHE(atype, avar) atype __attribute__((aligned(CFG_CACHELINE))) avar
+  #else
+    // Sun C prior to 5.9 only has integer SSE2 and MMX support.
+    #define CFG_ONLY_INTEGER_SSE2 1
+    #ifdef CFG_HAVE_SSE1
+      #undef CFG_HAVE_SSE1
+      #define CFG_HAVE_SSE1 0
+    #endif
+    #ifdef CFG_HAVE_SSE3
+      #undef CFG_HAVE_SSE3
+      #define CFG_HAVE_SSE3 0
+    #endif
+  #endif
+#endif
+
+#ifndef NOINLINE
+  #define NOINLINE
+#endif
+
+#ifndef FORCEINLINE
+  #define FORCEINLINE inline
+#endif
+
+// -----------------------------------------------------------------------------
+// Include SSE1/SSE2 headers.
+// -----------------------------------------------------------------------------
+
+#if CFG_COMPILER == CFG_COMPILER_SUNCC
+  #include <sunmedia_intrin.h>
+#else
+  #if CFG_HAVE_MMX == 1
+    #include <mmintrin.h>
+  #endif
+
+  #if CFG_HAVE_SSE1 == 1
+    #include <xmmintrin.h>
+  #endif
+
+  #if CFG_HAVE_SSE2 == 1
+    #include <emmintrin.h>
+  #endif
+
+  #if CFG_HAVE_SSE3 == 1
+    #include <pmmintrin.h>
+  #endif
+
+  #if CFG_HAVE_ALTIVEC == 1
+    #if !defined(__APPLE__)
+      #include <altivec.h>
+    #endif
+
+    // Fix up GCC's mess
+    #if !defined(__APPLE_ALTIVEC__)
+      #undef vector
+      #undef bool
+      #undef pixel
+    #endif
+  #endif
+#endif
+
+// -----------------------------------------------------------------------------
+// Platform-specific configuration/fixes.
+// -----------------------------------------------------------------------------
+
+// Threading and OS API selection
+#ifndef CFG_OSAPI
+  #if CFG_PLATFORM == CFG_PLATFORM_WIN32
+    #define CFG_OSAPI CFG_OSAPI_WIN32
+  #elif CFG_PLATFORM == CFG_PLATFORM_LINUX
+    #define CFG_OSAPI CFG_OSAPI_POSIX
+  #elif CFG_PLATFORM == CFG_PLATFORM_CYGWIN
+    #define CFG_OSAPI CFG_OSAPI_POSIX
+  #elif CFG_PLATFORM == CFG_PLATFORM_SOLARIS
+    #define CFG_OSAPI CFG_OSAPI_POSIX
+  #elif CFG_PLATFORM == CFG_PLATFORM_OSX
+    #define CFG_OSAPI CFG_OSAPI_POSIX
+  #elif CFG_PLATFORM == CFG_PLATFORM_FREEBSD
+    #define CFG_OSAPI CFG_OSAPI_POSIX
+  #else
+    #error Cannot detect OS API.
+  #endif
+#endif
+
+#ifndef CFG_THREADAPI
+  #if CFG_PLATFORM == CFG_PLATFORM_WIN32
+    #define CFG_THREADAPI CFG_THREADAPI_WIN32
+  #elif CFG_PLATFORM == CFG_PLATFORM_LINUX
+    #define CFG_THREADAPI CFG_THREADAPI_PTHREADS
+  #elif CFG_PLATFORM == CFG_PLATFORM_CYGWIN
+    #define CFG_THREADAPI CFG_THREADAPI_WIN32
+  #elif CFG_PLATFORM == CFG_PLATFORM_SOLARIS
+    #define CFG_THREADAPI CFG_THREADAPI_PTHREADS
+  #elif CFG_PLATFORM == CFG_PLATFORM_OSX
+    #define CFG_THREADAPI CFG_THREADAPI_PTHREADS
+  #elif CFG_PLATFORM == CFG_PLATFORM_FREEBSD
+    #define CFG_THREADAPI CFG_THREADAPI_PTHREADS
+  #else
+    #error Cannot detect threading API.
+  #endif
+#endif
+
+#if CFG_OSAPI == CFG_OSAPI_WIN32
+  #define NOMINMAX
+  #include <windows.h>
+#endif
+
+#if CFG_OSAPI == CFG_OSAPI_POSIX
+  #include <unistd.h>
+#endif
+
+#if CFG_THREADAPI == CFG_THREADAPI_WIN32
+  #include <process.h>
+#endif
+
+#if CFG_THREADAPI == CFG_THREADAPI_PTHREADS
+  #include <pthread.h>
+#endif
+
+// -----------------------------------------------------------------------------
+// General fixes.
+// -----------------------------------------------------------------------------
+
+// Emulate NaN()
+#if CFG_HAVE_NAN == 0
+  inline double nan(char *StrRep)
+  {
+    UNREFERENCED_PARAMETER(StrRep);
+
+    static const union
+    {
+      uint32_t nan_u32[2];
+      double nan_double;
+    } NANVal =
+    #if CFG_ENDIAN == CFG_ENDIAN_LITTLE
+      {{0xffffffff, 0x7fffffff}};
+    #else
+      {{0x7fffffff, 0xffffffff}};
+    #endif
+    return NANVal.nan_double;
+  }
+#endif
+
+// Define UINT64_C for 64-bit constants
+#ifndef UINT64_C
+  #if (CFG_COMPILER == CFG_COMPILER_GCC) || (CFG_COMPILER == CFG_COMPILER_SUNCC) || (CFG_COMPILER == CFG_COMPILER_ICC)
+    #define UINT64_C(x) (x ## ULL)
+    #define INT64_C(x) (x ## LL)
+  #elif CFG_COMPILER == CFG_COMPILER_MSVC
+    #define UINT64_C(x) (x ## UI64)
+    #define INT64_C(x) (x ## I64)
+  #else
+    #error Could not define UINT64_C. Need a compiler-specific fix.
+  #endif
+#endif
+
+  template<typename fp_type> union FP_UNION;
+
+  template<> union FP_UNION<double>
+  {
+      uint64_t as_int;
+      double as_value;
+  };
+
+  template<> union FP_UNION<float>
+  {
+      uint32_t as_int;
+      float as_value;
+  };
+
+  template<typename fp_type> inline FP_UNION<fp_type> _xmds_nan_mask();
+
+  template<> inline FP_UNION<double> _xmds_nan_mask<double>()
+  {
+      static const FP_UNION<double> NANVal = {UINT64_C(0x7ff0000000000000)};
+      return NANVal;
+  }
+
+  template<> inline FP_UNION<float> _xmds_nan_mask<float>()
+  {
+      static const FP_UNION<float> NANVal = {0x7f800000};
+      return NANVal;
+  }
+
+  template<typename fp_type> inline bool _xmds_isnonfinite(fp_type value)
+  {
+      FP_UNION<fp_type> x, NANMask = _xmds_nan_mask<fp_type>();
+      x.as_value = value;
+      return (x.as_int & NANMask.as_int) == NANMask.as_int;
+  }
+
+// Floating point casting.
+#if (CFG_HAVE_LRINT == 1) || (CFG_HAVE_LRINTF == 1)
+  // Enable ISO C functions on platforms that support them.
+  #define	_ISOC9X_SOURCE	1
+	#define _ISOC99_SOURCE	1
+	#define	__USE_ISOC9X	1
+	#define	__USE_ISOC99	1
+#endif
+
+#if (CFG_COMPILER == CFG_COMPILER_MSVC) && defined(_M_X64)
+  // MS killed inline assembly in x64 so have to go the slow way or the SSE(2)
+  // way. Note that since we're checking that we're using MSVC and in 64-bit
+  // mode, we know we have a LLP64 model (so long = 32 bits). The following is
+  // NOT correct in a LP64 model, where long is 64 bits.
+  #if (CFG_HAVE_LRINT == 0) && (CFG_HAVE_SSE2 == 1)
+    inline long int lrint(double x) { return _mm_cvtsd_si32(_mm_load_sd(&x)); }
+    #undef CFG_HAVE_LRINT
+    #define CFG_HAVE_LRINT 1
+  #endif
+
+  #if (CFG_HAVE_LRINTF == 0) && (CFG_HAVE_SSE1 == 1)
+    inline long int lrint(float x) { return _mm_cvtss_si32(_mm_load_ss(&x)); }
+    #undef CFG_HAVE_LRINTF
+    #define CFG_HAVE_LRINTF 1
+  #endif
+#endif
+
+#if (CFG_COMPILER == CFG_COMPILER_MSVC) && defined(_M_IX86) && !defined(_M_X64)
+  // We can use inline assembler.
+  #if (CFG_HAVE_LRINT == 0)
+    inline long int lrint(double x)
+    {
+      long int RetVal;
+
+	    __asm
+	    {
+        fld     x
+        fistp   RetVal
+		  };
+  			
+	    return RetVal;
+    } 
+    #undef CFG_HAVE_LRINT
+    #define CFG_HAVE_LRINT 1
+  #endif
+	
+  #if (CFG_HAVE_LRINTF == 0)
+    inline long int lrintf(float x)
+    {
+      long int RetVal;
+
+	    __asm
+	    {
+        fld     x
+		    fistp   RetVal
+		  };
+  			
+	    return RetVal;
+    }
+    #undef CFG_HAVE_LRINTF
+    #define CFG_HAVE_LRINTF 1
+  #endif
+#endif
+
+#if (CFG_HAVE_LRINT == 0)
+  #if CFG_COMPILER == CFG_COMPILER_GCC
+    #warning lrint() not natively supported, replacing with slow alternative.
+  #elif CFG_COMPILER == CFG_COMPILER_MSVC
+    #pragma message("Warning: lrint() not natively supported, replacing with slow alternative.")
+  #endif
+  // #include <math.h>
+  inline long int lrint(double x) { return static_cast<long int>(floor(x + 0.5)); }
+#endif
+
+#if (CFG_HAVE_LRINTF == 0)
+  #if CFG_COMPILER == CFG_COMPILER_GCC
+    #warning lrintf() not natively supported, replacing with slow alternative.
+  #elif CFG_COMPILER == CFG_COMPILER_MSVC
+    #pragma message("Warning: lrintf() not natively supported, replacing with slow alternative.")
+  #endif
+  // #include <math.h>
+  inline long int lrintf(float x) { return static_cast<long int>(floorf(x + 0.5f)); }
+#endif
+
+// -----------------------------------------------------------------------------
+// Endian correction.
+// -----------------------------------------------------------------------------
+
+template<int Bits> inline size_t EndianFix(size_t LittleEndianIndex)
+{
+  #if CFG_ENDIAN == CFG_ENDIAN_BIG
+  size_t FlipMask = (((size_t)1) << Bits) - 1;
+  return
+    (LittleEndianIndex & ~FlipMask) +
+    (FlipMask - (LittleEndianIndex & FlipMask));
+  #else
+  return LittleEndianIndex;
+  #endif
+}
+
+template<> size_t inline EndianFix<1>(size_t LittleEndianIndex)
+{
+  #if CFG_ENDIAN == CFG_ENDIAN_BIG
+  return (LittleEndianIndex ^ 1);
+  #else
+  return LittleEndianIndex;
+  #endif
+}
+
+template<int Bits> inline int EndianFix(int LittleEndianIndex)
+{
+  #if CFG_ENDIAN == CFG_ENDIAN_BIG
+  size_t FlipMask = (((int)1) << Bits) - 1;
+  return
+    (LittleEndianIndex & ~FlipMask) +
+    (FlipMask - (LittleEndianIndex & FlipMask));
+  #else
+  return LittleEndianIndex;
+  #endif
+}
+
+template<> int inline EndianFix<1>(int LittleEndianIndex)
+{
+  #if CFG_ENDIAN == CFG_ENDIAN_BIG
+  return (LittleEndianIndex ^ 1);
+  #else
+  return LittleEndianIndex;
+  #endif
+}
+
+template<int Bits, size_t LittleEndianIndex> struct EndianFix_static
+{
+  #if CFG_ENDIAN == CFG_ENDIAN_BIG
+  static const size_t FlipMask = (static_cast<size_t>(1) << Bits) - 1;
+  static const size_t Value = (LittleEndianIndex & ~FlipMask) + (FlipMask - (LittleEndianIndex & FlipMask));
+  #else
+  static const size_t Value = LittleEndianIndex;
+  #endif
+};
+
+template<int Bits, int LittleEndianIndex> struct EndianFix_static_int
+{
+  #if CFG_ENDIAN == CFG_ENDIAN_BIG
+  static const int FlipMask = (static_cast<int>(1) << Bits) - 1;
+  static const int Value = (LittleEndianIndex & ~FlipMask) + (FlipMask - (LittleEndianIndex & FlipMask));
+  #else
+  static const int Value = LittleEndianIndex;
+  #endif
+};
+
+#endif
diff --git a/xpdeint/minidom_extras.py b/xpdeint/minidom_extras.py
new file mode 100644
index 0000000..8d4ef27
--- /dev/null
+++ b/xpdeint/minidom_extras.py
@@ -0,0 +1,250 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+minidom_extras.py
+
+Created by Graham Dennis on 2008-06-15.
+
+Copyright (c) 2008-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+from xml.dom import minidom
+from xml.dom import expatbuilder
+from xpdeint.ParserException import ParserException
+import xpdeint.Python24Support
+
+# These are additional functions that will be added to the XML
+# classes for convenience.
+def getChildElementsByTagName(self, tagName, optional=False):
+  """
+  Return child XML elements that have the tag name `tagName`.
+  
+  This function will raise an exception if there are no children
+  with `tagName` unless the keyword argument `optional` is passed
+  with a value of `True`.
+  """
+  
+  elements = filter(lambda x: x.nodeType == minidom.Node.ELEMENT_NODE and x.tagName == tagName, self.childNodes)
+  if not optional and len(elements) == 0:
+    raise ParserException(self, "There must be at least one '%(tagName)s' element." % locals())
+  return elements
+
+def getChildElementsByTagNames(self, tagNames, optional=False):
+  """
+  Return child XML elements that have tag names in the collection `tagNames`.
+  
+  This function will raise an exception if there are no children with a tag name in `tagNames`
+  unless the keyword argument `optional` is `True`.
+  """
+  
+  elements = [element for element in self.childNodes if element.nodeType == minidom.Node.ELEMENT_NODE and element.tagName in tagNames]
+  if not optional and len(elements) == 0:
+    raise ParserException(self, "There must be at least one element from the set {%s}." % ", ".join(tagNames))
+  return elements
+
+def getChildElementByTagName(self, tagName, optional=False):
+  """
+  Return the child XML element that has the tag name `tagName`.
+  
+  This function will raise an exception if there is more than
+  one child with tag name `tagName`. Unless the keyword argument
+  `optional` is passed with a value of `True`, an exception will
+  also be raised if there is no child with tag name `tagName`.
+  """
+  elements = self.getChildElementsByTagName(tagName, optional=optional)
+
+  if not optional and not len(elements) == 1:
+    raise ParserException(self, "There must be exactly one '%(tagName)s' element." % locals())
+
+  if optional and len(elements) > 1:
+    raise ParserException(self, "There may be at most one '%(tagName)s' element." % locals())
+
+  if optional and len(elements) == 0:
+    return None
+  else:
+    return elements[0]
+
+
+def innerText(self):
+  """
+  Return the contents of all descendent text nodes and CDATA nodes.
+  
+  For example, consider the following XML::
+  
+    <root>
+      <someTag> someText </someTag>
+      <![CDATA[
+        some other text.
+        ]]>
+    </root>
+  
+  On the ``root`` element, `innerText` would return " someText some other text." plus
+  or minus some newlines and other whitespace.
+  """
+  contents = []
+  for child in self.childNodes:
+    if child.nodeType == minidom.Node.ELEMENT_NODE:
+      contents.append(child.innerText())
+    elif child.nodeType == minidom.Node.TEXT_NODE or child.nodeType == minidom.Node.CDATA_SECTION_NODE:
+      contents.append(child.data)
+  return "".join(contents).strip()
+
+
+def cdataContents(self):
+  """
+  Return the contents of any CDATA nodes that are children of this element.
+  """
+  contents = []
+  for child in self.childNodes:
+    if child.nodeType == minidom.Node.CDATA_SECTION_NODE:
+      contents.append(child.data)
+  return "".join(contents)
+
+def lineNumberForCDATASection(self):
+  for child in self.childNodes:
+    if child.nodeType == minidom.Node.CDATA_SECTION_NODE:
+      return child.getUserData('lineNumber')
+  raise ParserException(self, "Missing CDATA section.")
+
+def userUnderstandableXPath(self):
+  """
+  Return an XPath-like string (but more user-friendly) which allows the user to
+  locate this XML element.
+  
+  I'd use line/column numbers too except that that information isn't available as part
+  of the XML spec, so there isn't any function that you can call on an element to get
+  that information. At least from what I can tell.
+  """
+  
+  currentElement = self
+  elementPath = []
+  
+  while 1:
+    if not currentElement:
+      break
+    elementPath.append(currentElement)
+    currentElement = currentElement.parentNode
+  
+  elementPathStringList = []
+  for currentElement in reversed(elementPath):
+    if len(elementPathStringList) > 0:
+      elementPathStringList.append(" --> ")
+    
+    elementDescription = currentElement.nodeName
+    
+    if currentElement.parentNode:
+      siblingElements = currentElement.parentNode.getChildElementsByTagName(currentElement.tagName)
+      if len(siblingElements) > 1:
+        elementDescription += '[' + str(siblingElements.index(currentElement)) + ']'
+    elementPathStringList.extend(["'", elementDescription, "'"])
+  
+  return ''.join(elementPathStringList)
+
+from functools import wraps
+
+def concatenateFunctions(f1, f2):
+  """
+  Returns a function that calls two functions in turn.
+  
+  The function returned by this function first calls `f1`, and then
+  `f2`, but returns the result of `f1`.
+  """
+  @wraps(f1)
+  def wrapper(*args, **KWs):
+    result = f1(*args, **KWs)
+    f2(*args, **KWs)
+    return result
+  
+  return wrapper
+
+def composeFunctions(f1, f2):
+  """
+  Returns a function that calls ``f2(f1(args))``.
+  """
+  @wraps(f1)
+  def wrapper(*args, **KWs):
+    return f2(f1(*args, **KWs))
+  
+  return wrapper
+
+def setLineAndColumnHandlers(self, *argsOuter, **KWsOuter):
+  """
+  Set the line and column number handlers for an ExpatBuilder.
+  """
+  def setLineAndColumnValuesForElement(*args, **KWs):
+    """
+    Set the line and column numbers from the expat parser.
+    This data is copied into the ``userData`` dictionary of the node.
+    The start of the XML tag's line number is available with the key
+    'lineNumber', and its column number with the key 'columnNumber'.
+    """
+    parser = self._parser
+    self.curNode.setUserData('lineNumber', parser.CurrentLineNumber, None)
+    self.curNode.setUserData('columnNumber', parser.CurrentColumnNumber, None)
+  
+  def getLineNumberForCDATASection(*args, **KWs):
+    parser = self._parser
+    self.curNode.ownerDocument.setUserData('_cdata_section_line_number_start', parser.CurrentLineNumber, None)
+  
+  self.start_element_handler = concatenateFunctions(self.start_element_handler, setLineAndColumnValuesForElement)
+  self.start_cdata_section_handler = concatenateFunctions(self.start_cdata_section_handler, getLineNumberForCDATASection)
+
+def setLineNumberForCDATASection(node):
+  node.setUserData('lineNumber', node.ownerDocument.getUserData('_cdata_section_line_number_start'), None)
+  return node
+
+def external_entity_ref_handler(self, context, base, systemId, publicId):
+  childParser = self._parser.ExternalEntityParserCreate(context)
+  fragment = self.document.createDocumentFragment()
+  childParser.Parse(open(systemId,'r').read(), 1)
+  
+  return 1
+
+def install_minidom_extras():
+  """
+  This is the function to call to get the minidom extras installed.
+  """
+  # Add the helper methods defined earlier to the XML classes
+  minidom.Element.getChildElementsByTagName  = getChildElementsByTagName
+  minidom.Document.getChildElementsByTagName = getChildElementsByTagName
+  
+  minidom.Element.getChildElementsByTagNames  = getChildElementsByTagNames
+  minidom.Document.getChildElementsByTagNames = getChildElementsByTagNames
+  
+  minidom.Element.getChildElementByTagName  = getChildElementByTagName
+  minidom.Document.getChildElementByTagName = getChildElementByTagName
+  
+  minidom.Document.createCDATASection = composeFunctions(minidom.Document.createCDATASection, setLineNumberForCDATASection)
+  
+  minidom.Element.innerText = innerText
+  minidom.Element.cdataContents = cdataContents
+  minidom.Element.lineNumberForCDATASection = lineNumberForCDATASection
+  minidom.Element.userUnderstandableXPath = userUnderstandableXPath
+  
+
+  expatbuilder.ExpatBuilder.external_entity_ref_handler = external_entity_ref_handler
+  
+  
+  # Add our setLineAndColumnHandlers function to the end of the 'reset' function of ExpatBuilder
+  # This will ensure that our line and column number handlers are installed when any ExpatBuilder
+  # instance is created. This gets us line and column number information on our XML nodes as minidom
+  # uses ExpatBuilder to do the parsing for it.
+  # Note that 'reset' gets called during initialisation of the ExpatBuilder.
+  expatbuilder.ExpatBuilder.install = concatenateFunctions(setLineAndColumnHandlers, expatbuilder.ExpatBuilder.install)
+  
+
+install_minidom_extras()
diff --git a/xpdeint/parser2.py b/xpdeint/parser2.py
new file mode 100755
index 0000000..92fa4d0
--- /dev/null
+++ b/xpdeint/parser2.py
@@ -0,0 +1,498 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+parser2.py
+
+Created by Graham Dennis on 2008-01-03.
+
+Copyright (c) 2008-2012, Graham Dennis and Joe Hope
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+import os
+import sys
+import getopt
+import xpdeint.Python24Support
+import xml
+from xml.dom import minidom
+import xpdeint.minidom_extras
+import subprocess
+from pkg_resources import resource_filename
+import hashlib
+import shutil
+
+DATA_CACHE_VERSION = 1
+
+import cPickle
+
+from xpdeint.Preferences import xpdeintUserDataPath
+
+# Import the parser stuff
+from xpdeint.ParserException import ParserException, parserWarning
+from xpdeint.XMDS2Parser import XMDS2Parser
+
+# Import the top level template
+from xpdeint.Simulation import Simulation as SimulationTemplate
+
+# Import the IndentFilter. The IndentFilter is the magic filter
+# that when used correctly makes the generated source correctly
+# indented. See the comments in IndentFilter.py for more info.
+from xpdeint.IndentFilter import IndentFilter
+
+# Import the root class for all templates
+from xpdeint._ScriptElement import _ScriptElement
+
+# Import the Configuration module
+from xpdeint import Configuration
+
+# The help message printed when --help is used as an argument
+help_message = '''
+usage: xmds2 [options] fileToBeParsed
+
+Options and arguments:
+-h                              : Print this message (also --help)
+-o filename                     : This overrides the name of the output file to be generated (also --output)
+-v                              : Verbose mode (also --verbose)
+-g                              : Debug mode (also --debug). Compiler error messages report errors in the .cc
+                                  file, not the .xmds file. Implies --verbose. Mostly useful when debuging xmds
+                                  code generation.
+-n                              : Only generate a source file, don't compile (also --no-compile)
+--configure                     : Run configuration checks for compiling simulations
+--reconfigure                   : Run configuration using the same options as used with the last
+                                  time --configure was run with the additional arguments specified
+--include-path /path/to/include : Add the path /path/to/include to the list of paths searched for include headers
+                                  This option is only meaningful when used with --(re)configure
+--lib-path /path/to/lib         : Add the path /path/to/lib to the list of paths searched for libraries
+                                  This option is only meaningful when used with --(re)configure
+'''
+
+def fileContentsHash(filename):
+  return hashlib.sha1(file(filename).read()).hexdigest()
+  
+
+def anyObject(iterable):
+  """
+  Return an object from an iterable. This is designed to be used with sets
+  because I can't work out any other way of doing this, but it will work
+  with any iterable.
+  """
+  for obj in iterable:
+    return obj
+
+def degsOutput(err, globalNameSpace):
+  """
+  Format the output for DEGS in case of parsing error
+  """
+  lineNumber = err.lineNumber
+  columnNumber = err.columnNumber
+  err.msg = '\n' + err.msg + '\n'
+  print >> sys.stderr, err.msg
+  if not lineNumber == None:
+    positionReference =  ["Error caused at line %(lineNumber)i" % locals()]
+    if not columnNumber == None:
+      positionReference.append(", column %(columnNumber)i" % locals())
+    positionReference.append(":\n")
+    positionReference.append(globalNameSpace['inputScript'].splitlines(True)[lineNumber-1])
+    if not columnNumber == None:
+        positionReference.append(" "*(columnNumber-1) + "^~~ here.")
+    print >> sys.stderr, ''.join(positionReference) + '\n'
+  if err.element:
+    print >> sys.stderr, "In element: " + err.element.userUnderstandableXPath()
+  else:
+    print >> sys.stderr, "Unknown element. Please report this error to %s" % globalNameSpace['bugReportAddress']
+
+class Usage(Exception):
+  """
+  Exception class used when an error occurs parsing command
+  line arguments.
+  """
+  def __init__(self, msg):
+    self.msg = msg
+  
+
+def main(argv=None):
+  # Default to not being verbose with error messages
+  # If debug is true, then when an error occurs during parsing,
+  # the Python backtrace will be shown in addition to the XML location
+  # where the error occurred.
+  debug = False
+  verbose = False
+  # degs is off by default
+  # If degs is true then the output in case of error is formatted for parsing by DEGS
+  degs = False
+  
+  compileScript = True
+  noVersionInformation = False
+  
+  # Import version information
+  from Preferences import versionString
+  from Version import subversionRevisionString
+  
+  print "xmds2 version %(versionString)s (%(subversionRevisionString)s)" % locals()
+  print "Copyright 2000-2013 Graham Dennis, Joseph Hope, Mattias Johnsson"
+  print "                    and the xmds team"
+  
+  if not os.path.isdir(xpdeintUserDataPath):
+      os.mkdir(xpdeintUserDataPath)
+  
+  # Attempt to parse command line arguments
+  if argv is None:
+    argv = sys.argv
+  try:
+    try:
+      opts, args = getopt.gnu_getopt(
+                    argv[1:],
+                    "gvhno:",
+                    [
+                      "debug",
+                      "verbose",
+                      "help",
+                      "no-compile",
+                      "output=",
+                      "no-version",
+                      "configure",
+                      "reconfigure",
+                      "include-path=",
+                      "lib-path=",
+                      "waf-verbose",
+                      "degs" # This option is not documented and is intended only for use by DEGS, a Mac GUI for XMDS
+                    ]
+      )
+      del sys.argv[1:]
+    except getopt.error, msg:
+      raise Usage(msg)
+    
+    includePaths = []
+    libPaths = []
+    run_config = False
+    run_reconfig = False
+    
+    sourceFilename = None
+    # option processing
+    for option, value in opts:
+      if option in ("-g", "--debug"):
+        debug = verbose = True
+      elif option in ('-v', '--verbose'):
+        verbose = True
+      elif option in ('--degs'):
+        degs = True
+      elif option == "--waf-verbose":
+        Configuration.Logs.verbose = 3
+      elif option in ("-h", "--help"):
+        raise Usage(help_message)
+      elif option in ("-o", "--output"):
+        sourceFilename = value
+      elif option in ("-n", "--no-compile"):
+        compileScript = False
+      elif option == "--no-version":
+        # This option is here for the test suite so that the generated source files don't
+        # contain version information. This makes it easier to check if the source for a script
+        # has changed as otherwise it would change every time the subversison revision number
+        # increased
+        noVersionInformation = True
+      elif option == "--configure":
+        run_config = True
+      elif option == '--reconfigure':
+        run_reconfig = True
+      elif option == '--include-path':
+        includePaths.append(value)
+      elif option == '--lib-path':
+        libPaths.append(value)
+    
+    if run_config:
+      return Configuration.run_config(includePaths, libPaths)
+    elif run_reconfig or includePaths or libPaths:
+      return Configuration.run_reconfig(includePaths, libPaths)
+    
+    # argument processing
+    if len(args) == 1:
+        scriptName = args[0]
+    else:
+        raise Usage(help_message)
+  
+  except Usage, err:
+    print >> sys.stderr, sys.argv[0].split("/")[-1] + ": " + str(err.msg)
+    print >> sys.stderr, "\t for help use --help"
+    return 2
+  
+  wscript_path = resource_filename(__name__, 'support/wscript')
+  wscript_userdata_path = os.path.join(xpdeintUserDataPath, 'wscript')
+  waf_build_cache_path = os.path.join(xpdeintUserDataPath, 'waf_configure/c4che/_cache.py')
+  
+  if not os.path.isfile(wscript_userdata_path) or \
+    fileContentsHash(wscript_userdata_path) != fileContentsHash(wscript_path) or \
+    not os.path.exists(waf_build_cache_path):
+    print "Reconfiguring xmds2 (updated config script)..."
+    
+    Configuration.run_reconfig()
+  
+  # globalNameSpace is a dictionary of variables that are available in all
+  # templates
+  globalNameSpace = {'scriptName': scriptName, 'simulationName': os.path.splitext(scriptName)[0]}
+  
+  if noVersionInformation:
+    versionString = "VERSION_PLACEHOLDER"
+    subversionRevisionString = "SUBVERSION_REVISION_PLACEHOLDER"
+  
+  # Open the script file
+  try:
+    scriptFile = file(scriptName)
+  except Exception, err:
+    print >> sys.stderr, "Exception raised while trying to read xmds script:", err
+    return -1
+  
+  # Read the contents of the file
+  globalNameSpace['inputScript'] = scriptFile.read().expandtabs()
+  # Close the file
+  scriptFile.close()
+  del scriptFile
+  
+  print "Generating source code..."
+  
+  # Parse the XML input script into a set of XML
+  # classes
+  try:
+    xmlDocument = minidom.parseString(globalNameSpace['inputScript'])
+  except xml.parsers.expat.ExpatError, err:
+    print >> sys.stderr, "XML Parser error:", err
+    if debug: raise
+    return -1
+  except Exception, err:
+    print >> sys.stderr, "Exception raised during parsing xmds script:", err
+    if debug: raise
+    return -1
+  
+  # Attempt to import lxml and run the script through
+  # the schema
+  try:
+    from lxml import etree
+  except ImportError, err:
+    pass
+  else:
+    # Parse the schema
+    relaxng_doc = etree.parse(resource_filename(__name__, 'support/xpdeint.rng'))
+    relaxng = etree.RelaxNG(relaxng_doc)
+    # Parse the script
+    script_doc = etree.fromstring(globalNameSpace['inputScript'])
+    if not relaxng.validate(script_doc):
+      # Validation failed
+      for error in relaxng.error_log:
+        parserWarning((error.line, error.column), error.message)
+  
+  
+  globalNameSpace['debug'] = debug
+  globalNameSpace['xmlDocument'] = xmlDocument
+  globalNameSpace['features'] = {}
+  globalNameSpace['fields'] = []
+  globalNameSpace['simulationVectors'] = []
+  globalNameSpace['momentGroups'] = []
+  globalNameSpace['symbolNames'] = set()
+  globalNameSpace['xmds'] = {'versionString': versionString,
+                             'subversionRevision': subversionRevisionString}
+  globalNameSpace['templates'] = set()
+  globalNameSpace['precision'] = 'double'
+  globalNameSpace['simulationBuildVariant'] = set()
+  globalNameSpace['simulationUselib'] = set()
+  globalNameSpace['bugReportAddress'] = 'xmds-devel at lists.sourceforge.net'
+  
+  xpdeintDataCachePath = os.path.join(xpdeintUserDataPath, 'xpdeint_cache')
+  dataCache = {}
+  if os.path.isfile(xpdeintDataCachePath):
+    try:
+      try:
+        import mpmath
+        mpmath.mp.prec = 128
+      except ImportError, err:
+        pass
+      dataCacheFile = open(xpdeintDataCachePath, 'rb')
+      dataCache = cPickle.load(dataCacheFile)
+      dataCacheFile.close()
+      del dataCacheFile
+    except Exception, err:
+      print >> sys.stderr, "Warning: Unable to load xmds2 data cache."
+      if debug: raise
+  globalNameSpace['dataCache'] = dataCache
+  
+  if dataCache.get('version', 0) != DATA_CACHE_VERSION:
+    dataCache.clear()
+    dataCache['version'] = DATA_CACHE_VERSION
+  
+  # We need the anyObject function in a few templates, so
+  # we add it to the globalNameSpace, so that the function can
+  # be called from a template like $anyObject(someContainer)
+  globalNameSpace['anyObject'] = anyObject
+  
+  # Now start the process of parsing the XML class structure
+  # onto a template heirarchy.
+  try:
+    parser = None
+    
+    # Check if the XML claims to be an XMDS2 script
+    if XMDS2Parser.canParseXMLDocument(xmlDocument):
+      parser = XMDS2Parser()
+    
+    # We don't have a parser that understands the XML, so we must bail
+    if not parser:
+      print >> sys.stderr, "Unable to recognise file as an xmds script of the correct version."
+      return -1
+    
+    # Set our magic filter
+    filterClass = IndentFilter
+    # Construct the top-level template class
+    simulationTemplate = SimulationTemplate(parent = None, searchList=[globalNameSpace], filter=filterClass)
+    _ScriptElement.simulation = simulationTemplate
+    # Now get the parser to do the complex job of mapping the XML classes onto our
+    # templates.
+    parser.parseXMLDocument(xmlDocument, globalNameSpace, filterClass)
+    
+    # Now run preflight stage
+    # Preflight is the stage which maps vector names, etc to the actual vectors themselves. It also
+    # allows all templates to check that all of their settings are sane, and raise an exception if
+    # there is a problem.
+    #
+    
+    # Loop over a copy because we may create templates during iteration
+    for template in _ScriptElement.simulation.children[:]:
+      if not template._haveBeenRemoved:
+        template.implementationsForFunctionName('bindNamedVectors')
+    
+    for template in _ScriptElement.simulation.children[:]:
+      if not template._haveBeenRemoved:
+        template.implementationsForFunctionName('preflight')
+
+    for template in _ScriptElement.simulation.children[:]:
+      if not template._haveBeenRemoved:
+        template.implementationsForFunctionName('post_preflight')
+    
+    # Preflight is done
+    # We don't need the 'simulationVectors' variable any more.
+    del globalNameSpace['simulationVectors']
+    
+    # Now build the map of transforms needed in the simulation
+    globalNameSpace['features']['TransformMultiplexer'].buildTransformMap()
+    
+    
+    # Final conversion to string
+    simulationContents = str(simulationTemplate)
+    
+  # If there was an exception during parsing or preflight, a ParserException should have been
+  # raised. The ParserException knows the XML element that triggered the exception, and the 
+  # error string that should be presented to the user.
+  except ParserException, err: 
+    if degs:
+      degsOutput(err, globalNameSpace)
+      return -1
+    # Print the error to the user
+    lineNumber = err.lineNumber
+    columnNumber = err.columnNumber
+    print >> sys.stderr, err.msg
+    if not lineNumber == None:
+      positionReference =  ["    Error caused at line %(lineNumber)i" % locals()]
+      if not columnNumber == None:
+        positionReference.append(", column %(columnNumber)i" % locals())
+      positionReference.append(":\n")
+      positionReference.append(globalNameSpace['inputScript'].splitlines(True)[lineNumber-1])
+      if not columnNumber == None:
+          positionReference.append(" "*(columnNumber-1) + "^~~ here.")
+      print >> sys.stderr, ''.join(positionReference)
+    if debug:
+      if err.element:
+        print >> sys.stderr, "    In element: " + err.element.userUnderstandableXPath()
+      else:
+        print >> sys.stderr, "    Unknown element. Please report this error to %s" % globalNameSpace['bugReportAddress']
+    
+    # If we have the debug option on, then in addition to the path to the XML element
+    # that triggered the exception, print a traceback showing the list of Python function
+    # calls that led to the exception being hit.
+    if debug:
+      raise
+    
+    return -1
+  
+  dataCache = globalNameSpace['dataCache']
+  if dataCache:
+    try:
+      dataCacheFile = file(xpdeintDataCachePath, 'w')
+    except IOError, err:
+      print >> sys.stderr, "Warning: Unable to write xmds2 data cache. " \
+                           "Ensure '%(xpdeintUserDataPath)s' exists and is writable." % locals()
+    else:
+      cPickle.dump(dataCache, dataCacheFile, protocol = 2)
+      dataCacheFile.close()
+  
+  
+  # Now actually write the simulation to disk.
+  
+  if not sourceFilename:
+    sourceFilename = globalNameSpace['simulationName']
+  
+  if not sourceFilename.endswith('.cc'):
+    sourceFilename += '.cc'
+  
+  if not debug:
+    lines = simulationContents.splitlines(True)
+    for lineNumber, line in enumerate(lines[:]):
+      if '_XPDEINT_CORRECT_MISSING_LINE_NUMBER_' in line:
+        lines[lineNumber] = line.replace('_XPDEINT_CORRECT_MISSING_LINE_NUMBER_', '%i "%s"' % (lineNumber+2, sourceFilename))
+    simulationContents = ''.join(lines)
+  
+  file(sourceFilename, 'w').write(simulationContents)
+  
+  print "... done"
+  
+  if debug:
+    globalNameSpace['simulationUselib'].add('debug')
+    globalNameSpace['simulationUselib'].discard('vectorise')
+  
+  if not globalNameSpace['simulationUselib'].intersection(['debug']):
+    globalNameSpace['simulationUselib'].add('optimise')
+  
+  buildKWs = {
+    'includes': [resource_filename(__name__, 'includes').replace(' ', r'\ ')],
+    'uselib': list(globalNameSpace['simulationUselib']),
+  }
+  
+  userCFlags = None
+  if 'CFlags' in globalNameSpace['features']:
+    userCFlags = str(globalNameSpace['features']['CFlags'].cflags())
+  
+  variant = globalNameSpace['simulationBuildVariant']
+  if not variant:
+    variant.add('default')
+  
+  assert len(variant) == 1
+  
+  if compileScript:
+      print "Compiling simulation..."
+    
+      result = Configuration.run_build(
+        sourceFilename,
+        sourceFilename[:-3], # strip of trailing '.cc'
+        variant = anyObject(variant),
+        buildKWs = buildKWs,
+        verbose = verbose,
+        userCFlags = userCFlags
+      )
+      
+      if result == 0:
+        print "... done. Type './%s' to run." % globalNameSpace['simulationName']
+      else:
+        print "\n\nFATAL ERROR: Failed to compile. Check warnings and errors. The most important will be first."
+      
+      return result
+  
+
+if __name__ == "__main__":
+  sys.exit(main())
diff --git a/xpdeint/support/Makefile b/xpdeint/support/Makefile
new file mode 100644
index 0000000..47fee55
--- /dev/null
+++ b/xpdeint/support/Makefile
@@ -0,0 +1,11 @@
+
+all: xpdeint.rng
+
+xpdeint.rng: xpdeint.rnc
+	java -jar trang.jar xpdeint.rnc xpdeint.rng
+
+
+clean:
+	@rm xpdeint.rng
+
+.PHONY: all clean
diff --git a/xpdeint/support/trang.jar b/xpdeint/support/trang.jar
new file mode 100755
index 0000000..a14cb9f
Binary files /dev/null and b/xpdeint/support/trang.jar differ
diff --git a/xpdeint/support/wscript b/xpdeint/support/wscript
new file mode 100755
index 0000000..6ea0314
--- /dev/null
+++ b/xpdeint/support/wscript
@@ -0,0 +1,604 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+wscript
+
+The waf script to configure compilation of generated simulations.
+
+Created by Graham Dennis on 2009-03-01.
+
+Copyright (c) 2009-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+
+import os, sys, platform
+
+from waflib import Task, TaskGen
+from waflib.TaskGen import feature
+
+def options(opt):
+    # options provided by modules
+    opt.load('compiler_cxx')
+
+def optionAsList(var):
+    if isinstance(var, str):
+        return [var]
+    elif isinstance(var, list):
+        return var
+    assert False
+
+
+# This doesn't have great performance, but it's a small dataset we'll be working on
+def append_to_unordered_set(dest, value):
+    if value in dest:
+        dest.remove(value)
+    dest.append(value)
+
+def expand_dependencies(dest, uselib, env):
+    append_to_unordered_set(dest, uselib)
+    if not uselib in env.uselib_dependencies: return
+    expand_dependencies_of_list(dest, env.uselib_dependencies[uselib], env)
+
+def expand_dependencies_of_list(dest, uselibs, env):
+    for uselib in uselibs[:]:
+        expand_dependencies(dest, uselib, env)
+
+
+def configure(conf):
+    env = conf.env
+    
+    env.uselib_dependencies = {}
+    
+    def _check_cxx(**KWs):
+        # Don't execute when cross-compiling
+        KWs['execute'] = not conf.env['is_cross_compile']
+        KWs['mandatory'] = False
+        KWs['ENVIRONMENT_NAME'] = conf.env['ENVIRONMENT_NAME']
+        
+        if 'cxxflags' in KWs:
+          cxxflags = optionAsList(KWs['cxxflags'])
+          
+          linkflags = []
+          if 'linkflags' in KWs:
+            linkflags.extend(optionAsList(KWs['linkflags']))
+          KWs['linkflags'] = linkflags
+        
+        original_uselib = []
+
+        if 'uselib' in KWs:
+            current_uselib = optionAsList(KWs['uselib'])
+            original_uselib = current_uselib[:]
+            expand_dependencies_of_list(current_uselib, original_uselib[:], conf.env)
+            KWs['uselib'] = current_uselib
+        
+        result = conf.check_cxx(**KWs) not in [None, False]
+        if result and 'uselib_store' in KWs:
+            conf.env.append_unique('uselib', KWs['uselib_store'])
+            if original_uselib:
+                current_uselib_dep = conf.env.uselib_dependencies.setdefault(KWs['uselib_store'], [])
+                for uselib in original_uselib:
+                    if uselib == KWs['uselib_store']: continue
+                    append_to_unordered_set(current_uselib_dep, uselib)
+        return result
+    
+    def try_options(uselib_store, kwOptions, common = None):
+        common = common or {}
+        for kws in kwOptions:
+            predicate = kws.get('predicate', True)
+            if callable(predicate):
+              predicate = predicate()
+            if not predicate: continue
+            
+            allKWs = common.copy()
+            allKWs.update(kws)
+            if check_cxx(uselib_store=uselib_store, **allKWs):
+                return True
+        return False
+    
+    def check_cxx(**KWs):
+        # Prefer a static library over a dynamic one if available
+        if ('lib' not in KWs) or ('uselib_store' not in KWs) or ('_skip' in KWs):
+            return _check_cxx(**KWs)
+        
+        lib = KWs['lib']
+        del KWs['lib']
+        uselib_store = KWs['uselib_store']
+        KWs['_skip'] = True
+        del KWs['uselib_store']
+        options = [
+            {'stlib': lib,   'msg': "%s (static library)" % KWs['msg'], 'errmsg': "no (will try dynamic library instead)"},
+            {'lib'  : lib,   'msg': "%s (dynamic library)" % KWs['msg']},
+        ]
+        if not conf.env['STLIB_MARKER']:
+            options = [
+            # On systems like Mac OS X, it seems we can't force the linker to prefer static libraries over dynamic ones
+            # Except of course by including them by listing the full path.
+                {'lib': lib}
+            ]
+        if not 'errmsg' in KWs:
+            KWs['errmsg'] = "no (it's optional anyway)"
+            
+        return try_options(uselib_store, options, KWs)
+    
+    
+    def configure_compiler():
+        conf.load('compiler_cxx')
+        
+        conf.check_cxx(
+            msg = "Checking whether the compiler works",
+            errmsg = "The compiler doesn't seem to work"
+        )
+        
+        conf.check_cxx(
+            msg = "Checking that we have a C++ compiler",
+            fragment = """
+            #include <iostream>
+            int main() { return 0; }
+            """,
+            errmsg = "Please specify a C++ compiler."
+        )
+
+        conf.env['is_cross_compile'] = not conf.check_cxx(
+            msg = "Checking whether we are cross-compiling",
+            okmsg = "no",
+            errmsg = "maybe, assuming we are",
+            execute = True,
+            mandatory = False,
+        )
+        
+        # If we have a static library marker, try to link the simulation statically for performance.
+        if conf.env['STLIB_MARKER']:
+            conf.env['FINAL_LINK_VAR'] = conf.env['STLIB_MARKER']
+            result = conf.check_cxx(
+                msg = "Checking whether we can link to only static libraries",
+                errmsg = "no (will use dynamic libraries)",
+                mandatory = False,
+                execute = not conf.env['is_cross_compile']
+            )
+            if not result:
+                del conf.env['FINAL_LINK_VAR']
+        
+        
+        if conf.env['CXX_NAME'] == 'gcc':
+            machine_optimisations = [
+                {
+                    "msg": "Trying to make compiler optimise for this machine",
+                    "cxxflags": "-march=native",
+                },
+                {
+                    "msg": "Checking for Altivec",
+                    "cxxflags": ['-mpim-altivec', '-maltivec'],
+                },
+                {
+                    "msg": "Checking for AVX",
+                    "cxxflags": ["-mavx", "-msse3", "-msse2", "-msse", "-mfpmath=sse"],
+                },
+                {
+                    "msg": "Checking for SSE3",
+                    "cxxflags": ["-msse3", "-msse2", "-msse", "-mfpmath=sse"],
+                },
+                {
+                    "msg": "Checking for SSE2",
+                    "cxxflags": ["-msse2", "-msse", "-mfpmath=sse"],
+                },
+                {
+                    "msg": "Checking for SSE",
+                    "cxxflags": ["-msse", "-mfpmath=sse"]
+                }
+            ]
+            
+            try_options('optimise', machine_optimisations,
+                { # This is so that the compiler will generate SIMD instructions
+                  # If the linker / assembler doesn't support those instructions,
+                  # Then we'll pick it up this way.
+                    "fragment": "int main() { double __volatile__ a = 1.0; a *= 1.03; return 0; }"
+                }
+            )
+            
+            check_cxx(
+                cxxflags='-mtune=native',
+                uselib_store="optimise",
+                msg = "Trying to make compiler tune for this machine"
+            )
+            
+            optimisation_flags = [
+                '-O3', '-ffast-math', '-funroll-all-loops', '-fomit-frame-pointer', '-falign-loops', '-fstrict-aliasing', '-momit-leaf-frame-pointer'
+            ]
+            
+            for optimisation_flag in optimisation_flags:
+                check_cxx(
+                    cxxflags=optimisation_flag,
+                    uselib_store="optimise"
+                )
+            
+            check_cxx(
+                cxxflags=['-fno-unsafe-math-optimizations', '-fno-finite-math-only'],
+                uselib_store="safe_math",
+                uselib='optimise',
+                msg = "Checking for cautious math flags"
+            )
+            
+            # Needed to silence some warnings on Mac OS X related to FFTW and AVX
+            if sys.platform == 'darwin':
+                env.append_unique('LINKFLAGS', ['-Wl,-no_compact_unwind'])
+                env.append_unique('CXXFLAGS', ['-mmacosx-version-min=%s' % '.'.join(platform.mac_ver()[0].split('.')[:2])])
+            
+            check_cxx(
+                cxxflags='-ftree-vectorize',
+                uselib_store='vectorise',
+                uselib="optimise",
+                msg = "Checking for Autovectorisation"
+            )
+            
+            check_cxx(
+                cxxflags='-fopenmp',
+                linkflags="-fopenmp",
+                uselib_store='openmp',
+                msg = "Checking for OpenMP"
+            )
+            
+            check_cxx(
+                cxxflags="-pthread",
+                linkflags="-pthread",
+                uselib_store="threads",
+                msg = "Checking for pthreads",
+            )
+        elif conf.env['CXX_NAME'] == 'icc':
+            compiler_optimisations = [
+                {
+                    "msg": "Checking for the 'go fast' compiler option",
+                    "cxxflags": ['-fast', '-ffast-math', '-complex-limited-range', '-fomit-frame-pointer'],
+                    "linkflags": ["-fast"],
+                },
+                {
+                    "msg": "Checking for fallback optimisation flags",
+                    "cxxflags": ['-O3', '-ipo', '-ffast-math', '-complex-limited-range', '-fomit-frame-pointer'],
+                    "linkflags": ['-O3'],
+                },
+                {
+                    "msg": "Checking safe optimisation flags",
+                    "cxxflags": "-O3",
+                    "linkflags": "-O3"
+                }
+            ]
+            
+            try_options('optimise', compiler_optimisations)
+            
+            machine_optimisations = [
+                {
+                    "msg": "Trying to optimise for SSE4",
+                    "cxxflags": "-xS",
+                },
+                {
+                    "msg": "Trying to optimise for SSSE3",
+                    "cxxflags": "-xT",
+                },
+                {
+                    "msg": "Trying to optimise for SSE3",
+                    "cxxflags": "-xP",
+                },
+                {
+                    "msg": "Trying to optimise for SSE2",
+                    "cxxflags": "-xN",
+                },
+            ]
+            
+            try_options('optimise', machine_optimisations)
+            
+            check_cxx(
+                cxxflags="-fma",
+                uselib_store="optimise",
+                msg = "Trying to fuse multiply and add instructions"
+            )
+            
+            check_cxx(
+                cxxflags = ["-fp-model", "precise"],
+                uselib_store="safe_math",
+                uselib="optimise",
+                msg = "Checking for cautious math flags"
+            )
+            
+            check_cxx(
+                cxxflags = "-vec",
+                uselib_store="vectorise",
+                uselib="optimise",
+                msg = "Checking for Autovectorisation"
+            )
+            
+            check_cxx(
+                cxxflags='-openmp',
+                linkflags="-openmp",
+                uselib_store="openmp",
+                msg = "Checking for OpenMP"
+            )
+            
+            check_cxx(
+                cxxflags="-pthread",
+                linkflags="-pthread",
+                uselib_store="threads",
+                msg = "Checking for pthreads"
+            )
+        
+        
+        check_cxx(
+            cxxflags="-g",
+            uselib_store="debug",
+            msg = "Checking for compiler debug flags"
+        )
+        
+        # Check for srandomdev, used for runtime initialisation of random number generators
+        check_cxx(
+            header_name='stdlib.h',
+            function_name='srandomdev',
+            defines = 'HAVE_SRANDOMDEV',
+            uselib_store = 'randomisation_seeding',
+            msg = "Checking for srandomdev"
+        )
+        
+        # Check for the availability of /dev/urandom
+        check_cxx(
+            defines = 'HAVE_DEV_URANDOM',
+            uselib_store = 'randomisation_seeding',
+            fragment= '''
+                extern "C" {
+                #include <stdio.h>
+                	int main() {
+                        FILE *fp = fopen("/dev/urandom", "r");
+                        return fp == NULL;
+                    }
+                }
+            ''',
+            msg = "Checking for /dev/urandom",
+        )
+        
+        # Check for zlib, used by hdf5
+        check_cxx(
+            lib='z',
+            function_name="deflate",
+            header_name="zlib.h",
+            uselib_store="zlib",
+            msg = "Checking for zlib"
+        )
+        
+        check_cxx(
+            lib='hdf5',
+            header_name="hdf5.h",
+            function_name="H5check_version",
+            uselib_store="hdf5",
+            uselib="zlib" if "zlib" in conf.env['uselib'] else [],
+            msg = "Checking for HDF5",
+        )
+        
+        if 'hdf5' in conf.env['uselib']:
+            check_cxx(
+                lib='hdf5_hl',
+                defines='HAVE_HDF5_HL',
+                header_name=['hdf5.h', 'hdf5_hl.h'],
+                function_name='H5DSset_scale',
+                uselib_store='hdf5',
+                uselib='hdf5',
+                msg = "Checking for HDF5 High-level library",
+            )
+            
+            # We need to reverse the library order because hdf5_hl depends on hdf5
+            if conf.env['STLIB_hdf5']: conf.env['STLIB_hdf5'] = list(reversed(conf.env.get_flat('STLIB_hdf5').split()))
+            if conf.env['SHLIB_hdf5']: conf.env['SHLIB_hdf5'] = list(reversed(conf.env.get_flat('SHLIB_hdf5').split()))
+            
+            check_cxx(
+                header_name=['hdf5.h'],
+                defines='HAVE_H5LEXISTS',
+                function_name='H5Lexists',
+                uselib = 'hdf5',
+                uselib_store = 'hdf5',
+            )
+        
+        check_cxx(
+            lib='xmds',
+            uselib_store='xmds',
+            msg = "Checking for libxmds"
+        )
+        
+        # Check for system-specific features
+        if sys.platform == 'darwin':
+            check_cxx(
+                framework="CoreFoundation",
+                uselib_store="system",
+                msg = "Checking for Apple CoreFoundation framework",
+            )
+            check_cxx(
+                framework="IOKit",
+                uselib_store="system",
+                uselib="system",
+                msg = "Checking for Apple IOKit framework",
+            )
+        
+        
+        
+        check_cxx(
+            lib=["iomp", "vml"],
+            header_name='mkl_vsl.h',
+            function_name='vslNewStream',
+            uselib_store='mkl_vsl',
+            msg = "Checking for Intel's Vector Math Library"
+        )
+        
+        # The max-inline-insns-single=1800 option works for gcc but not icc, so try a series of options to see what works
+        dsfmt_optimisations = [
+          {
+              "cxxflags": ["-finline-functions", "--param", "max-inline-insns-single=1800"],
+              "msg": "Checking aggressive dSFMT compile flags",
+          },
+          {
+              "cxxflags": ["-finline-functions"],
+              "msg": "Checking safer dSFMT compile flags",
+          },
+          {
+              "cxxflags": [],
+              "msg": "Checking dSFMT compile flags",
+          },
+        ];
+        
+        try_options('dsfmt', dsfmt_optimisations)
+        
+        # Find CBLAS
+        cblas_options = [
+            {# Intel MKL
+                'defines': 'CBLAS_MKL',
+                'lib': ['mkl_intel_lp64', 'mkl_intel_thread', 'mkl_core'],
+                'uselib': 'openmp',
+                'header_name': 'mkl.h',
+                'msg': "Checking for Intel's Math Kernel Library",
+            },
+            {# Apple Accelerate
+                'defines': 'CBLAS_VECLIB',
+                'framework_name': 'Accelerate',
+                'msg': "Checking for Apple's Accelerate framework",
+                'predicate': sys.platform == 'darwin'
+            },
+            {# ATLAS CBLAS
+                'defines': 'CBLAS_ATLAS',
+                'lib': 'cblas',
+                'fragment': '''
+                    extern "C" {
+                    #include <cblas.h>
+                    	int main() {
+                    	    void *p=(void*)(cblas_dgemm);
+                    	    return 0;
+                        }
+                    }
+                ''',
+                'msg': "Checking for ATLAS's CBLAS."
+            },
+            {# GSL CBLAS
+                'defines': 'CBLAS_GSL',
+                'lib': 'gslcblas',
+                'header_name': 'gsl/gsl_cblas.h',
+                'msg': "Checking for GSL's CBLAS",
+            }
+        ]
+        cblas_common = {
+            'function_name': 'cblas_dgemm',
+        }
+        
+        try_options('cblas', cblas_options, cblas_common)
+        
+        check_cxx(
+            lib='gsl',
+            uselib='cblas',
+            uselib_store='gsl',
+            header_name='gsl/gsl_sf.h',
+            function_name='gsl_sf_bessel_jl',
+            msg="Checking for GSL"
+        )
+        
+        check_cxx(
+            lib='fftw3',
+            header_name='fftw3.h',
+            function_name='fftw_execute',
+            uselib_store='fftw3',
+            msg = "Checking for FFTW3",
+            errmsg = "Couldn't find FFTW3.  Please install."
+        )
+        
+        check_cxx(
+            lib='fftw3f',
+            header_name='fftw3.h',
+            function_name='fftwf_execute',
+            uselib_store='fftw3f',
+            msg = "Checking for single-precision FFTW3"
+        )
+        
+        if 'fftw3' in conf.env['uselib']:
+            check_cxx(
+                lib='fftw3_threads',
+                header_name='fftw3.h',
+                function_name='fftw_init_threads',
+                uselib_store='fftw3_threads',
+                uselib=['fftw3', 'threads'],
+                msg = "Checking for threading support in FFTW3",
+            )
+            check_cxx(
+                lib='fftw3_omp',
+                header_name='fftw3.h',
+                function_name='fftw_init_threads',
+                uselib_store='fftw3_omp',
+                uselib=['fftw3', 'openmp'],
+                msg = "Checking for OpenMP support in FFTW3",
+            )
+        if 'fftw3f' in conf.env['uselib']:
+            check_cxx(
+                lib='fftw3f_threads',
+                header_name='fftw3.h',
+                function_name='fftwf_init_threads',
+                uselib_store='fftw3f_threads',
+                uselib=['fftw3f', 'threads'],
+                msg = "Checking for threading support in single-precision FFTW3",
+            )
+            check_cxx(
+                lib='fftw3f_omp',
+                header_name='fftw3.h',
+                function_name='fftwf_init_threads',
+                uselib_store='fftw3f_omp',
+                uselib=['fftw3f', 'openmp'],
+                msg = "Checking for OpenMP support in single-precision FFTW3",
+            )
+        
+        # Destroy all those unnecessary #define's generated by waf.
+        # Any we actually want will be attached to a uselib var.
+        del conf.env["DEFINES"]
+    
+    print
+    print "Configuring for single-process scripts..."
+    conf.setenv('default', env)
+    conf.env['ENVIRONMENT_NAME'] = 'default'
+    configure_compiler()
+    
+    # Stuff for MPI variant
+    print
+    print "Configuring for MPI scripts..."
+    conf.setenv('mpi', env)
+    conf.env['ENVIRONMENT_NAME'] = 'mpi'
+    if conf.find_program('mpic++', var='MPICXX', mandatory = False):
+        
+        conf.env['CXX'] = conf.env['MPICXX']
+        conf.env['LINK_CXX'] = conf.env['MPICXX']
+        
+        configure_compiler()
+        
+        if 'fftw3' in conf.env['uselib']:
+            check_cxx(
+                lib='fftw3_mpi',
+                header_name='fftw3.h fftw3-mpi.h',
+                function_name='fftw_mpi_init',
+                uselib_store='fftw3_mpi',
+                uselib='fftw3',
+                msg = "Checking for FFTW3 with MPI"
+            )
+        if 'fftw3f' in conf.env['uselib']:
+            check_cxx(
+                lib='fftw3f_mpi',
+                header_name='fftw3.h fftw3-mpi.h',
+                function_name='fftwf_mpi_init',
+                uselib_store='fftw3f_mpi',
+                uselib='fftw3f',
+                msg = "Checking for single-precision FFTW3 with MPI"
+            )
+        
+        del conf.env["DEFINES"]
+    else:
+        print "MPI not found. No scripts using MPI can be compiled on this system."
+        conf.setenv('default', env)
+        del conf.all_envs['mpi']
+    
diff --git a/xpdeint/support/xpdeint.rnc b/xpdeint/support/xpdeint.rnc
new file mode 100644
index 0000000..20c732c
--- /dev/null
+++ b/xpdeint/support/xpdeint.rnc
@@ -0,0 +1,280 @@
+start = Simulation
+Simulation = element simulation {
+    attribute xmds-version { "2" },
+    (   
+        element name { text }
+        | element author { text }
+        | element description { text }
+        | Testing
+        | Features
+        | Geometry
+        | Driver
+        | Vector
+        | ComputedVector
+        | NoiseVector
+        | Sequence
+        | Output
+    )+
+}
+
+Testing = element testing {
+    ( 
+        element command_line { text }
+        | Arguments
+        | XSILFile
+        | InputXSILFile
+    )+
+}
+
+XSILFile = element xsil_file {
+    attribute name { text }
+    , attribute expected { text }
+    , attribute absolute_tolerance { text }?
+    , attribute relative_tolerance { text }?
+    , element moment_group {
+        attribute number { text },
+        attribute relative_tolerance { text }?,
+        attribute absolute_tolerance { text }?
+    }?
+}
+
+InputXSILFile = element input_xsil_file {
+    attribute name { text }
+}
+
+# Features
+Features = element features {
+    (
+        element auto_vectorise    { Bool | empty }
+        | element benchmark       { Bool | empty }
+        | element bing            { Bool | empty }
+        | element cflags          { text }
+        | element chunked_output  { attribute size  {text} }
+        | element diagnostics     { Bool | empty }
+        | element error_check     { Bool | empty }
+        | element halt_non_finite { Bool | empty }
+        | element openmp          { attribute threads {text}?, (Bool | empty) }
+        | Arguments
+        | element globals { text }
+        | element validation { 
+              attribute kind { text }
+              , empty
+          }
+        | FFTW
+        | element precision { text }
+    )+
+}
+
+Bool = "yes" | "no"
+
+Arguments = element arguments {
+    attribute append_args_to_output_filename { Bool }?
+    , Argument*
+    , text?
+}
+
+Argument = element argument {
+    attribute name { text }
+    , attribute type { text }
+    , attribute default_value { text }
+    , empty
+}
+
+FFTW = element fftw {
+    attribute plan { text }?
+    , attribute threads { text }?
+    , empty
+}
+
+# Geometry
+Geometry = element geometry {
+    element propagation_dimension { text }
+    , element transverse_dimensions { Dimension+ }?
+}
+
+Dimension = element dimension {
+    attribute name { text }
+    , attribute type { text }?
+    , attribute lattice { text }?
+    , attribute spectral_lattice { text}?
+    , ( attribute domain { text } | attribute length_scale { text } )
+    , attribute transform { text }?
+    , attribute order { text }?
+    , attribute aliases { text }?
+    , attribute volume_prefactor { text }?
+    , empty
+}
+
+# Driver
+Driver = element driver {
+    attribute name { text }
+    , attribute kind { text }?
+    , attribute paths { text }?
+    , empty
+}
+
+# Vector stuff
+VectorCommon = 
+    attribute name { text }
+    , attribute dimensions { text }?
+    , attribute initial_space { text }?
+	, attribute initial_basis { text }?
+    , attribute type { text }?
+    , element components { text }
+
+
+Dependencies = element dependencies {
+    attribute basis { text }?
+    , text
+}
+
+Vector = element vector {
+    VectorCommon
+    , element initialisation {
+        attribute kind { text }?
+        , attribute geometry_matching_mode { text }?
+        , element filename { 
+            attribute group { text }?
+            , text
+            }?
+        , ( text
+        & Dependencies? )
+    }?
+}
+
+ComputedVector = element computed_vector {
+    VectorCommon
+    , element evaluation {
+        Dependencies?
+        & text
+    }
+}
+
+NoiseVector = element noise_vector {
+    VectorCommon
+    , attribute kind { text },
+    attribute mean { text }?,
+    attribute mean-rate { text }?,
+    attribute mean-density { text }?,
+    attribute method { text }?,
+    attribute seed { text }?
+}
+
+# Sequence
+Sequence = element sequence {
+    attribute cycles { text }?
+    , (   Integrate 
+        | Filter
+        | Breakpoint
+        | Sequence
+      )*
+}
+
+Integrate = element integrate {
+    attribute algorithm { text }
+    , attribute interval { text }
+    , attribute steps { text }?
+    , attribute tolerance { text }?
+    , attribute iterations { text }?
+    , attribute cutoff { text }?
+    , attribute home_space { text }?
+    , (
+        element samples { text }
+        | Filters
+        | ComputedVector
+        | Operators
+      )+
+}
+
+Filters = element filters {
+    attribute where { text }?
+    , Filter+
+}
+
+Operators = element operators {
+    attribute dimensions { text }?
+    , (
+        Operator
+        | element integration_vectors {
+            attribute basis { text }?
+            , text
+          }
+        | Dependencies
+        | text
+      )+
+}
+
+Operator = element operator {
+    IPEXOperatorContents
+    | FunctionsOperatorContents
+    | CrossPropagationOperatorContents
+}
+
+IPEXOperatorContents = 
+    attribute kind { "ip" | "ex" | "IP" | "EX" }
+    , attribute constant { Bool }?
+    , attribute basis { text }?
+    , attribute type { text }?
+    , ( element operator_names { text }
+    & Dependencies?
+    & text )
+
+FunctionsOperatorContents = 
+    attribute kind { "functions" }
+    , text
+
+CrossPropagationOperatorContents = 
+    attribute kind { "cross_propagation" }
+    , attribute algorithm { text }
+    , attribute propagation_dimension { text }
+    , attribute iterations { text}?
+    , ( 
+        element integration_vectors { text }
+        | Dependencies
+        | element boundary_condition {
+            attribute kind { text }
+            , Dependencies?
+            , text
+        }
+        | Operator
+        | text
+      )+
+
+Filter = element filter {
+    attribute name { text }?
+    & Dependencies?
+    & text
+}
+
+Breakpoint = element breakpoint {
+    attribute filename { text }?
+    , attribute format { text }?
+    , Dependencies
+}
+
+SamplingContents = 
+  attribute initial_sample { Bool } ?
+  , attribute basis { text }?
+  , (
+      ComputedVector
+      | Operator
+      | element moments { text }
+      | Dependencies
+      | text
+  )+
+
+
+Output = element output {
+    attribute format { text }?
+    , attribute filename { text }?
+    , (
+        element group {
+          element sampling {
+            SamplingContents
+          }
+        }
+        | element sampling_group {
+            SamplingContents
+          }
+      )*
+}
diff --git a/xpdeint/support/xpdeint.rng b/xpdeint/support/xpdeint.rng
new file mode 100644
index 0000000..5d3ecaf
--- /dev/null
+++ b/xpdeint/support/xpdeint.rng
@@ -0,0 +1,554 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns="http://relaxng.org/ns/structure/1.0">
+  <start>
+    <ref name="Simulation"/>
+  </start>
+  <define name="Simulation">
+    <element name="simulation">
+      <attribute name="xmds-version">
+        <value>2</value>
+      </attribute>
+      <oneOrMore>
+        <choice>
+          <element name="name">
+            <text/>
+          </element>
+          <element name="author">
+            <text/>
+          </element>
+          <element name="description">
+            <text/>
+          </element>
+          <ref name="Testing"/>
+          <ref name="Features"/>
+          <ref name="Geometry"/>
+          <ref name="Driver"/>
+          <ref name="Vector"/>
+          <ref name="ComputedVector"/>
+          <ref name="NoiseVector"/>
+          <ref name="Sequence"/>
+          <ref name="Output"/>
+        </choice>
+      </oneOrMore>
+    </element>
+  </define>
+  <define name="Testing">
+    <element name="testing">
+      <oneOrMore>
+        <choice>
+          <element name="command_line">
+            <text/>
+          </element>
+          <ref name="Arguments"/>
+          <ref name="XSILFile"/>
+          <ref name="InputXSILFile"/>
+        </choice>
+      </oneOrMore>
+    </element>
+  </define>
+  <define name="XSILFile">
+    <element name="xsil_file">
+      <attribute name="name"/>
+      <attribute name="expected"/>
+      <optional>
+        <attribute name="absolute_tolerance"/>
+      </optional>
+      <optional>
+        <attribute name="relative_tolerance"/>
+      </optional>
+      <optional>
+        <element name="moment_group">
+          <attribute name="number"/>
+          <optional>
+            <attribute name="relative_tolerance"/>
+          </optional>
+          <optional>
+            <attribute name="absolute_tolerance"/>
+          </optional>
+        </element>
+      </optional>
+    </element>
+  </define>
+  <define name="InputXSILFile">
+    <element name="input_xsil_file">
+      <attribute name="name"/>
+    </element>
+  </define>
+  <!-- Features -->
+  <define name="Features">
+    <element name="features">
+      <oneOrMore>
+        <choice>
+          <element name="auto_vectorise">
+            <choice>
+              <ref name="Bool"/>
+              <empty/>
+            </choice>
+          </element>
+          <element name="benchmark">
+            <choice>
+              <ref name="Bool"/>
+              <empty/>
+            </choice>
+          </element>
+          <element name="bing">
+            <choice>
+              <ref name="Bool"/>
+              <empty/>
+            </choice>
+          </element>
+          <element name="cflags">
+            <text/>
+          </element>
+          <element name="chunked_output">
+            <attribute name="size"/>
+          </element>
+          <element name="diagnostics">
+            <choice>
+              <ref name="Bool"/>
+              <empty/>
+            </choice>
+          </element>
+          <element name="error_check">
+            <choice>
+              <ref name="Bool"/>
+              <empty/>
+            </choice>
+          </element>
+          <element name="halt_non_finite">
+            <choice>
+              <ref name="Bool"/>
+              <empty/>
+            </choice>
+          </element>
+          <element name="openmp">
+            <optional>
+              <attribute name="threads"/>
+            </optional>
+            <choice>
+              <ref name="Bool"/>
+              <empty/>
+            </choice>
+          </element>
+          <ref name="Arguments"/>
+          <element name="globals">
+            <text/>
+          </element>
+          <element name="validation">
+            <attribute name="kind"/>
+            <empty/>
+          </element>
+          <ref name="FFTW"/>
+          <element name="precision">
+            <text/>
+          </element>
+        </choice>
+      </oneOrMore>
+    </element>
+  </define>
+  <define name="Bool">
+    <choice>
+      <value>yes</value>
+      <value>no</value>
+    </choice>
+  </define>
+  <define name="Arguments">
+    <element name="arguments">
+      <optional>
+        <attribute name="append_args_to_output_filename">
+          <ref name="Bool"/>
+        </attribute>
+      </optional>
+      <zeroOrMore>
+        <ref name="Argument"/>
+      </zeroOrMore>
+      <optional>
+        <text/>
+      </optional>
+    </element>
+  </define>
+  <define name="Argument">
+    <element name="argument">
+      <attribute name="name"/>
+      <attribute name="type"/>
+      <attribute name="default_value"/>
+      <empty/>
+    </element>
+  </define>
+  <define name="FFTW">
+    <element name="fftw">
+      <optional>
+        <attribute name="plan"/>
+      </optional>
+      <optional>
+        <attribute name="threads"/>
+      </optional>
+      <empty/>
+    </element>
+  </define>
+  <!-- Geometry -->
+  <define name="Geometry">
+    <element name="geometry">
+      <element name="propagation_dimension">
+        <text/>
+      </element>
+      <optional>
+        <element name="transverse_dimensions">
+          <oneOrMore>
+            <ref name="Dimension"/>
+          </oneOrMore>
+        </element>
+      </optional>
+    </element>
+  </define>
+  <define name="Dimension">
+    <element name="dimension">
+      <attribute name="name"/>
+      <optional>
+        <attribute name="type"/>
+      </optional>
+      <optional>
+        <attribute name="lattice"/>
+      </optional>
+      <optional>
+        <attribute name="spectral_lattice"/>
+      </optional>
+      <choice>
+        <attribute name="domain"/>
+        <attribute name="length_scale"/>
+      </choice>
+      <optional>
+        <attribute name="transform"/>
+      </optional>
+      <optional>
+        <attribute name="order"/>
+      </optional>
+      <optional>
+        <attribute name="aliases"/>
+      </optional>
+      <optional>
+        <attribute name="volume_prefactor"/>
+      </optional>
+      <empty/>
+    </element>
+  </define>
+  <!-- Driver -->
+  <define name="Driver">
+    <element name="driver">
+      <attribute name="name"/>
+      <optional>
+        <attribute name="kind"/>
+      </optional>
+      <optional>
+        <attribute name="paths"/>
+      </optional>
+      <empty/>
+    </element>
+  </define>
+  <!-- Vector stuff -->
+  <define name="VectorCommon">
+    <attribute name="name"/>
+    <optional>
+      <attribute name="dimensions"/>
+    </optional>
+    <optional>
+      <attribute name="initial_space"/>
+    </optional>
+    <optional>
+      <attribute name="initial_basis"/>
+    </optional>
+    <optional>
+      <attribute name="type"/>
+    </optional>
+    <element name="components">
+      <text/>
+    </element>
+  </define>
+  <define name="Dependencies">
+    <element name="dependencies">
+      <optional>
+        <attribute name="basis"/>
+      </optional>
+      <text/>
+    </element>
+  </define>
+  <define name="Vector">
+    <element name="vector">
+      <ref name="VectorCommon"/>
+      <optional>
+        <element name="initialisation">
+          <optional>
+            <attribute name="kind"/>
+          </optional>
+          <optional>
+            <attribute name="geometry_matching_mode"/>
+          </optional>
+          <optional>
+            <element name="filename">
+              <optional>
+                <attribute name="group"/>
+              </optional>
+              <text/>
+            </element>
+          </optional>
+          <interleave>
+            <text/>
+            <optional>
+              <ref name="Dependencies"/>
+            </optional>
+          </interleave>
+        </element>
+      </optional>
+    </element>
+  </define>
+  <define name="ComputedVector">
+    <element name="computed_vector">
+      <ref name="VectorCommon"/>
+      <element name="evaluation">
+        <interleave>
+          <optional>
+            <ref name="Dependencies"/>
+          </optional>
+          <text/>
+        </interleave>
+      </element>
+    </element>
+  </define>
+  <define name="NoiseVector">
+    <element name="noise_vector">
+      <ref name="VectorCommon"/>
+      <attribute name="kind"/>
+      <optional>
+        <attribute name="mean"/>
+      </optional>
+      <optional>
+        <attribute name="mean-rate"/>
+      </optional>
+      <optional>
+        <attribute name="mean-density"/>
+      </optional>
+      <optional>
+        <attribute name="method"/>
+      </optional>
+      <optional>
+        <attribute name="seed"/>
+      </optional>
+    </element>
+  </define>
+  <!-- Sequence -->
+  <define name="Sequence">
+    <element name="sequence">
+      <optional>
+        <attribute name="cycles"/>
+      </optional>
+      <zeroOrMore>
+        <choice>
+          <ref name="Integrate"/>
+          <ref name="Filter"/>
+          <ref name="Breakpoint"/>
+          <ref name="Sequence"/>
+        </choice>
+      </zeroOrMore>
+    </element>
+  </define>
+  <define name="Integrate">
+    <element name="integrate">
+      <attribute name="algorithm"/>
+      <attribute name="interval"/>
+      <optional>
+        <attribute name="steps"/>
+      </optional>
+      <optional>
+        <attribute name="tolerance"/>
+      </optional>
+      <optional>
+        <attribute name="iterations"/>
+      </optional>
+      <optional>
+        <attribute name="cutoff"/>
+      </optional>
+      <optional>
+        <attribute name="home_space"/>
+      </optional>
+      <oneOrMore>
+        <choice>
+          <element name="samples">
+            <text/>
+          </element>
+          <ref name="Filters"/>
+          <ref name="ComputedVector"/>
+          <ref name="Operators"/>
+        </choice>
+      </oneOrMore>
+    </element>
+  </define>
+  <define name="Filters">
+    <element name="filters">
+      <optional>
+        <attribute name="where"/>
+      </optional>
+      <oneOrMore>
+        <ref name="Filter"/>
+      </oneOrMore>
+    </element>
+  </define>
+  <define name="Operators">
+    <element name="operators">
+      <optional>
+        <attribute name="dimensions"/>
+      </optional>
+      <oneOrMore>
+        <choice>
+          <ref name="Operator"/>
+          <element name="integration_vectors">
+            <optional>
+              <attribute name="basis"/>
+            </optional>
+            <text/>
+          </element>
+          <ref name="Dependencies"/>
+          <text/>
+        </choice>
+      </oneOrMore>
+    </element>
+  </define>
+  <define name="Operator">
+    <element name="operator">
+      <choice>
+        <ref name="IPEXOperatorContents"/>
+        <ref name="FunctionsOperatorContents"/>
+        <ref name="CrossPropagationOperatorContents"/>
+      </choice>
+    </element>
+  </define>
+  <define name="IPEXOperatorContents">
+    <attribute name="kind">
+      <choice>
+        <value>ip</value>
+        <value>ex</value>
+        <value>IP</value>
+        <value>EX</value>
+      </choice>
+    </attribute>
+    <optional>
+      <attribute name="constant">
+        <ref name="Bool"/>
+      </attribute>
+    </optional>
+    <optional>
+      <attribute name="basis"/>
+    </optional>
+    <optional>
+      <attribute name="type"/>
+    </optional>
+    <interleave>
+      <element name="operator_names">
+        <text/>
+      </element>
+      <optional>
+        <ref name="Dependencies"/>
+      </optional>
+      <text/>
+    </interleave>
+  </define>
+  <define name="FunctionsOperatorContents">
+    <attribute name="kind">
+      <value>functions</value>
+    </attribute>
+    <text/>
+  </define>
+  <define name="CrossPropagationOperatorContents">
+    <attribute name="kind">
+      <value>cross_propagation</value>
+    </attribute>
+    <attribute name="algorithm"/>
+    <attribute name="propagation_dimension"/>
+    <optional>
+      <attribute name="iterations"/>
+    </optional>
+    <oneOrMore>
+      <choice>
+        <element name="integration_vectors">
+          <text/>
+        </element>
+        <ref name="Dependencies"/>
+        <element name="boundary_condition">
+          <attribute name="kind"/>
+          <optional>
+            <ref name="Dependencies"/>
+          </optional>
+          <text/>
+        </element>
+        <ref name="Operator"/>
+        <text/>
+      </choice>
+    </oneOrMore>
+  </define>
+  <define name="Filter">
+    <element name="filter">
+      <interleave>
+        <optional>
+          <attribute name="name"/>
+        </optional>
+        <optional>
+          <ref name="Dependencies"/>
+        </optional>
+        <text/>
+      </interleave>
+    </element>
+  </define>
+  <define name="Breakpoint">
+    <element name="breakpoint">
+      <optional>
+        <attribute name="filename"/>
+      </optional>
+      <optional>
+        <attribute name="format"/>
+      </optional>
+      <ref name="Dependencies"/>
+    </element>
+  </define>
+  <define name="SamplingContents">
+    <optional>
+      <attribute name="initial_sample">
+        <ref name="Bool"/>
+      </attribute>
+    </optional>
+    <optional>
+      <attribute name="basis"/>
+    </optional>
+    <oneOrMore>
+      <choice>
+        <ref name="ComputedVector"/>
+        <ref name="Operator"/>
+        <element name="moments">
+          <text/>
+        </element>
+        <ref name="Dependencies"/>
+        <text/>
+      </choice>
+    </oneOrMore>
+  </define>
+  <define name="Output">
+    <element name="output">
+      <optional>
+        <attribute name="format"/>
+      </optional>
+      <optional>
+        <attribute name="filename"/>
+      </optional>
+      <zeroOrMore>
+        <choice>
+          <element name="group">
+            <element name="sampling">
+              <ref name="SamplingContents"/>
+            </element>
+          </element>
+          <element name="sampling_group">
+            <ref name="SamplingContents"/>
+          </element>
+        </choice>
+      </zeroOrMore>
+    </element>
+  </define>
+</grammar>
diff --git a/xpdeint/version.sh b/xpdeint/version.sh
new file mode 100755
index 0000000..86111ca
--- /dev/null
+++ b/xpdeint/version.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+# Find out the latest revision
+REVISION="\"HEAD\""
+if [ -d "../.svn" ]; then
+  REVISION=\""r`svn info . | sed -n 's/Revision: //p'`"\"
+elif [ -d "../.git" ]; then
+  REVISION=\""r`git log -1 | sed -n 's/.*xpdeint@\([0-9]*\).*/\1/p'`"\"
+  # If we don't have a revision, then we must have git commits after the last SVN revision.
+  # So mark the revision number as the last SVN revision with '+git' appended.
+  if [ "$REVISION" == "\"r\"" ]; then
+    REVISION=\""r`git log | grep git-svn-id | head -1 | sed -n 's/.*xpdeint@\([0-9]*\).*/\1/p'`+git"\"
+  fi
+elif [ -f "Version.py" ]; then
+  # File exists, let's not change the version
+  exit
+fi
+echo "#!/usr/bin/env python" > Version.py
+echo "# encoding: utf-8" >> Version.py
+echo "\"\"\"This is generated by the makefile via the shell program \'version.sh\'\"\"\"" >> Version.py
+echo "subversionRevisionString =$REVISION" >> Version.py
\ No newline at end of file
diff --git a/xpdeint/waf/waf-light b/xpdeint/waf/waf-light
new file mode 100755
index 0000000..5c2ab80
--- /dev/null
+++ b/xpdeint/waf/waf-light
@@ -0,0 +1,164 @@
+#!/usr/bin/env python
+# encoding: ISO8859-1
+# Thomas Nagy, 2005-2011
+
+"""
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+"""
+
+import os, sys
+
+VERSION="1.6.9"
+REVISION="x"
+INSTALL="x"
+C1='x'
+C2='x'
+cwd = os.getcwd()
+join = os.path.join
+
+if sys.hexversion<0x206000f:
+	raise ImportError('Python >= 2.6 is required to create the waf file')
+
+WAF='waf'
+def b(x):
+	return x
+if sys.hexversion>0x300000f:
+	WAF='waf3'
+	def b(x):
+		return x.encode()
+
+def err(m):
+	print(('\033[91mError: %s\033[0m' % m))
+	sys.exit(1)
+
+def unpack_wafdir(dir):
+	f = open(sys.argv[0],'rb')
+	c = 'corrupt archive (%d)'
+	while 1:
+		line = f.readline()
+		if not line: err('run waf-light from a folder containing waflib')
+		if line == b('#==>\n'):
+			txt = f.readline()
+			if not txt: err(c % 1)
+			if f.readline() != b('#<==\n'): err(c % 2)
+			break
+	if not txt: err(c % 3)
+	txt = txt[1:-1].replace(b(C1), b('\n')).replace(b(C2), b('\r'))
+
+	import shutil, tarfile
+	try: shutil.rmtree(dir)
+	except OSError: pass
+	try:
+		for x in ['Tools', 'extras']:
+			os.makedirs(join(dir, 'waflib', x))
+	except OSError:
+		err("Cannot unpack waf lib into %s\nMove waf into a writeable directory" % dir)
+
+	os.chdir(dir)
+	tmp = 't.bz2'
+	t = open(tmp,'wb')
+	t.write(txt)
+	t.close()
+
+	try:
+		t = tarfile.open(tmp)
+	except:
+		try:
+			os.system('bunzip2 t.bz2')
+			t = tarfile.open('t')
+			tmp = 't'
+		except:
+			os.chdir(cwd)
+			try: shutil.rmtree(dir)
+			except OSError: pass
+			err("Waf cannot be unpacked, check that bzip2 support is present")
+
+	for x in t: t.extract(x)
+	t.close()
+
+	for x in ['Tools', 'extras']:
+		os.chmod(join('waflib',x), 493)
+
+	if sys.hexversion<0x300000f:
+		sys.path = [join(dir, 'waflib')] + sys.path
+		import fixpy2
+		fixpy2.fixdir(dir)
+
+	os.unlink(tmp)
+	os.chdir(cwd)
+
+	try: dir = unicode(dir, 'mbcs')
+	except: pass
+	try:
+		from ctypes import windll
+		windll.kernel32.SetFileAttributesW(dir, 2)
+	except:
+		pass
+
+def test(dir):
+	try:
+		os.stat(join(dir, 'waflib'))
+		return os.path.abspath(dir)
+	except OSError:
+		pass
+
+def find_lib():
+	name = sys.argv[0]
+	base = os.path.dirname(os.path.abspath(name))
+
+	#devs use $WAFDIR
+	w=test(os.environ.get('WAFDIR', ''))
+	if w: return w
+
+	#waf-light
+	if name.endswith('waf-light'):
+		w = test(base)
+		if w: return w
+		err('waf-light requires waflib -> export WAFDIR=/folder')
+
+	dirname = '%s-%s-%s' % (WAF, VERSION, REVISION)
+	for i in [INSTALL,'/usr','/usr/local','/opt']:
+		w = test(i + '/lib/' + dirname)
+		if w: return w
+
+	#waf-local
+	dir = join(base, (sys.platform != 'win32' and '.' or '') + dirname)
+	w = test(dir)
+	if w: return w
+
+	#unpack
+	unpack_wafdir(dir)
+	return dir
+
+wafdir = find_lib()
+sys.path.insert(0, wafdir)
+
+if __name__ == '__main__':
+	import waflib.extras.compat15#PRELUDE
+	from waflib import Scripting
+	Scripting.waf_entry_point(cwd, VERSION, wafdir)
+
diff --git a/xpdeint/waf/waflib/Build.py b/xpdeint/waf/waflib/Build.py
new file mode 100644
index 0000000..e96678e
--- /dev/null
+++ b/xpdeint/waf/waflib/Build.py
@@ -0,0 +1,1293 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005-2010 (ita)
+
+"""
+Classes related to the build phase (build, clean, install, step, etc)
+
+The inheritance tree is the following:
+
+"""
+
+import os, sys, errno, re, shutil
+try: import cPickle
+except: import pickle as cPickle
+from waflib import Runner, TaskGen, Utils, ConfigSet, Task, Logs, Options, Context, Errors
+import waflib.Node
+
+CACHE_DIR = 'c4che'
+"""Location of the cache files"""
+
+CACHE_SUFFIX = '_cache.py'
+"""Suffix for the cache files"""
+
+INSTALL = 1337
+"""Positive value '->' install, see :py:attr:`waflib.Build.BuildContext.is_install`"""
+
+UNINSTALL = -1337
+"""Negative value '<-' uninstall, see :py:attr:`waflib.Build.BuildContext.is_install`"""
+
+SAVED_ATTRS = 'root node_deps raw_deps task_sigs'.split()
+"""Build class members to save between the runs (root, node_deps, raw_deps, task_sigs)"""
+
+CFG_FILES = 'cfg_files'
+"""Files from the build directory to hash before starting the build (``config.h`` written during the configuration)"""
+
+POST_AT_ONCE = 0
+"""Post mode: all task generators are posted before the build really starts"""
+
+POST_LAZY = 1
+"""Post mode: post the task generators group after group"""
+
+POST_BOTH = 2
+"""Post mode: post the task generators at once, then re-check them for each group"""
+
+class BuildContext(Context.Context):
+	'''executes the build'''
+
+	cmd = 'build'
+	variant = ''
+
+	def __init__(self, **kw):
+		super(BuildContext, self).__init__(**kw)
+
+		self.is_install = 0
+		"""Non-zero value when installing or uninstalling file"""
+
+		self.top_dir = kw.get('top_dir', Context.top_dir)
+
+		self.run_dir = kw.get('run_dir', Context.run_dir)
+
+		self.post_mode = POST_AT_ONCE
+		"""post the task generators at once, group-by-group, or both"""
+
+		# output directory - may be set until the nodes are considered
+		self.out_dir = kw.get('out_dir', Context.out_dir)
+
+		self.cache_dir = kw.get('cache_dir', None)
+		if not self.cache_dir:
+			self.cache_dir = self.out_dir + os.sep + CACHE_DIR
+
+		# map names to environments, the '' must be defined
+		self.all_envs = {}
+
+		# ======================================= #
+		# cache variables
+
+		self.task_sigs = {}
+		"""Signatures of the tasks (persists between build executions)"""
+
+		self.node_deps = {}
+		"""Dict of node dependencies found by :py:meth:`waflib.Task.Task.scan` (persists between build executions)"""
+
+		self.raw_deps = {}
+		"""Dict of custom data returned by :py:meth:`waflib.Task.Task.scan` (persists between build executions)"""
+
+		# list of folders that are already scanned
+		# so that we do not need to stat them one more time
+		self.cache_dir_contents = {}
+
+		self.task_gen_cache_names = {}
+
+		self.launch_dir = Context.launch_dir
+
+		self.jobs = Options.options.jobs
+		self.targets = Options.options.targets
+		self.keep = Options.options.keep
+		self.cache_global = Options.cache_global
+		self.nocache = Options.options.nocache
+		self.progress_bar = Options.options.progress_bar
+
+		############ stuff below has not been reviewed
+
+		# Manual dependencies.
+		self.deps_man = Utils.defaultdict(list)
+		"""Manual dependencies set by :py:meth:`waflib.Build.BuildContext.add_manual_dependency`"""
+
+		# just the structure here
+		self.current_group = 0
+		"""
+		Current build group
+		"""
+
+		self.groups = []
+		"""
+		List containing lists of task generators
+		"""
+		self.group_names = {}
+		"""
+		Map group names to the group lists. See :py:meth:`waflib.Build.BuildContext.add_group`
+		"""
+
+	def get_variant_dir(self):
+		"""Getter for the variant_dir attribute"""
+		if not self.variant:
+			return self.out_dir
+		return os.path.join(self.out_dir, self.variant)
+	variant_dir = property(get_variant_dir, None)
+
+	def __call__(self, *k, **kw):
+		"""
+		Create a task generator and add it to the current build group. The following forms are equivalent::
+
+			def build(bld):
+				tg = bld(a=1, b=2)
+
+			def build(bld):
+				tg = bld()
+				tg.a = 1
+				tg.b = 2
+
+			def build(bld):
+				tg = TaskGen.task_gen(a=1, b=2)
+				bld.add_to_group(tg, None)
+
+		:param group: group name to add the task generator to
+		:type group: string
+		"""
+		kw['bld'] = self
+		ret = TaskGen.task_gen(*k, **kw)
+		self.task_gen_cache_names = {} # reset the cache, each time
+		self.add_to_group(ret, group=kw.get('group', None))
+		return ret
+
+	def __copy__(self):
+		"""Implemented to prevents copies of build contexts (raises an exception)"""
+		raise Errors.WafError('build contexts are not supposed to be copied')
+
+	def install_files(self, *k, **kw):
+		"""Actual implementation provided by :py:meth:`waflib.Build.InstallContext.install_files`"""
+		pass
+
+	def install_as(self, *k, **kw):
+		"""Actual implementation provided by :py:meth:`waflib.Build.InstallContext.install_as`"""
+		pass
+
+	def symlink_as(self, *k, **kw):
+		"""Actual implementation provided by :py:meth:`waflib.Build.InstallContext.symlink_as`"""
+		pass
+
+	def load_envs(self):
+		"""
+		The configuration command creates files of the form ``build/c4che/NAMEcache.py``. This method
+		creates a :py:class:`waflib.ConfigSet.ConfigSet` instance for each ``NAME`` by reading those
+		files. The config sets are then stored in the dict :py:attr:`waflib.Build.BuildContext.allenvs`.
+		"""
+		node = self.root.find_node(self.cache_dir)
+		if not node:
+			raise Errors.WafError('The project was not configured: run "waf configure" first!')
+		lst = node.ant_glob('**/*%s' % CACHE_SUFFIX)
+
+		if not lst:
+			raise Errors.WafError('The cache directory is empty: reconfigure the project')
+
+		for x in lst:
+			name = x.path_from(node).replace(CACHE_SUFFIX, '').replace('\\', '/')
+			env = ConfigSet.ConfigSet(x.abspath())
+			self.all_envs[name] = env
+			for f in env[CFG_FILES]:
+				newnode = self.root.find_resource(f)
+				try:
+					h = Utils.h_file(newnode.abspath())
+				except (IOError, AttributeError):
+					Logs.error('cannot find %r' % f)
+					h = Utils.SIG_NIL
+				newnode.sig = h
+
+	def init_dirs(self):
+		"""
+		Initialize the project directory and the build directory by creating the nodes
+		:py:attr:`waflib.Build.BuildContext.srcnode` and :py:attr:`waflib.Build.BuildContext.bldnode`
+		corresponding to ``top_dir`` and ``variant_dir`` respectively. The ``bldnode`` directory will be
+		created if it does not exist.
+		"""
+
+		if not (os.path.isabs(self.top_dir) and os.path.isabs(self.out_dir)):
+			raise Errors.WafError('The project was not configured: run "waf configure" first!')
+
+		self.path = self.srcnode = self.root.find_dir(self.top_dir)
+		self.bldnode = self.root.make_node(self.variant_dir)
+		self.bldnode.mkdir()
+
+	def execute(self):
+		"""
+		Restore the data from previous builds and call :py:meth:`waflib.Build.BuildContext.execute_build`. Overrides from :py:func:`waflib.Context.Context.execute`
+		"""
+		self.restore()
+		if not self.all_envs:
+			self.load_envs()
+
+		self.execute_build()
+
+	def execute_build(self):
+		"""
+		Execute the build by:
+
+		* reading the scripts (see :py:meth:`waflib.Context.Context.recurse`)
+		* calling :py:meth:`waflib.Build.BuildContext.pre_build` to call user build functions
+		* calling :py:meth:`waflib.Build.BuildContext.compile` to process the tasks
+		* calling :py:meth:`waflib.Build.BuildContext.post_build` to call user build functions
+		"""
+
+		Logs.info("Waf: Entering directory `%s'" % self.variant_dir)
+		self.recurse([self.run_dir])
+		self.pre_build()
+
+		# display the time elapsed in the progress bar
+		self.timer = Utils.Timer()
+
+		if self.progress_bar:
+			sys.stderr.write(Logs.colors.cursor_off)
+		try:
+			self.compile()
+		finally:
+			if self.progress_bar == 1:
+				c = len(self.returned_tasks) or 1
+				self.to_log(self.progress_line(c, c, Logs.colors.BLUE, Logs.colors.NORMAL))
+				print('')
+				sys.stdout.flush()
+				sys.stderr.write(Logs.colors.cursor_on)
+			Logs.info("Waf: Leaving directory `%s'" % self.variant_dir)
+		self.post_build()
+
+	def restore(self):
+		"""
+		Load the data from a previous run, sets the attributes listed in :py:const:`waflib.Build.SAVED_ATTRS`
+		"""
+		try:
+			env = ConfigSet.ConfigSet(os.path.join(self.cache_dir, 'build.config.py'))
+		except (IOError, OSError):
+			pass
+		else:
+			if env['version'] < Context.HEXVERSION:
+				raise Errors.WafError('Version mismatch! reconfigure the project')
+			for t in env['tools']:
+				self.setup(**t)
+
+		f = None
+		try:
+			dbfn = os.path.join(self.variant_dir, Context.DBFILE)
+			try:
+				f = open(dbfn, 'rb')
+			except (IOError, EOFError):
+				# handle missing file/empty file
+				Logs.debug('build: could not load the build cache %s (missing)' % dbfn)
+			else:
+				try:
+					waflib.Node.pickle_lock.acquire()
+					waflib.Node.Nod3 = self.node_class
+					try:
+						data = cPickle.load(f)
+					except Exception as e:
+						Logs.debug('build: could not pickle the build cache %s: %r' % (dbfn, e))
+					else:
+						for x in SAVED_ATTRS:
+							setattr(self, x, data[x])
+				finally:
+					waflib.Node.pickle_lock.release()
+		finally:
+			if f:
+				f.close()
+
+		self.init_dirs()
+
+	def store(self):
+		"""
+		Store the data for next runs, sets the attributes listed in :py:const:`waflib.Build.SAVED_ATTRS`. Uses a temporary
+		file to avoid problems on ctrl+c.
+		"""
+
+		data = {}
+		for x in SAVED_ATTRS:
+			data[x] = getattr(self, x)
+		db = os.path.join(self.variant_dir, Context.DBFILE)
+
+		try:
+			waflib.Node.pickle_lock.acquire()
+			waflib.Node.Nod3 = self.node_class
+
+			f = None
+			try:
+				f = open(db + '.tmp', 'wb')
+				cPickle.dump(data, f)
+			finally:
+				if f:
+					f.close()
+		finally:
+			waflib.Node.pickle_lock.release()
+
+		try:
+			st = os.stat(db)
+			os.unlink(db)
+			if not Utils.is_win32: # win32 has no chown but we're paranoid
+				os.chown(db + '.tmp', st.st_uid, st.st_gid)
+		except (AttributeError, OSError):
+			pass
+
+		# do not use shutil.move (copy is not thread-safe)
+		os.rename(db + '.tmp', db)
+
+	def compile(self):
+		"""
+		Run the build by creating an instance of :py:class:`waflib.Runner.Parallel`
+		The cache file is not written if the build is up to date (no task executed).
+		"""
+		Logs.debug('build: compile()')
+
+		# use another object to perform the producer-consumer logic (reduce the complexity)
+		self.producer = Runner.Parallel(self, self.jobs)
+		self.producer.biter = self.get_build_iterator()
+		self.returned_tasks = [] # not part of the API yet
+		try:
+			self.producer.start()
+		except KeyboardInterrupt:
+			self.store()
+			raise
+		else:
+			if self.producer.dirty:
+				self.store()
+
+		if self.producer.error:
+			raise Errors.BuildError(self.producer.error)
+
+	def setup(self, tool, tooldir=None, funs=None):
+		"""
+		Import waf tools, used to import those accessed during the configuration::
+
+			def configure(conf):
+				conf.load('glib2')
+
+			def build(bld):
+				pass # glib2 is imported implicitly
+
+		:param tool: tool list
+		:type tool: list
+		:param tooldir: optional tool directory (sys.path)
+		:type tooldir: list of string
+		:param funs: unused variable
+		"""
+		if isinstance(tool, list):
+			for i in tool: self.setup(i, tooldir)
+			return
+
+		module = Context.load_tool(tool, tooldir)
+		if hasattr(module, "setup"): module.setup(self)
+
+	def get_env(self):
+		"""Getter for the env property"""
+		try:
+			return self.all_envs[self.variant]
+		except KeyError:
+			return self.all_envs['']
+	def set_env(self, val):
+		"""Setter for the env property"""
+		self.all_envs[self.variant] = val
+
+	env = property(get_env, set_env)
+
+	def add_manual_dependency(self, path, value):
+		"""
+		Adds a dependency from a node object to a value::
+
+			def build(bld):
+				bld.add_manual_dependency(
+					bld.path.find_resource('wscript'),
+					bld.root.find_resource('/etc/fstab'))
+
+		:param path: file path
+		:type path: string or :py:class:`waflib.Node.Node`
+		:param value: value to depend on
+		:type value: :py:class:`waflib.Node.Node`, string, or function returning a string
+		"""
+		if isinstance(path, waflib.Node.Node):
+			node = path
+		elif os.path.isabs(path):
+			node = self.root.find_resource(path)
+		else:
+			node = self.path.find_resource(path)
+		self.deps_man[id(node)].append(value)
+
+	def launch_node(self):
+		"""Returns the launch directory as a :py:class:`waflib.Node.Node` object"""
+		try:
+			# private cache
+			return self.p_ln
+		except AttributeError:
+			self.p_ln = self.root.find_dir(self.launch_dir)
+			return self.p_ln
+
+	def hash_env_vars(self, env, vars_lst):
+		"""
+		Hash configuration set variables::
+
+			def build(bld):
+				bld.hash_env_vars(bld.env, ['CXX', 'CC'])
+
+		:param env: Configuration Set
+		:type env: :py:class:`waflib.ConfigSet.ConfigSet`
+		:param vars_lst: list of variables
+		:type vars_list: list of string
+		"""
+
+		if not env.table:
+			env = env.parent
+			if not env:
+				return Utils.SIG_NIL
+
+		idx = str(id(env)) + str(vars_lst)
+		try:
+			cache = self.cache_env
+		except AttributeError:
+			cache = self.cache_env = {}
+		else:
+			try:
+				return self.cache_env[idx]
+			except KeyError:
+				pass
+
+		lst = [env[a] for a in vars_lst]
+		ret = Utils.h_list(lst)
+		Logs.debug('envhash: %s %r', Utils.to_hex(ret), lst)
+
+		cache[idx] = ret
+
+		return ret
+
+	def get_tgen_by_name(self, name):
+		"""
+		Retrieves a task generator from its name or its target name
+		the name must be unique::
+
+			def build(bld):
+				tg = bld(name='foo')
+				tg == bld.get_tgen_by_name('foo')
+		"""
+		cache = self.task_gen_cache_names
+		if not cache:
+			# create the index lazily
+			for g in self.groups:
+				for tg in g:
+					try:
+						cache[tg.name] = tg
+					except AttributeError:
+						# raised if not a task generator, which should be uncommon
+						pass
+		try:
+			return cache[name]
+		except KeyError:
+			raise Errors.WafError('Could not find a task generator for the name %r' % name)
+
+	def progress_line(self, state, total, col1, col2):
+		"""
+		Compute the progress bar used by ``waf -p``
+		"""
+		n = len(str(total))
+
+		Utils.rot_idx += 1
+		ind = Utils.rot_chr[Utils.rot_idx % 4]
+
+		pc = (100.*state)/total
+		eta = str(self.timer)
+		fs = "[%%%dd/%%%dd][%%s%%2d%%%%%%s][%s][" % (n, n, ind)
+		left = fs % (state, total, col1, pc, col2)
+		right = '][%s%s%s]' % (col1, eta, col2)
+
+		cols = Logs.get_term_cols() - len(left) - len(right) + 2*len(col1) + 2*len(col2)
+		if cols < 7: cols = 7
+
+		ratio = ((cols*state)//total) - 1
+
+		bar = ('='*ratio+'>').ljust(cols)
+		msg = Utils.indicator % (left, bar, right)
+
+		return msg
+
+	def declare_chain(self, *k, **kw):
+		"""
+		Wrapper for :py:func:`waflib.TaskGen.declare_chain` provided for convenience
+		"""
+		return TaskGen.declare_chain(*k, **kw)
+
+	def pre_build(self):
+		"""Execute user-defined methods before the build starts, see :py:meth:`waflib.Build.BuildContext.add_pre_fun`"""
+		for m in getattr(self, 'pre_funs', []):
+			m(self)
+
+	def post_build(self):
+		"""Executes the user-defined methods after the build is successful, see :py:meth:`waflib.Build.BuildContext.add_post_fun`"""
+		for m in getattr(self, 'post_funs', []):
+			m(self)
+
+	def add_pre_fun(self, meth):
+		"""
+		Bind a method to execute after the scripts are read and before the build starts::
+
+			def mycallback(bld):
+				print("Hello, world!")
+
+			def build(bld):
+				bld.add_pre_fun(mycallback)
+		"""
+		try:
+			self.pre_funs.append(meth)
+		except AttributeError:
+			self.pre_funs = [meth]
+
+	def add_post_fun(self, meth):
+		"""
+		Bind a method to execute immediately after the build is successful::
+
+			def call_ldconfig(bld):
+				bld.exec_command('/sbin/ldconfig')
+
+			def build(bld):
+				if bld.cmd == 'install':
+					bld.add_pre_fun(call_ldconfig)
+		"""
+		try:
+			self.post_funs.append(meth)
+		except AttributeError:
+			self.post_funs = [meth]
+
+	def get_group(self, x):
+		"""
+		Get the group x, or return the current group if x is None
+
+		:param x: name or number or None
+		:type x: string, int or None
+		"""
+		if not self.groups:
+			self.add_group()
+		if x is None:
+			return self.groups[self.current_group]
+		if x in self.group_names:
+			return self.group_names[x]
+		return self.groups[x]
+
+	def add_to_group(self, tgen, group=None):
+		"""add a task or a task generator for the build"""
+		# paranoid
+		assert(isinstance(tgen, TaskGen.task_gen) or isinstance(tgen, Task.TaskBase))
+		tgen.bld = self
+		self.get_group(group).append(tgen)
+
+	def get_group_name(self, g):
+		"""name for the group g (utility)"""
+		if not isinstance(g, list):
+			g = self.groups[g]
+		for x in self.group_names:
+			if id(self.group_names[x]) == id(g):
+				return x
+		return ''
+
+	def get_group_idx(self, tg):
+		"""
+		Index of the group containing the task generator given as argument::
+
+			def build(bld):
+				tg = bld(name='nada')
+				0 == bld.get_group_idx(tg)
+
+		:param tg: Task generator object
+		:type tg: :py:class:`waflib.TaskGen.task_gen`
+		"""
+		se = id(tg)
+		for i in range(len(self.groups)):
+			for t in self.groups[i]:
+				if id(t) == se:
+					return i
+		return None
+
+	def add_group(self, name=None, move=True):
+		"""
+		Add a new group of tasks/task generators. By default the new group becomes the default group for new task generators.
+
+		:param name: name for this group
+		:type name: string
+		:param move: set the group created as default group (True by default)
+		:type move: bool
+		"""
+		#if self.groups and not self.groups[0].tasks:
+		#	error('add_group: an empty group is already present')
+		if name and name in self.group_names:
+			Logs.error('add_group: name %s already present' % name)
+		g = []
+		self.group_names[name] = g
+		self.groups.append(g)
+		if move:
+			self.current_group = len(self.groups) - 1
+
+	def set_group(self, idx):
+		"""
+		Set the current group to be idx: now new task generators will be added to this group by default::
+
+			def build(bld):
+				bld(rule='touch ${TGT}', target='foo.txt')
+				bld.add_group() # now the current group is 1
+				bld(rule='touch ${TGT}', target='bar.txt')
+				bld.set_group(0) # now the current group is 0
+				bld(rule='touch ${TGT}', target='truc.txt') # build truc.txt before bar.txt
+
+		:param idx: group name or group index
+		:type idx: string or int
+		"""
+		if isinstance(idx, str):
+			g = self.group_names[idx]
+			for i in range(len(self.groups)):
+				if id(g) == id(self.groups[i]):
+					self.current_group = i
+		else:
+			self.current_group = idx
+
+	def total(self):
+		"""
+		Approximate task count: this value may be inaccurate if task generators are posted lazily (see :py:attr:`waflib.Build.BuildContext.post_mode`).
+		The value :py:attr:`waflib.Runner.Parallel.total` is updated during the task execution.
+		"""
+		total = 0
+		for group in self.groups:
+			for tg in group:
+				try:
+					total += len(tg.tasks)
+				except AttributeError:
+					total += 1
+		return total
+
+	def get_targets(self):
+		"""
+		Return the task generator corresponding to the 'targets' list, used by :py:meth:`waflib.Build.BuildContext.get_build_iterator`::
+
+			$ waf --targets=myprogram,myshlib
+		"""
+		to_post = []
+		min_grp = 0
+		for name in self.targets.split(','):
+			tg = self.get_tgen_by_name(name)
+			if not tg:
+				raise Errors.WafError('target %r does not exist' % name)
+
+			m = self.get_group_idx(tg)
+			if m > min_grp:
+				min_grp = m
+				to_post = [tg]
+			elif m == min_grp:
+				to_post.append(tg)
+		return (min_grp, to_post)
+
+	def post_group(self):
+		"""
+		Post the task generators from the group indexed by self.cur, used by :py:meth:`waflib.Build.BuildContext.get_build_iterator`
+		"""
+		if self.targets == '*':
+			for tg in self.groups[self.cur]:
+				try:
+					f = tg.post
+				except AttributeError:
+					pass
+				else:
+					f()
+		elif self.targets:
+			if self.cur < self._min_grp:
+				for tg in self.groups[self.cur]:
+					try:
+						f = tg.post
+					except AttributeError:
+						pass
+					else:
+						f()
+			else:
+				for tg in self._exact_tg:
+					tg.post()
+		else:
+			ln = self.launch_node()
+			for tg in self.groups[self.cur]:
+				try:
+					f = tg.post
+				except AttributeError:
+					pass
+				else:
+					if tg.path.is_child_of(ln):
+						f()
+
+	def get_tasks_group(self, idx):
+		"""
+		Return all the tasks for the group of num idx, used by :py:meth:`waflib.Build.BuildContext.get_build_iterator`
+		"""
+		tasks = []
+		for tg in self.groups[idx]:
+			# TODO a try-except might be more efficient
+			if isinstance(tg, Task.TaskBase):
+				tasks.append(tg)
+			else:
+				tasks.extend(tg.tasks)
+		return tasks
+
+	def get_build_iterator(self):
+		"""
+		Creates a generator object that returns lists of tasks executable in parallel (yield)
+
+		:return: tasks which can be executed immediatly
+		:rtype: list of :py:class:`waflib.Task.TaskBase`
+		"""
+		self.cur = 0
+
+		if self.targets and self.targets != '*':
+			(self._min_grp, self._exact_tg) = self.get_targets()
+
+		global lazy_post
+		if self.post_mode != POST_LAZY:
+			while self.cur < len(self.groups):
+				self.post_group()
+				self.cur += 1
+			self.cur = 0
+
+		while self.cur < len(self.groups):
+			# first post the task generators for the group
+			if self.post_mode != POST_AT_ONCE:
+				self.post_group()
+
+			# then extract the tasks
+			tasks = self.get_tasks_group(self.cur)
+			# if the constraints are set properly (ext_in/ext_out, before/after)
+			# the call to set_file_constraints may be removed (can be a 15% penalty on no-op rebuilds)
+			# (but leave set_file_constraints for the installation step)
+			#
+			# if the tasks have only files, set_file_constraints is required but set_precedence_constraints is not necessary
+			#
+			Task.set_file_constraints(tasks)
+			Task.set_precedence_constraints(tasks)
+
+			self.cur_tasks = tasks
+			self.cur += 1
+			if not tasks: # return something else the build will stop
+				continue
+			yield tasks
+		while 1:
+			yield []
+
+
+	#def install_dir(self, path, env=None):
+	#	"""
+	#	Create empty folders for the installation (very rarely used) TODO
+	#	"""
+	#	return
+
+class inst(Task.Task):
+	"""
+    Special task used for installing files and symlinks, it behaves both like a task
+	and like a task generator
+	"""
+	color = 'CYAN'
+
+	def post(self):
+		"""
+		Same interface as in :py:meth:`waflib.TaskGen.task_gen.post`
+		"""
+		buf = []
+		for x in self.source:
+			if isinstance(x, waflib.Node.Node):
+				y = x
+			else:
+				y = self.path.find_resource(x)
+				if not y:
+					if Logs.verbose:
+						Logs.warn('Could not find %s immediately (may cause broken builds)' % x)
+					idx = self.generator.bld.get_group_idx(self)
+					for tg in self.generator.bld.groups[idx]:
+						if not isinstance(tg, inst) and id(tg) != id(self):
+							tg.post()
+						y = self.path.find_resource(x)
+						if y:
+							break
+					else:
+						raise Errors.WafError('could not find %r in %r' % (x, self.path))
+			buf.append(y)
+		self.inputs = buf
+
+	def runnable_status(self):
+		"""
+		Installation tasks are always executed, so this method returns either :py:const:`waflib.Task.ASK_LATER` or :py:const:`waflib.Task.RUN_ME`.
+		"""
+		ret = super(inst, self).runnable_status()
+		if ret == Task.SKIP_ME:
+			return Task.RUN_ME
+		return ret
+
+	def __str__(self):
+		"""Return an empty string to disable the display"""
+		return ''
+
+	def run(self):
+		"""The attribute 'exec_task' holds the method to execute"""
+		return self.generator.exec_task()
+
+	def get_install_path(self, destdir=True):
+		"""
+		Installation path obtained from ``self.dest`` and prefixed by the destdir.
+		The variables such as '${PREFIX}/bin' are substituted.
+		"""
+		dest = Utils.subst_vars(self.dest, self.env)
+		dest = dest.replace('/', os.sep)
+		if destdir and Options.options.destdir:
+			dest = os.path.join(Options.options.destdir, os.path.splitdrive(dest)[1].lstrip(os.sep))
+		return dest
+
+	def exec_install_files(self):
+		"""
+		Predefined method for installing files
+		"""
+		destpath = self.get_install_path()
+		if not destpath:
+			raise Errors.WafError('unknown installation path %r' % self.generator)
+		for x, y in zip(self.source, self.inputs):
+			if self.relative_trick:
+				destfile = os.path.join(destpath, y.path_from(self.path))
+				Utils.check_dir(os.path.dirname(destfile))
+			else:
+				destfile = os.path.join(destpath, y.name)
+			self.generator.bld.do_install(y.abspath(), destfile, self.chmod)
+
+	def exec_install_as(self):
+		"""
+		Predefined method for installing one file with a given name
+		"""
+		destfile = self.get_install_path()
+		self.generator.bld.do_install(self.inputs[0].abspath(), destfile, self.chmod)
+
+	def exec_symlink_as(self):
+		"""
+		Predefined method for installing a symlink
+		"""
+		destfile = self.get_install_path()
+		self.generator.bld.do_link(self.link, destfile)
+
+class InstallContext(BuildContext):
+	'''installs the targets on the system'''
+	cmd = 'install'
+
+	def __init__(self, **kw):
+		super(InstallContext, self).__init__(**kw)
+
+		# list of targets to uninstall for removing the empty folders after uninstalling
+		self.uninstall = []
+		self.is_install = INSTALL
+
+	def do_install(self, src, tgt, chmod=Utils.O644):
+		"""
+		Copy a file from src to tgt with given file permissions. The actual copy is not performed
+		if the source and target file have the same size and the same timestamps. When the copy occurs,
+		the file is first removed and then copied (prevent stale inodes).
+
+		This method is overridden in :py:meth:`waflib.Build.UninstallContext.do_install` to remove the file.
+
+		:param src: file name as absolute path
+		:type src: string
+		:param tgt: file destination, as absolute path
+		:type tgt: string
+		:param chmod: installation mode
+		:type chmod: int
+		"""
+		d, _ = os.path.split(tgt)
+		if not d:
+			raise Errors.WafError('Invalid installation given %r->%r' % (src, tgt))
+		Utils.check_dir(d)
+
+		srclbl = src.replace(self.srcnode.abspath() + os.sep, '')
+		if not Options.options.force:
+			# check if the file is already there to avoid a copy
+			try:
+				st1 = os.stat(tgt)
+				st2 = os.stat(src)
+			except OSError:
+				pass
+			else:
+				# same size and identical timestamps -> make no copy
+				if st1.st_mtime + 2 >= st2.st_mtime and st1.st_size == st2.st_size:
+					if not self.progress_bar:
+						Logs.info('- install %s (from %s)' % (tgt, srclbl))
+					return False
+
+		if not self.progress_bar:
+			Logs.info('+ install %s (from %s)' % (tgt, srclbl))
+
+		# following is for shared libs and stale inodes (-_-)
+		try:
+			os.remove(tgt)
+		except OSError:
+			pass
+
+		try:
+			shutil.copy2(src, tgt)
+			os.chmod(tgt, chmod)
+		except IOError:
+			try:
+				os.stat(src)
+			except (OSError, IOError):
+				Logs.error('File %r does not exist' % src)
+			raise Errors.WafError('Could not install the file %r' % tgt)
+
+	def do_link(self, src, tgt):
+		"""
+		Create a symlink from tgt to src.
+
+		This method is overridden in :py:meth:`waflib.Build.UninstallContext.do_link` to remove the symlink.
+
+		:param src: file name as absolute path
+		:type src: string
+		:param tgt: file destination, as absolute path
+		:type tgt: string
+		"""
+		d, _ = os.path.split(tgt)
+		Utils.check_dir(d)
+
+		link = False
+		if not os.path.islink(tgt):
+			link = True
+		elif os.readlink(tgt) != src:
+			link = True
+
+		if link:
+			try: os.remove(tgt)
+			except OSError: pass
+			if not self.progress_bar:
+				Logs.info('+ symlink %s (to %s)' % (tgt, src))
+			os.symlink(src, tgt)
+		else:
+			if not self.progress_bar:
+				Logs.info('- symlink %s (to %s)' % (tgt, src))
+
+	def run_task_now(self, tsk, postpone):
+		"""
+		This method is called by :py:meth:`waflib.Build.InstallContext.install_files`,
+		:py:meth:`waflib.Build.InstallContext.install_as` and :py:meth:`waflib.Build.InstallContext.symlink_as` immediately
+		after the installation task is created. Its role is to force the immediate execution if necessary, that is when
+		``postpone=False`` was given.
+		"""
+		tsk.post()
+		if not postpone:
+			if tsk.runnable_status() == Task.ASK_LATER:
+				raise self.WafError('cannot post the task %r' % tsk)
+			tsk.run()
+
+	def install_files(self, dest, files, env=None, chmod=Utils.O644, relative_trick=False, cwd=None, add=True, postpone=True):
+		"""
+		Create a task to install files on the system::
+
+			def build(bld):
+				bld.install_files('${DATADIR}', self.path.find_resource('wscript'))
+
+		:param dest: absolute path of the destination directory
+		:type dest: string
+		:param files: input files
+		:type files: list of strings or list of nodes
+		:param env: configuration set for performing substitutions in dest
+		:type env: Configuration set
+		:param relative_trick: preserve the folder hierarchy when installing whole folders
+		:type relative_trick: bool
+		:param cwd: parent node for searching srcfile, when srcfile is not a :py:class:`waflib.Node.Node`
+		:type cwd: :py:class:`waflib.Node.Node`
+		:param add: add the task created to a build group - set ``False`` only if the installation task is created after the build has started
+		:type add: bool
+		:param postpone: execute the task immediately to perform the installation
+		:type postpone: bool
+		"""
+		tsk = inst(env=env or self.env)
+		tsk.bld = self
+		tsk.path = cwd or self.path
+		tsk.chmod = chmod
+		if isinstance(files, waflib.Node.Node):
+			tsk.source =  [files]
+		else:
+			tsk.source = Utils.to_list(files)
+		tsk.dest = dest
+		tsk.exec_task = tsk.exec_install_files
+		tsk.relative_trick = relative_trick
+		if add: self.add_to_group(tsk)
+		self.run_task_now(tsk, postpone)
+		return tsk
+
+	def install_as(self, dest, srcfile, env=None, chmod=Utils.O644, cwd=None, add=True, postpone=True):
+		"""
+		Create a task to install a file on the system with a different name::
+
+			def build(bld):
+				bld.install_as('${PREFIX}/bin', 'myapp', chmod=Utils.O755)
+
+		:param dest: absolute path of the destination file
+		:type dest: string
+		:param srcfile: input file
+		:type srcfile: string or node
+		:param cwd: parent node for searching srcfile, when srcfile is not a :py:class:`waflib.Node.Node`
+		:type cwd: :py:class:`waflib.Node.Node`
+		:param env: configuration set for performing substitutions in dest
+		:type env: Configuration set
+		:param add: add the task created to a build group - set ``False`` only if the installation task is created after the build has started
+		:type add: bool
+		:param postpone: execute the task immediately to perform the installation
+		:type postpone: bool
+		"""
+		tsk = inst(env=env or self.env)
+		tsk.bld = self
+		tsk.path = cwd or self.path
+		tsk.chmod = chmod
+		tsk.source = [srcfile]
+		tsk.dest = dest
+		tsk.exec_task = tsk.exec_install_as
+		if add: self.add_to_group(tsk)
+		self.run_task_now(tsk, postpone)
+		return tsk
+
+	def symlink_as(self, dest, src, env=None, cwd=None, add=True, postpone=True):
+		"""
+		Create a task to install a symlink::
+
+			def build(bld):
+				bld.symlink_as('${PREFIX}/lib/libfoo.so', 'libfoo.so.1.2.3')
+
+		:param dest: absolute path of the symlink
+		:type dest: string
+		:param src: absolute or relative path of the link
+		:type src: string
+		:param env: configuration set for performing substitutions in dest
+		:type env: Configuration set
+		:param add: add the task created to a build group - set ``False`` only if the installation task is created after the build has started
+		:type add: bool
+		:param postpone: execute the task immediately to perform the installation
+		:type postpone: bool
+		"""
+
+		if Utils.is_win32:
+			# symlinks *cannot* work on that platform
+			return
+
+		tsk = inst(env=env or self.env)
+		tsk.bld = self
+		tsk.dest = dest
+		tsk.path = cwd or self.path
+		tsk.source = []
+		tsk.link = src
+		tsk.exec_task = tsk.exec_symlink_as
+		if add: self.add_to_group(tsk)
+		self.run_task_now(tsk, postpone)
+		return tsk
+
+class UninstallContext(InstallContext):
+	'''removes the targets installed'''
+	cmd = 'uninstall'
+
+	def __init__(self, **kw):
+		super(UninstallContext, self).__init__(**kw)
+		self.is_install = UNINSTALL
+
+	def do_install(self, src, tgt, chmod=Utils.O644):
+		"""See :py:meth:`waflib.Build.InstallContext.do_install`"""
+		if not self.progress_bar:
+			Logs.info('- remove %s' % tgt)
+
+		self.uninstall.append(tgt)
+		try:
+			os.remove(tgt)
+		except OSError as e:
+			if e.errno != errno.ENOENT:
+				if not getattr(self, 'uninstall_error', None):
+					self.uninstall_error = True
+					Logs.warn('build: some files could not be uninstalled (retry with -vv to list them)')
+				if Logs.verbose > 1:
+					Logs.warn('could not remove %s (error code %r)' % (e.filename, e.errno))
+
+		# TODO ita refactor this into a post build action to uninstall the folders (optimization)
+		while tgt:
+			tgt = os.path.dirname(tgt)
+			try:
+				os.rmdir(tgt)
+			except OSError:
+				break
+
+	def do_link(self, src, tgt):
+		"""See :py:meth:`waflib.Build.InstallContext.do_link`"""
+		try:
+			if not self.progress_bar:
+				Logs.info('- unlink %s' % tgt)
+			os.remove(tgt)
+		except OSError:
+			pass
+
+		# TODO ita refactor this into a post build action to uninstall the folders (optimization)?
+		while tgt:
+			tgt = os.path.dirname(tgt)
+			try:
+				os.rmdir(tgt)
+			except OSError:
+				break
+
+	def execute(self):
+		"""
+		See :py:func:`waflib.Context.Context.execute`
+		"""
+		try:
+			# do not execute any tasks
+			def runnable_status(self):
+				return Task.SKIP_ME
+			setattr(Task.Task, 'runnable_status_back', Task.Task.runnable_status)
+			setattr(Task.Task, 'runnable_status', runnable_status)
+
+			super(UninstallContext, self).execute()
+		finally:
+			setattr(Task.Task, 'runnable_status', Task.Task.runnable_status_back)
+
+class CleanContext(BuildContext):
+	'''cleans the project'''
+	cmd = 'clean'
+	def execute(self):
+		"""
+		See :py:func:`waflib.Context.Context.execute`
+		"""
+		self.restore()
+		if not self.all_envs:
+			self.load_envs()
+
+		self.recurse([self.run_dir])
+		try:
+			self.clean()
+		finally:
+			self.store()
+
+	def clean(self):
+		"""clean the data and some files in the build dir .. well, TODO"""
+		Logs.debug('build: clean called')
+
+		if self.bldnode != self.srcnode:
+			# would lead to a disaster if top == out
+			lst = [self.root.find_or_declare(f) for f in self.env[CFG_FILES]]
+			for n in self.bldnode.ant_glob('**/*', excl='lock* *conf_check_*/** config.log c4che/*'):
+				if n in lst:
+					continue
+				n.delete()
+		self.root.children = {}
+
+		for v in 'node_deps task_sigs raw_deps'.split():
+			setattr(self, v, {})
+
+class ListContext(BuildContext):
+	'''lists the targets to execute'''
+
+	cmd = 'list'
+	def execute(self):
+		"""
+		See :py:func:`waflib.Context.Context.execute`.
+		"""
+		self.restore()
+		if not self.all_envs:
+			self.load_envs()
+
+		self.recurse([self.run_dir])
+		self.pre_build()
+
+		# display the time elapsed in the progress bar
+		self.timer = Utils.Timer()
+
+		for g in self.groups:
+			for tg in g:
+				try:
+					f = tg.post
+				except AttributeError:
+					pass
+				else:
+					f()
+
+		try:
+			# force the cache initialization
+			self.get_tgen_by_name('')
+		except:
+			pass
+		lst = list(self.task_gen_cache_names.keys())
+		lst.sort()
+		for k in lst:
+			Logs.pprint('GREEN', k)
+
+class StepContext(BuildContext):
+	'''executes tasks in a step-by-step fashion, for debugging'''
+	cmd = 'step'
+
+	def __init__(self, **kw):
+		super(StepContext, self).__init__(**kw)
+		self.files = Options.options.files
+
+	def compile(self):
+		"""
+		Compile the tasks matching the input/output files given (regular expression matching). Derived from :py:meth:`waflib.Build.BuildContext.compile`::
+
+			$ waf step --files=foo.c,bar.c,in:truc.c,out:bar.o
+			$ waf step --files=in:foo.cpp.1.o # link task only
+
+		"""
+		if not self.files:
+			Logs.warn('Add a pattern for the debug build, for example "waf step --files=main.c,app"')
+			BuildContext.compile(self)
+			return
+
+		for g in self.groups:
+			for tg in g:
+				try:
+					f = tg.post
+				except AttributeError:
+					pass
+				else:
+					f()
+
+			for pat in self.files.split(','):
+				matcher = self.get_matcher(pat)
+				for tg in g:
+					if isinstance(tg, Task.TaskBase):
+						lst = [tg]
+					else:
+						lst = tg.tasks
+					for tsk in lst:
+						do_exec = False
+						for node in getattr(tsk, 'inputs', []):
+							if matcher(node, output=False):
+								do_exec = True
+								break
+						for node in getattr(tsk, 'outputs', []):
+							if matcher(node, output=True):
+								do_exec = True
+								break
+						if do_exec:
+							ret = tsk.run()
+							Logs.info('%s -> exit %r' % (str(tsk), ret))
+
+	def get_matcher(self, pat):
+		# this returns a function
+		inn = True
+		out = True
+		if pat.startswith('in:'):
+			out = False
+			pat = pat.replace('in:', '')
+		elif pat.startswith('out:'):
+			inn = False
+			pat = pat.replace('out:', '')
+
+		anode = self.root.find_node(pat)
+		pattern = None
+		if not anode:
+			if not pat.startswith('^'):
+				pat = '^.+?%s' % pat
+			if not pat.endswith('$'):
+				pat = '%s$' % pat
+			pattern = re.compile(pat)
+
+		def match(node, output):
+			if output == True and not out:
+				return False
+			if output == False and not inn:
+				return False
+
+			if anode:
+				return anode == node
+			else:
+				return pattern.match(node.abspath())
+		return match
+
+BuildContext.store = Utils.nogc(BuildContext.store)
+BuildContext.restore = Utils.nogc(BuildContext.restore)
+
diff --git a/xpdeint/waf/waflib/Build.pyc b/xpdeint/waf/waflib/Build.pyc
new file mode 100644
index 0000000..b37db9b
Binary files /dev/null and b/xpdeint/waf/waflib/Build.pyc differ
diff --git a/xpdeint/waf/waflib/ConfigSet.py b/xpdeint/waf/waflib/ConfigSet.py
new file mode 100644
index 0000000..052c053
--- /dev/null
+++ b/xpdeint/waf/waflib/ConfigSet.py
@@ -0,0 +1,337 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005-2010 (ita)
+
+"""
+
+ConfigSet: a special dict
+
+The values put in :py:class:`ConfigSet` must be lists
+"""
+
+import copy, re, os
+from waflib import Logs, Utils
+re_imp = re.compile('^(#)*?([^#=]*?)\ =\ (.*?)$', re.M)
+
+class ConfigSet(object):
+	"""
+	A dict that honor serialization and parent relationships. The serialization format
+	is human-readable (python-like) and performed by using eval() and repr().
+	For high performance prefer pickle. Do not store functions as they are not serializable.
+
+	The values can be accessed by attributes or by keys::
+
+		from waflib.ConfigSet import ConfigSet
+		env = ConfigSet()
+		env.FOO = 'test'
+		env['FOO'] = 'test'
+	"""
+	__slots__ = ('table', 'parent')
+	def __init__(self, filename=None):
+		self.table = {}
+		"""
+		Internal dict holding the object values
+		"""
+		#self.parent = None
+
+		if filename:
+			self.load(filename)
+
+	def __contains__(self, key):
+		"""
+		Enable the *in* syntax::
+
+			if 'foo' in env:
+				print env['foo']
+		"""
+		if key in self.table: return True
+		try: return self.parent.__contains__(key)
+		except AttributeError: return False # parent may not exist
+
+	def keys(self):
+		"""Dict interface (unknown purpose)"""
+		keys = set()
+		cur = self
+		while cur:
+			keys.update(cur.table.keys())
+			cur = getattr(cur, 'parent', None)
+		keys = list(keys)
+		keys.sort()
+		return keys
+
+	def __str__(self):
+		"""Text representation of the ConfigSet (for debugging purposes)"""
+		return "\n".join(["%r %r" % (x, self.__getitem__(x)) for x in self.keys()])
+
+	def __getitem__(self, key):
+		"""
+		Dictionary interface: get value from key::
+
+			def configure(conf):
+				conf.env['foo'] = {}
+				print(env['foo'])
+		"""
+		try:
+			while 1:
+				x = self.table.get(key, None)
+				if not x is None:
+					return x
+				self = self.parent
+		except AttributeError:
+			return []
+
+	def __setitem__(self, key, value):
+		"""
+		Dictionary interface: get value from key
+		"""
+		self.table[key] = value
+
+	def __delitem__(self, key):
+		"""
+		Dictionary interface: get value from key
+		"""
+		self[key] = []
+
+	def __getattr__(self, name):
+		"""
+		Attribute access provided for convenience. The following forms are equivalent::
+
+			def configure(conf):
+				conf.env.value
+				conf.env['value']
+		"""
+		if name in self.__slots__:
+			return object.__getattr__(self, name)
+		else:
+			return self[name]
+
+	def __setattr__(self, name, value):
+		"""
+		Attribute access provided for convenience. The following forms are equivalent::
+
+			def configure(conf):
+				conf.env.value = x
+				env['value'] = x
+		"""
+		if name in self.__slots__:
+			object.__setattr__(self, name, value)
+		else:
+			self[name] = value
+
+	def __delattr__(self, name):
+		"""
+		Attribute access provided for convenience. The following forms are equivalent::
+
+			def configure(conf):
+				del env.value
+				del env['value']
+		"""
+		if name in self.__slots__:
+			object.__delattr__(self, name)
+		else:
+			del self[name]
+
+	def derive(self):
+		"""
+		Returns a new ConfigSet deriving from self. The copy returned
+		will be a shallow copy::
+
+			from waflib.ConfigSet import ConfigSet
+			env = ConfigSet()
+			env.append_value('CFLAGS', ['-O2'])
+			child = env.derive()
+			child.CFLAGS.append('test') # warning! this will modify 'env'
+			child.CFLAGS = ['-O3'] # new list, ok
+			child.append_value('CFLAGS', ['-O3']) # ok
+
+		Use :py:func:`ConfigSet.detach` to detach the child from the parent.
+		"""
+		newenv = ConfigSet()
+		newenv.parent = self
+		return newenv
+
+	def detach(self):
+		"""
+		Detach self from its parent (if existing)
+
+		Modifying the parent :py:class:`ConfigSet` will not change the current object
+		Modifying this :py:class:`ConfigSet` will not modify the parent one.
+		"""
+		tbl = self.get_merged_dict()
+		try:
+			delattr(self, 'parent')
+		except AttributeError:
+			pass
+		else:
+			keys = tbl.keys()
+			for x in keys:
+				tbl[x] = copy.deepcopy(tbl[x])
+			self.table = tbl
+
+	def get_flat(self, key):
+		"""
+		Return a value as a string. If the input is a list, the value returned is space-separated.
+
+		:param key: key to use
+		:type key: string
+		"""
+		s = self[key]
+		if isinstance(s, str): return s
+		return ' '.join(s)
+
+	def _get_list_value_for_modification(self, key):
+		"""
+		Return a list value for further modification.
+
+		The list may be modified inplace and there is no need to do this afterwards::
+
+			self.table[var] = value
+		"""
+		try:
+			value = self.table[key]
+		except KeyError:
+			try: value = self.parent[key]
+			except AttributeError: value = []
+			if isinstance(value, list):
+				value = value[:]
+			else:
+				value = [value]
+		else:
+			if not isinstance(value, list):
+				value = [value]
+		self.table[key] = value
+		return value
+
+	def append_value(self, var, val):
+		"""
+		Appends a value to the specified config key::
+
+			def build(bld):
+				bld.env.append_value('CFLAGS', ['-O2'])
+
+		The value must be a list or a tuple
+		"""
+		current_value = self._get_list_value_for_modification(var)
+		if isinstance(val, str): # if there were string everywhere we could optimize this
+			val = [val]
+		current_value.extend(val)
+
+	def prepend_value(self, var, val):
+		"""
+		Prepends a value to the specified item::
+
+			def configure(conf):
+				conf.env.prepend_value('CFLAGS', ['-O2'])
+
+		The value must be a list or a tuple
+		"""
+		if isinstance(val, str):
+			val = [val]
+		self.table[var] =  val + self._get_list_value_for_modification(var)
+
+	def append_unique(self, var, val):
+		"""
+		Append a value to the specified item only if it's not already present::
+
+			def build(bld):
+				bld.env.append_unique('CFLAGS', ['-O2', '-g'])
+
+		The value must be a list or a tuple
+		"""
+		if isinstance(val, str):
+			val = [val]
+		current_value = self._get_list_value_for_modification(var)
+
+		for x in val:
+			if x not in current_value:
+				current_value.append(x)
+
+	def get_merged_dict(self):
+		"""
+		Compute the merged dictionary from the fusion of self and all its parent
+
+		:rtype: a ConfigSet object
+		"""
+		table_list = []
+		env = self
+		while 1:
+			table_list.insert(0, env.table)
+			try: env = env.parent
+			except AttributeError: break
+		merged_table = {}
+		for table in table_list:
+			merged_table.update(table)
+		return merged_table
+
+	def store(self, filename):
+		"""
+		Write the :py:class:`ConfigSet` data into a file. See :py:meth:`ConfigSet.load` for reading such files.
+
+		:param filename: file to use
+		:type filename: string
+		"""
+		try:
+			os.makedirs(os.path.split(filename)[0])
+		except OSError:
+			pass
+
+		f = None
+		try:
+			f = open(filename, 'w')
+			merged_table = self.get_merged_dict()
+			keys = list(merged_table.keys())
+			keys.sort()
+			for k in keys:
+				if k != 'undo_stack':
+					f.write('%s = %r\n' % (k, merged_table[k]))
+		finally:
+			if f:
+				f.close()
+
+	def load(self, filename):
+		"""
+		Retrieve the :py:class:`ConfigSet` data from a file. See :py:meth:`ConfigSet.store` for writing such files
+
+		:param filename: file to use
+		:type filename: string
+		"""
+		tbl = self.table
+		code = Utils.readf(filename)
+		for m in re_imp.finditer(code):
+			g = m.group
+			tbl[g(2)] = eval(g(3))
+		Logs.debug('env: %s' % str(self.table))
+
+	def update(self, d):
+		"""
+		Dictionary interface: replace values from another dict
+
+		:param d: object to use the value from
+		:type d: dict-like object
+		"""
+		for k, v in d.items():
+			self[k] = v
+
+	def stash(self):
+		"""
+		Store the object state, to provide a kind of transaction support::
+
+			env = ConfigSet()
+			env.stash()
+			try:
+				env.append_value('CFLAGS', '-O3')
+				call_some_method(env)
+			finally:
+				env.revert()
+
+		The history is kept in a stack, and is lost during the serialization by :py:meth:`ConfigSet.store`
+		"""
+		self.undo_stack = self.undo_stack + [self.table]
+		self.table = self.table.copy()
+
+	def revert(self):
+		"""
+		Reverts the object to a previous state. See :py:meth:`ConfigSet.stash`
+		"""
+		self.table = self.undo_stack.pop(-1)
+
diff --git a/xpdeint/waf/waflib/ConfigSet.pyc b/xpdeint/waf/waflib/ConfigSet.pyc
new file mode 100644
index 0000000..ccd4ffd
Binary files /dev/null and b/xpdeint/waf/waflib/ConfigSet.pyc differ
diff --git a/xpdeint/waf/waflib/Configure.py b/xpdeint/waf/waflib/Configure.py
new file mode 100644
index 0000000..eb1e4d4
--- /dev/null
+++ b/xpdeint/waf/waflib/Configure.py
@@ -0,0 +1,570 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005-2010 (ita)
+
+"""
+Configuration system
+
+A :py:class:`waflib.Configure.ConfigurationContext` instance is created when ``waf configure`` is called, it is used to:
+
+* create data dictionaries (ConfigSet instances)
+* store the list of modules to import
+* hold configuration routines such as ``find_program``, etc
+"""
+
+import os, shlex, sys, time
+from waflib import ConfigSet, Utils, Options, Logs, Context, Build, Errors
+
+try:
+	from urllib import request
+except:
+	from urllib import urlopen
+else:
+	urlopen = request.urlopen
+
+BREAK    = 'break'
+"""In case of a configuration error, break"""
+
+CONTINUE = 'continue'
+"""In case of a configuration error, continue"""
+
+WAF_CONFIG_LOG = 'config.log'
+"""Name of the configuration log file"""
+
+autoconfig = False
+"""Execute the configuration automatically"""
+
+conf_template = '''# project %(app)s configured on %(now)s by
+# waf %(wafver)s (abi %(abi)s, python %(pyver)x on %(systype)s)
+# using %(args)s
+#'''
+
+def download_check(node):
+	"""
+	Hook to check for the tools which are downloaded. Replace with your function if necessary.
+	"""
+	pass
+
+def download_tool(tool, force=False, ctx=None):
+	"""
+	Download a Waf tool from the remote repository defined in :py:const:`waflib.Context.remote_repo`::
+
+		$ waf configure --download
+	"""
+	for x in Utils.to_list(Context.remote_repo):
+		for sub in Utils.to_list(Context.remote_locs):
+			url = '/'.join((x, sub, tool + '.py'))
+			try:
+				web = urlopen(url)
+				try:
+					if web.getcode() != 200:
+						continue
+				except AttributeError:
+					pass
+			except Exception:
+				# on python3 urlopen throws an exception
+				# python 2.3 does not have getcode and throws an exception to fail
+				continue
+			else:
+				tmp = ctx.root.make_node(os.sep.join((Context.waf_dir, 'waflib', 'extras', tool + '.py')))
+				tmp.write(web.read())
+				Logs.warn('Downloaded %s from %s' % (tool, url))
+				download_check(tmp)
+				try:
+					module = Context.load_tool(tool)
+				except:
+					Logs.warn('The tool %s from %s is unusable' % (tool, url))
+					try:
+						tmp.delete()
+					except:
+						pass
+					continue
+				return module
+	raise Errors.WafError('Could not load the Waf tool')
+
+class ConfigurationContext(Context.Context):
+	'''configures the project'''
+
+	cmd = 'configure'
+
+	error_handlers = []
+	"""
+	Additional functions to handle configuration errors
+	"""
+
+	def __init__(self, **kw):
+		super(ConfigurationContext, self).__init__(**kw)
+		self.environ = dict(os.environ)
+		self.all_envs = {}
+
+		self.top_dir = None
+		self.out_dir = None
+
+		self.tools = [] # tools loaded in the configuration, and that will be loaded when building
+
+		self.hash = 0
+		self.files = []
+
+		self.tool_cache = []
+
+		self.setenv('')
+
+	def setenv(self, name, env=None):
+		"""
+		Set a new config set for conf.env. If a config set of that name already exists,
+		recall it without modification.
+
+		The name is the filename prefix to save to ``c4che/NAME_cache.py``, and it
+		is also used as *variants* by the build commands.
+		Though related to variants, whatever kind of data may be stored in the config set::
+
+			def configure(cfg):
+				cfg.env.ONE = 1
+				cfg.setenv('foo')
+				cfg.env.ONE = 2
+
+			def build(bld):
+				2 == bld.env_of_name('foo').ONE
+
+		:param name: name of the configuration set
+		:type name: string
+		:param env: ConfigSet to copy, or an empty ConfigSet is created
+		:type env: :py:class:`waflib.ConfigSet.ConfigSet`
+		"""
+		if name not in self.all_envs or env:
+			if not env:
+				env = ConfigSet.ConfigSet()
+				self.prepare_env(env)
+			else:
+				env = env.derive()
+			self.all_envs[name] = env
+		self.variant = name
+
+	def get_env(self):
+		"""Getter for the env property"""
+		return self.all_envs[self.variant]
+	def set_env(self, val):
+		"""Setter for the env property"""
+		self.all_envs[self.variant] = val
+
+	env = property(get_env, set_env)
+
+	def init_dirs(self):
+		"""
+		Initialize the project directory and the build directory
+		"""
+
+		top = self.top_dir
+		if not top:
+			top = Options.options.top
+		if not top:
+			top = getattr(Context.g_module, Context.TOP, None)
+		if not top:
+			top = self.path.abspath()
+		top = os.path.abspath(top)
+
+		self.srcnode = (os.path.isabs(top) and self.root or self.path).find_dir(top)
+		assert(self.srcnode)
+
+		out = self.out_dir
+		if not out:
+			out = Options.options.out
+		if not out:
+			out = getattr(Context.g_module, Context.OUT, None)
+		if not out:
+			out = Options.lockfile.replace('.lock-waf_%s_' % sys.platform, '').replace('.lock-waf', '')
+
+		self.bldnode = (os.path.isabs(out) and self.root or self.path).make_node(out)
+		self.bldnode.mkdir()
+
+		if not os.path.isdir(self.bldnode.abspath()):
+			conf.fatal('could not create the build directory %s' % self.bldnode.abspath())
+
+	def execute(self):
+		"""
+		See :py:func:`waflib.Context.Context.execute`
+		"""
+		self.init_dirs()
+
+		self.cachedir = self.bldnode.make_node(Build.CACHE_DIR)
+		self.cachedir.mkdir()
+
+		path = os.path.join(self.bldnode.abspath(), WAF_CONFIG_LOG)
+		self.logger = Logs.make_logger(path, 'cfg')
+
+		app = getattr(Context.g_module, 'APPNAME', '')
+		if app:
+			ver = getattr(Context.g_module, 'VERSION', '')
+			if ver:
+				app = "%s (%s)" % (app, ver)
+
+		now = time.ctime()
+		pyver = sys.hexversion
+		systype = sys.platform
+		args = " ".join(sys.argv)
+		wafver = Context.WAFVERSION
+		abi = Context.ABI
+		self.to_log(conf_template % vars())
+
+		self.msg('Setting top to', self.srcnode.abspath())
+		self.msg('Setting out to', self.bldnode.abspath())
+
+		if id(self.srcnode) == id(self.bldnode):
+			Logs.warn('Setting top == out (remember to use "update_outputs")')
+		elif id(self.path) != id(self.srcnode):
+			if self.srcnode.is_child_of(self.path):
+				Logs.warn('Are you certain that you do not want to set top="." ?')
+
+		super(ConfigurationContext, self).execute()
+
+		self.store()
+
+		Context.top_dir = self.srcnode.abspath()
+		Context.out_dir = self.bldnode.abspath()
+
+		# this will write a configure lock so that subsequent builds will
+		# consider the current path as the root directory (see prepare_impl).
+		# to remove: use 'waf distclean'
+		env = ConfigSet.ConfigSet()
+		env['argv'] = sys.argv
+		env['options'] = Options.options.__dict__
+
+		env.run_dir = Context.run_dir
+		env.top_dir = Context.top_dir
+		env.out_dir = Context.out_dir
+
+		# conf.hash & conf.files hold wscript files paths and hash
+		# (used only by Configure.autoconfig)
+		env['hash'] = self.hash
+		env['files'] = self.files
+		env['environ'] = dict(self.environ)
+
+		if not self.env.NO_LOCK_IN_RUN:
+			env.store(Context.run_dir + os.sep + Options.lockfile)
+		if not self.env.NO_LOCK_IN_TOP:
+			env.store(Context.top_dir + os.sep + Options.lockfile)
+		if not self.env.NO_LOCK_IN_OUT:
+			env.store(Context.out_dir + os.sep + Options.lockfile)
+
+	def prepare_env(self, env):
+		"""
+		Insert *PREFIX*, *BINDIR* and *LIBDIR* values into ``env``
+
+		:type env: :py:class:`waflib.ConfigSet.ConfigSet`
+		:param env: a ConfigSet, usually ``conf.env``
+		"""
+		if not env.PREFIX:
+			env.PREFIX = os.path.abspath(os.path.expanduser(Options.options.prefix))
+		if not env.BINDIR:
+			env.BINDIR = Utils.subst_vars('${PREFIX}/bin', env)
+		if not env.LIBDIR:
+			env.LIBDIR = Utils.subst_vars('${PREFIX}/lib', env)
+
+	def store(self):
+		"""Save the config results into the cache file"""
+		n = self.cachedir.make_node('build.config.py')
+		n.write('version = 0x%x\ntools = %r\n' % (Context.HEXVERSION, self.tools))
+
+		if not self.all_envs:
+			self.fatal('nothing to store in the configuration context!')
+
+		for key in self.all_envs:
+			tmpenv = self.all_envs[key]
+			tmpenv.store(os.path.join(self.cachedir.abspath(), key + Build.CACHE_SUFFIX))
+
+	def load(self, input, tooldir=None, funs=None, download=True):
+		"""
+		Load Waf tools, which will be imported whenever a build is started.
+
+		:param input: waf tools to import
+		:type input: list of string
+		:param tooldir: paths for the imports
+		:type tooldir: list of string
+		:param funs: functions to execute from the waf tools
+		:type funs: list of string
+		:param download: whether to download the tool from the waf repository
+		:type download: bool
+		"""
+
+		tools = Utils.to_list(input)
+		if tooldir: tooldir = Utils.to_list(tooldir)
+		for tool in tools:
+			# avoid loading the same tool more than once with the same functions
+			# used by composite projects
+
+			mag = (tool, id(self.env), funs)
+			if mag in self.tool_cache:
+				self.to_log('(tool %s is already loaded, skipping)' % tool)
+				continue
+			self.tool_cache.append(mag)
+
+			module = None
+			try:
+				module = Context.load_tool(tool, tooldir)
+			except ImportError as e:
+				if Options.options.download:
+					module = download_tool(tool, ctx=self)
+					if not module:
+						self.fatal('Could not load the Waf tool %r or download a suitable replacement from the repository (sys.path %r)\n%s' % (tool, sys.path, e))
+				else:
+					self.fatal('Could not load the Waf tool %r from %r (try the --download option?):\n%s' % (tool, sys.path, e))
+			except Exception as e:
+				self.to_log('imp %r (%r & %r)' % (tool, tooldir, funs))
+				self.to_log(Utils.ex_stack())
+				raise
+
+			if funs is not None:
+				self.eval_rules(funs)
+			else:
+				func = getattr(module, 'configure', None)
+				if func:
+					if type(func) is type(Utils.readf): func(self)
+					else: self.eval_rules(func)
+
+			self.tools.append({'tool':tool, 'tooldir':tooldir, 'funs':funs})
+
+	def post_recurse(self, node):
+		"""
+		Records the path and a hash of the scripts visited, see :py:meth:`waflib.Context.Context.post_recurse`
+
+		:param node: script
+		:type node: :py:class:`waflib.Node.Node`
+		"""
+		super(ConfigurationContext, self).post_recurse(node)
+		self.hash = hash((self.hash, node.read('rb')))
+		self.files.append(node.abspath())
+
+	def eval_rules(self, rules):
+		"""
+		Execute the configuration tests. The method :py:meth:`waflib.Configure.ConfigurationContext.err_handler`
+		is used to process the eventual exceptions
+
+		:param rules: list of configuration method names
+		:type rules: list of string
+		"""
+		self.rules = Utils.to_list(rules)
+		for x in self.rules:
+			f = getattr(self, x)
+			if not f: self.fatal("No such method '%s'." % x)
+			try:
+				f()
+			except Exception as e:
+				ret = self.err_handler(x, e)
+				if ret == BREAK:
+					break
+				elif ret == CONTINUE:
+					continue
+				else:
+					raise
+
+	def err_handler(self, fun, error):
+		"""
+		Error handler for the configuration tests, the default is to let the exception raise
+
+		:param fun: configuration test
+		:type fun: method
+		:param error: exception
+		:type error: exception
+		"""
+		pass
+
+def conf(f):
+	"""
+	Decorator: attach new configuration functions to :py:class:`waflib.Build.BuildContext` and
+	:py:class:`waflib.Configure.ConfigurationContext`. The methods bound will accept a parameter
+	named 'mandatory' to disable the configuration errors::
+
+		def configure(conf):
+			conf.find_program('abc', mandatory=False)
+
+	:param f: method to bind
+	:type f: function
+	"""
+	def fun(*k, **kw):
+		mandatory = True
+		if 'mandatory' in kw:
+			mandatory = kw['mandatory']
+			del kw['mandatory']
+
+		try:
+			return f(*k, **kw)
+		except Errors.ConfigurationError as e:
+			if mandatory:
+				raise e
+
+	setattr(ConfigurationContext, f.__name__, fun)
+	setattr(Build.BuildContext, f.__name__, fun)
+	return f
+
+ at conf
+def add_os_flags(self, var, dest=None):
+	"""
+	Import operating system environment values into ``conf.env`` dict::
+
+		def configure(conf):
+			conf.add_os_flags('CFLAGS')
+
+	:param var: variable to use
+	:type var: string
+	:param dest: destination variable, by default the same as var
+	:type dest: string
+	"""
+	# do not use 'get' to make certain the variable is not defined
+	try: self.env.append_value(dest or var, shlex.split(self.environ[var]))
+	except KeyError: pass
+
+ at conf
+def cmd_to_list(self, cmd):
+	"""
+	Detect if a command is written in pseudo shell like ``ccache g++`` and return a list.
+
+	:param cmd: command
+	:type cmd: a string or a list of string
+	"""
+	if isinstance(cmd, str) and cmd.find(' '):
+		try:
+			os.stat(cmd)
+		except OSError:
+			return shlex.split(cmd)
+		else:
+			return [cmd]
+	return cmd
+
+ at conf
+def check_waf_version(self, mini='1.6.0', maxi='1.7.0'):
+	"""
+	check for the waf version
+
+	Versions should be supplied as hex. 0x01000000 means 1.0.0,
+	0x010408 means 1.4.8, etc.
+
+	:type  mini: number, tuple or string
+	:param mini: Minimum required version
+	:type  maxi: number, tuple or string
+	:param maxi: Maximum allowed version
+	"""
+	self.start_msg('Checking for waf version in %s-%s' % (str(mini), str(maxi)))
+	ver = Context.HEXVERSION
+	if Utils.num2ver(mini) > ver:
+		self.fatal('waf version should be at least %r (%r found)' % (Utils.num2ver(mini), ver))
+
+	if Utils.num2ver(maxi) < ver:
+		self.fatal('waf version should be at most %r (%r found)' % (Utils.num2ver(maxi), ver))
+	self.end_msg('ok')
+
+ at conf
+def find_file(self, filename, path_list=[]):
+	"""
+	Find a file in a list of paths
+
+	:param filename: name of the file to search for
+	:param path_list: list of directories to search
+	:return: the first occurrence filename or '' if filename could not be found
+	"""
+	for n in Utils.to_list(filename):
+		for d in Utils.to_list(path_list):
+			p = os.path.join(d, n)
+			if os.path.exists(p):
+				return p
+	self.fatal('Could not find %r' % filename)
+
+ at conf
+def find_program(self, filename, **kw):
+	"""
+	Search for a program on the operating system
+
+	When var is used, you may set os.environ[var] to help find a specific program version, for example::
+
+		$ VALAC=/usr/bin/valac_test waf configure
+
+	:param path_list: paths to use for searching
+	:type param_list: list of string
+	:param var: store the result to conf.env[var], by default use filename.upper()
+	:type var: string
+	:param ext: list of extensions for the binary (do not add an extension for portability)
+	:type ext: list of string
+	"""
+
+	exts = kw.get('exts', Utils.is_win32 and '.exe,.com,.bat,.cmd' or ',.sh,.pl,.py')
+
+	environ = kw.get('environ', os.environ)
+
+	ret = ''
+	filename = Utils.to_list(filename)
+
+	var = kw.get('var', '')
+	if not var:
+		var = filename[0].upper()
+
+	if self.env[var]:
+		ret = self.env[var]
+	elif var in environ:
+		ret = environ[var]
+
+	path_list = kw.get('path_list', '')
+	if not ret:
+		if path_list:
+			path_list = Utils.to_list(path_list)
+		else:
+			path_list = environ.get('PATH', '').split(os.pathsep)
+
+		if not isinstance(filename, list):
+			filename = [filename]
+
+		for a in exts.split(','):
+			if ret:
+				break
+			for b in filename:
+				if ret:
+					break
+				for c in path_list:
+					if ret:
+						break
+					x = os.path.expanduser(os.path.join(c, b + a))
+					if os.path.isfile(x):
+						ret = x
+
+	if not ret and Utils.winreg:
+		ret = Utils.get_registry_app_path(Utils.winreg.HKEY_CURRENT_USER, filename)
+	if not ret and Utils.winreg:
+		ret = Utils.get_registry_app_path(Utils.winreg.HKEY_LOCAL_MACHINE, filename)
+
+	self.msg('Checking for program ' + ','.join(filename), ret or False)
+	self.to_log('find program=%r paths=%r var=%r -> %r' % (filename, path_list, var, ret))
+
+	if not ret:
+		self.fatal(kw.get('errmsg', '') or 'Could not find the program %s' % ','.join(filename))
+
+	if var:
+		self.env[var] = ret
+	return ret
+
+
+ at conf
+def find_perl_program(self, filename, path_list=[], var=None, environ=None, exts=''):
+	"""
+	Search for a perl program on the operating system
+
+	:param filename: file to search for
+	:type filename: string
+	:param path_list: list of paths to look into
+	:type path_list: list of string
+	:param var: store the results into *conf.env.var*
+	:type var: string
+	:param environ: operating system environment to pass to :py:func:`waflib.Configure.find_program`
+	:type environ: dict
+	:param exts: extensions given to :py:func:`waflib.Configure.find_program`
+	:type exts: list
+	"""
+
+	try:
+		app = self.find_program(filename, path_list=path_list, var=var, environ=environ, exts=exts)
+	except:
+		self.find_program('perl', var='PERL')
+		app = self.find_file(filename, os.environ['PATH'].split(os.pathsep))
+		if not app:
+			raise
+		if var:
+			self.env[var] = Utils.to_list(self.env['PERL']) + [app]
+	self.msg('Checking for %r' % filename, app)
+
diff --git a/xpdeint/waf/waflib/Configure.pyc b/xpdeint/waf/waflib/Configure.pyc
new file mode 100644
index 0000000..f560aec
Binary files /dev/null and b/xpdeint/waf/waflib/Configure.pyc differ
diff --git a/xpdeint/waf/waflib/Context.py b/xpdeint/waf/waflib/Context.py
new file mode 100644
index 0000000..1196a97
--- /dev/null
+++ b/xpdeint/waf/waflib/Context.py
@@ -0,0 +1,595 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2010 (ita)
+
+"""
+Classes and functions required for waf commands
+"""
+
+import os, imp, sys
+from waflib import Utils, Errors, Logs
+import waflib.Node
+
+# the following 3 constants are updated on each new release (do not touch)
+HEXVERSION=0x1060900
+"""Constant updated on new releases"""
+
+WAFVERSION="1.6.9"
+"""Constant updated on new releases"""
+
+WAFREVISION="54dc13ba5f51bfe2ae277451ec5ac1d0a91c7aaf"
+"""Constant updated on new releases"""
+
+ABI = 98
+"""Version of the build data cache file format (used in :py:const:`waflib.Context.DBFILE`)"""
+
+DBFILE = '.wafpickle-%d' % ABI
+"""Name of the pickle file for storing the build data"""
+
+APPNAME = 'APPNAME'
+"""Default application name (used by ``waf dist``)"""
+
+VERSION = 'VERSION'
+"""Default application version (used by ``waf dist``)"""
+
+TOP  = 'top'
+"""The variable name for the top-level directory in wscript files"""
+
+OUT  = 'out'
+"""The variable name for the output directory in wscript files"""
+
+WSCRIPT_FILE = 'wscript'
+"""Name of the waf script files"""
+
+
+launch_dir = ''
+"""Directory from which waf has been called"""
+run_dir = ''
+"""Location of the wscript file to use as the entry point"""
+top_dir = ''
+"""Location of the project directory (top), if the project was configured"""
+out_dir = ''
+"""Location of the build directory (out), if the project was configured"""
+waf_dir = ''
+"""Directory containing the waf modules"""
+
+local_repo = ''
+"""Local repository containing additional Waf tools (plugins)"""
+remote_repo = 'http://waf.googlecode.com/git/'
+"""
+Remote directory containing downloadable waf tools. The missing tools can be downloaded by using::
+
+	$ waf configure --download
+"""
+
+remote_locs = ['branches/waf-%s/waflib/extras' % WAFVERSION, 'trunk/waflib/extras', 'trunk/waflib/Tools']
+"""
+Remote directories for use with :py:const:`waflib.Context.remote_repo`
+"""
+
+g_module = None
+"""
+Module representing the main wscript file (see :py:const:`waflib.Context.run_dir`)
+"""
+
+STDOUT = 1
+STDERR = -1
+BOTH   = 0
+
+classes = []
+"""
+List of :py:class:`waflib.Context.Context` subclasses that can be used as waf commands. The classes
+are added automatically by a metaclass.
+"""
+
+
+def create_context(cmd_name, *k, **kw):
+	"""
+	Create a new :py:class:`waflib.Context.Context` instance corresponding to the given command.
+	Used in particular by :py:func:`waflib.Scripting.run_command`
+
+	:param cmd_name: command
+	:type cmd_name: string
+	:param k: arguments to give to the context class initializer
+	:type k: list
+	:param k: keyword arguments to give to the context class initializer
+	:type k: dict
+	"""
+	global classes
+	for x in classes:
+		if x.cmd == cmd_name:
+			return x(*k, **kw)
+	ctx = Context(*k, **kw)
+	ctx.fun = cmd_name
+	return ctx
+
+class store_context(type):
+	"""
+	Metaclass for storing the command classes into the list :py:const:`waflib.Context.classes`
+	Context classes must provide an attribute 'cmd' representing the command to execute
+	"""
+	def __init__(cls, name, bases, dict):
+		super(store_context, cls).__init__(name, bases, dict)
+		name = cls.__name__
+
+		if name == 'ctx' or name == 'Context':
+			return
+
+		try:
+			cls.cmd
+		except AttributeError:
+			raise Errors.WafError('Missing command for the context class %r (cmd)' % name)
+
+		if not getattr(cls, 'fun', None):
+			cls.fun = cls.cmd
+
+		global classes
+		classes.insert(0, cls)
+
+ctx = store_context('ctx', (object,), {})
+"""Base class for the :py:class:`waflib.Context.Context` classes"""
+
+class Context(ctx):
+	"""
+	Default context for waf commands, and base class for new command contexts.
+
+	Context objects are passed to top-level functions::
+
+		def foo(ctx):
+			print(ctx.__class__.__name__) # waflib.Context.Context
+
+	Subclasses must define the attribute 'cmd':
+
+	:param cmd: command to execute as in ``waf cmd``
+	:type cmd: string
+	:param fun: function name to execute when the command is called
+	:type fun: string
+
+	.. inheritance-diagram:: waflib.Context.Context waflib.Build.BuildContext waflib.Build.InstallContext waflib.Build.UninstallContext waflib.Build.StepContext waflib.Build.ListContext waflib.Configure.ConfigurationContext waflib.Scripting.Dist waflib.Scripting.DistCheck waflib.Build.CleanContext
+
+	"""
+
+	errors = Errors
+	"""
+	Shortcut to :py:mod:`waflib.Errors` provided for convenience
+	"""
+
+	tools = {}
+	"""
+	A cache for modules (wscript files) read by :py:meth:`Context.Context.load`
+	"""
+
+	def __init__(self, **kw):
+		try:
+			rd = kw['run_dir']
+		except KeyError:
+			global run_dir
+			rd = run_dir
+
+		# binds the context to the nodes in use to avoid a context singleton
+		class node_class(waflib.Node.Node):
+			pass
+		self.node_class = node_class
+		self.node_class.__module__ = "waflib.Node"
+		self.node_class.__name__ = "Nod3"
+		self.node_class.ctx = self
+
+		self.root = self.node_class('', None)
+		self.cur_script = None
+		self.path = self.root.find_dir(rd)
+
+		self.stack_path = []
+		self.exec_dict = {'ctx':self, 'conf':self, 'bld':self, 'opt':self}
+		self.logger = None
+
+	def __hash__(self):
+		"""
+		Return a hash value for storing context objects in dicts or sets. The value is not persistent.
+
+		:return: hash value
+		:rtype: int
+		"""
+		return id(self)
+
+	def load(self, tool_list, *k, **kw):
+		"""
+		Load a Waf tool as a module, and try calling the function named :py:const:`waflib.Context.Context.fun` from it.
+		A ``tooldir`` value may be provided as a list of module paths.
+
+		:type tool_list: list of string or space-separated string
+		:param tool_list: list of Waf tools to use
+		"""
+		tools = Utils.to_list(tool_list)
+		path = Utils.to_list(kw.get('tooldir', ''))
+
+		for t in tools:
+			module = load_tool(t, path)
+			fun = getattr(module, kw.get('name', self.fun), None)
+			if fun:
+				fun(self)
+
+	def execute(self):
+		"""
+		Execute the command. Redefine this method in subclasses.
+		"""
+		global g_module
+		self.recurse([os.path.dirname(g_module.root_path)])
+
+	def pre_recurse(self, node):
+		"""
+		Method executed immediately before a folder is read by :py:meth:`waflib.Context.Context.recurse`. The node given is set
+		as an attribute ``self.cur_script``, and as the current path ``self.path``
+
+		:param node: script
+		:type node: :py:class:`waflib.Node.Node`
+		"""
+		self.stack_path.append(self.cur_script)
+
+		self.cur_script = node
+		self.path = node.parent
+
+	def post_recurse(self, node):
+		"""
+		Restore ``self.cur_script`` and ``self.path`` right after :py:meth:`waflib.Context.Context.recurse` terminates.
+
+		:param node: script
+		:type node: :py:class:`waflib.Node.Node`
+		"""
+		self.cur_script = self.stack_path.pop()
+		if self.cur_script:
+			self.path = self.cur_script.parent
+
+	def recurse(self, dirs, name=None, mandatory=True, once=True):
+		"""
+		Run user code from the supplied list of directories.
+		The directories can be either absolute, or relative to the directory
+		of the wscript file. The methods :py:meth:`waflib.Context.Context.pre_recurse` and :py:meth:`waflib.Context.Context.post_recurse`
+		are called immediately before and after a script has been executed.
+
+		:param dirs: List of directories to visit
+		:type dirs: list of string or space-separated string
+		:param name: Name of function to invoke from the wscript
+		:type  name: string
+		:param mandatory: whether sub wscript files are required to exist
+		:type  mandatory: bool
+		:param once: read the script file once for a particular context
+		:type once: bool
+		"""
+		try:
+			cache = self.recurse_cache
+		except:
+			cache = self.recurse_cache = {}
+
+		for d in Utils.to_list(dirs):
+
+			if not os.path.isabs(d):
+				# absolute paths only
+				d = os.path.join(self.path.abspath(), d)
+
+			WSCRIPT     = os.path.join(d, WSCRIPT_FILE)
+			WSCRIPT_FUN = WSCRIPT + '_' + (name or self.fun)
+
+			node = self.root.find_node(WSCRIPT_FUN)
+			if node and (not once or node not in cache):
+				cache[node] = True
+				self.pre_recurse(node)
+				try:
+					function_code = node.read('rU')
+					exec(compile(function_code, node.abspath(), 'exec'), self.exec_dict)
+				finally:
+					self.post_recurse(node)
+			elif not node:
+				node = self.root.find_node(WSCRIPT)
+				if node and (not once or node not in cache):
+					cache[node] = True
+					self.pre_recurse(node)
+					try:
+						wscript_module = load_module(node.abspath())
+						user_function = getattr(wscript_module, (name or self.fun), None)
+						if not user_function:
+							if not mandatory:
+								continue
+							raise Errors.WafError('No function %s defined in %s' % (name or self.fun, node.abspath()))
+						user_function(self)
+					finally:
+						self.post_recurse(node)
+				elif not node:
+					if not mandatory:
+						continue
+					raise Errors.WafError('No wscript file in directory %s' % d)
+
+	def exec_command(self, cmd, **kw):
+		"""
+		Execute a command and return the exit status. If the context has the attribute 'log',
+		capture and log the process stderr/stdout for logging purposes::
+
+			def run(tsk):
+				ret = tsk.generator.bld.exec_command('touch foo.txt')
+				return ret
+
+		Do not confuse this method with :py:meth:`waflib.Context.Context.cmd_and_log` which is used to
+		return the standard output/error values.
+
+		:param cmd: command argument for subprocess.Popen
+		:param kw: keyword arguments for subprocess.Popen
+		"""
+		subprocess = Utils.subprocess
+		kw['shell'] = isinstance(cmd, str)
+		Logs.debug('runner: %r' % cmd)
+		Logs.debug('runner_env: kw=%s' % kw)
+
+		try:
+			if self.logger:
+				# warning: may deadlock with a lot of output (subprocess limitation)
+
+				self.logger.info(cmd)
+
+				kw['stdout'] = kw['stderr'] = subprocess.PIPE
+				p = subprocess.Popen(cmd, **kw)
+				(out, err) = p.communicate()
+				if out:
+					self.logger.debug('out: %s' % out.decode(sys.stdout.encoding or 'iso8859-1'))
+				if err:
+					self.logger.error('err: %s' % err.decode(sys.stdout.encoding or 'iso8859-1'))
+				return p.returncode
+			else:
+				p = subprocess.Popen(cmd, **kw)
+				return p.wait()
+		except OSError:
+			return -1
+
+	def cmd_and_log(self, cmd, **kw):
+		"""
+		Execute a command and return stdout if the execution is successful.
+		An exception is thrown when the exit status is non-0. In that case, both stderr and stdout
+		will be bound to the WafError object::
+
+			def configure(conf):
+				out = conf.cmd_and_log(['echo', 'hello'], output=waflib.Context.STDOUT, quiet=waflib.Context.BOTH)
+				(out, err) = conf.cmd_and_log(['echo', 'hello'], output=waflib.Context.BOTH)
+				try:
+					conf.cmd_and_log(['which', 'someapp'], output=waflib.Context.BOTH)
+				except Exception as e:
+					print(e.stdout, e.stderr)
+
+		:param cmd: args for subprocess.Popen
+		:param kw: keyword arguments for subprocess.Popen
+		"""
+		subprocess = Utils.subprocess
+		kw['shell'] = isinstance(cmd, str)
+		Logs.debug('runner: %r' % cmd)
+
+		if 'quiet' in kw:
+			quiet = kw['quiet']
+			del kw['quiet']
+		else:
+			quiet = None
+
+		if 'output' in kw:
+			to_ret = kw['output']
+			del kw['output']
+		else:
+			to_ret = STDOUT
+
+		kw['stdout'] = kw['stderr'] = subprocess.PIPE
+		if quiet is None:
+			self.to_log(cmd)
+		try:
+			p = subprocess.Popen(cmd, **kw)
+			(out, err) = p.communicate()
+		except Exception as e:
+			raise Errors.WafError('Execution failure: %s' % str(e), ex=e)
+
+		if not isinstance(out, str):
+			out = out.decode(sys.stdout.encoding or 'iso8859-1')
+		if not isinstance(err, str):
+			err = err.decode(sys.stdout.encoding or 'iso8859-1')
+
+		if out and quiet != STDOUT and quiet != BOTH:
+			self.to_log('out: %s' % out)
+		if err and quiet != STDERR and quiet != BOTH:
+			self.to_log('err: %s' % err)
+
+		if p.returncode:
+			e = Errors.WafError('Command %r returned %r' % (cmd, p.returncode))
+			e.returncode = p.returncode
+			e.stderr = err
+			e.stdout = out
+			raise e
+
+		if to_ret == BOTH:
+			return (out, err)
+		elif to_ret == STDERR:
+			return err
+		return out
+
+	def fatal(self, msg, ex=None):
+		"""
+		Raise a configuration error to interrupt the execution immediately::
+
+			def configure(conf):
+				conf.fatal('a requirement is missing')
+
+		:param msg: message to display
+		:type msg: string
+		:param ex: optional exception object
+		:type ex: exception
+		"""
+		if self.logger:
+			self.logger.info('from %s: %s' % (self.path.abspath(), msg))
+		try:
+			msg = '%s\n(complete log in %s)' % (msg, self.logger.handlers[0].baseFilename)
+		except:
+			pass
+		raise self.errors.ConfigurationError(msg, ex=ex)
+
+	def to_log(self, msg):
+		"""
+		Log some information to the logger (if present), or to stderr. If the message is empty,
+		it is not printed::
+
+			def build(bld):
+				bld.to_log('starting the build')
+
+		When in doubt, override this method, or provide a logger on the context class.
+
+		:param msg: message
+		:type msg: string
+		"""
+		if not msg:
+			return
+		if self.logger:
+			self.logger.info(msg)
+		else:
+			sys.stderr.write(str(msg))
+			sys.stderr.flush()
+
+
+	def msg(self, msg, result, color=None):
+		"""
+		Print a configuration message of the form ``msg: result``.
+		The second part of the message will be in colors. The output
+		can be disabled easly by setting ``in_msg`` to a positive value::
+
+			def configure(conf):
+				self.in_msg = 1
+				conf.msg('Checking for library foo', 'ok')
+				# no output
+
+		:param msg: message to display to the user
+		:type msg: string
+		:param result: result to display
+		:type result: string or boolean
+		:param color: color to use, see :py:const:`waflib.Logs.colors_lst`
+		:type color: string
+		"""
+		self.start_msg(msg)
+
+		if not isinstance(color, str):
+			color = result and 'GREEN' or 'YELLOW'
+
+		self.end_msg(result, color)
+
+	def start_msg(self, msg):
+		"""
+		Print the beginning of a 'Checking for xxx' message. See :py:meth:`waflib.Context.Context.msg`
+		"""
+		try:
+			if self.in_msg:
+				self.in_msg += 1
+				return
+		except:
+			self.in_msg = 0
+		self.in_msg += 1
+
+		try:
+			self.line_just = max(self.line_just, len(msg))
+		except AttributeError:
+			self.line_just = max(40, len(msg))
+		for x in (self.line_just * '-', msg):
+			self.to_log(x)
+		Logs.pprint('NORMAL', "%s :" % msg.ljust(self.line_just), sep='')
+
+	def end_msg(self, result, color=None):
+		"""Print the end of a 'Checking for' message. See :py:meth:`waflib.Context.Context.msg`"""
+		self.in_msg -= 1
+		if self.in_msg:
+			return
+
+		defcolor = 'GREEN'
+		if result == True:
+			msg = 'ok'
+		elif result == False:
+			msg = 'not found'
+			defcolor = 'YELLOW'
+		else:
+			msg = str(result)
+
+		self.to_log(msg)
+		Logs.pprint(color or defcolor, msg)
+
+
+	def load_special_tools(self, var, ban=[]):
+		global waf_dir
+		lst = self.root.find_node(waf_dir).find_node('waflib/extras').ant_glob(var)
+		for x in lst:
+			if not x.name in ban:
+				load_tool(x.name.replace('.py', ''))
+
+cache_modules = {}
+"""
+Dictionary holding already loaded modules, keyed by their absolute path.
+The modules are added automatically by :py:func:`waflib.Context.load_module`
+"""
+
+def load_module(path):
+	"""
+	Load a source file as a python module.
+
+	:param path: file path
+	:type path: string
+	:return: Loaded Python module
+	:rtype: module
+	"""
+	try:
+		return cache_modules[path]
+	except KeyError:
+		pass
+
+	module = imp.new_module(WSCRIPT_FILE)
+	try:
+		code = Utils.readf(path, m='rU')
+	except (IOError, OSError):
+		raise Errors.WafError('Could not read the file %r' % path)
+
+	module_dir = os.path.dirname(path)
+	sys.path.insert(0, module_dir)
+
+	exec(compile(code, path, 'exec'), module.__dict__)
+	sys.path.remove(module_dir)
+
+	cache_modules[path] = module
+
+	return module
+
+def load_tool(tool, tooldir=None):
+	"""
+	Import a Waf tool (python module), and store it in the dict :py:const:`waflib.Context.Context.tools`
+
+	:type  tool: string
+	:param tool: Name of the tool
+	:type  tooldir: list
+	:param tooldir: List of directories to search for the tool module
+	"""
+	tool = tool.replace('++', 'xx')
+	tool = tool.replace('java', 'javaw')
+	tool = tool.replace('compiler_cc', 'compiler_c')
+
+	if tooldir:
+		assert isinstance(tooldir, list)
+		sys.path = tooldir + sys.path
+		try:
+			__import__(tool)
+			ret = sys.modules[tool]
+			Context.tools[tool] = ret
+			return ret
+		finally:
+			for d in tooldir:
+				sys.path.remove(d)
+	else:
+		global waf_dir
+		try:
+			os.stat(os.path.join(waf_dir, 'waflib', 'extras', tool + '.py'))
+			d = 'waflib.extras.%s' % tool
+		except:
+			try:
+				os.stat(os.path.join(waf_dir, 'waflib', 'Tools', tool + '.py'))
+				d = 'waflib.Tools.%s' % tool
+			except:
+				d = tool # user has messed with sys.path
+
+		__import__(d)
+		ret = sys.modules[d]
+		Context.tools[tool] = ret
+		return ret
+
diff --git a/xpdeint/waf/waflib/Context.pyc b/xpdeint/waf/waflib/Context.pyc
new file mode 100644
index 0000000..21ebfe1
Binary files /dev/null and b/xpdeint/waf/waflib/Context.pyc differ
diff --git a/xpdeint/waf/waflib/Errors.py b/xpdeint/waf/waflib/Errors.py
new file mode 100644
index 0000000..104f7d8
--- /dev/null
+++ b/xpdeint/waf/waflib/Errors.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2010 (ita)
+
+"""
+Exceptions used in the Waf code
+"""
+
+import traceback, sys
+
+class WafError(Exception):
+	"""Base class for all Waf errors"""
+	def __init__(self, msg='', ex=None):
+		"""
+		:param msg: error message
+		:type msg: string
+		:param ex: exception causing this error (optional)
+		:type ex: exception
+		"""
+		self.msg = msg
+		assert not isinstance(msg, Exception)
+
+		self.stack = []
+		if ex:
+			if not msg:
+				self.msg = str(ex)
+			if isinstance(ex, WafError):
+				self.stack = ex.stack
+			else:
+				self.stack = traceback.extract_tb(sys.exc_info()[2])
+		self.stack += traceback.extract_stack()[:-1]
+		self.verbose_msg = ''.join(traceback.format_list(self.stack))
+
+	def __str__(self):
+		return str(self.msg)
+
+class BuildError(WafError):
+	"""
+	Errors raised during the build and install phases
+	"""
+	def __init__(self, error_tasks=[]):
+		"""
+		:param error_tasks: tasks that could not complete normally
+		:type error_tasks: list of task objects
+		"""
+		self.tasks = error_tasks
+		WafError.__init__(self, self.format_error())
+
+	def format_error(self):
+		"""format the error messages from the tasks that failed"""
+		lst = ['Build failed']
+		for tsk in self.tasks:
+			txt = tsk.format_error()
+			if txt: lst.append(txt)
+		return '\n'.join(lst)
+
+class ConfigurationError(WafError):
+	"""
+	Configuration exception raised in particular by :py:meth:`waflib.Context.Context.fatal`
+	"""
+	pass
+
+class TaskRescan(WafError):
+	"""task-specific exception type, trigger a signature recomputation"""
+	pass
+
+class TaskNotReady(WafError):
+	"""task-specific exception type, raised when the task signature cannot be computed"""
+	pass
+
diff --git a/xpdeint/waf/waflib/Errors.pyc b/xpdeint/waf/waflib/Errors.pyc
new file mode 100644
index 0000000..5e88127
Binary files /dev/null and b/xpdeint/waf/waflib/Errors.pyc differ
diff --git a/xpdeint/waf/waflib/Logs.py b/xpdeint/waf/waflib/Logs.py
new file mode 100644
index 0000000..a88ef0a
--- /dev/null
+++ b/xpdeint/waf/waflib/Logs.py
@@ -0,0 +1,274 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005-2010 (ita)
+
+"""
+logging, colors, terminal width and pretty-print
+"""
+
+import os, re, traceback, sys
+
+_nocolor = os.environ.get('NOCOLOR', 'no') not in ('no', '0', 'false')
+try:
+	if not _nocolor:
+		import waflib.ansiterm
+except:
+	# optional module for colors on win32, just ignore if it cannot be imported
+	pass
+
+import logging # do it after
+
+LOG_FORMAT = "%(asctime)s %(c1)s%(zone)s%(c2)s %(message)s"
+HOUR_FORMAT = "%H:%M:%S"
+
+zones = ''
+verbose = 0
+
+colors_lst = {
+'USE' : True,
+'BOLD'  :'\x1b[01;1m',
+'RED'   :'\x1b[01;31m',
+'GREEN' :'\x1b[32m',
+'YELLOW':'\x1b[33m',
+'PINK'  :'\x1b[35m',
+'BLUE'  :'\x1b[01;34m',
+'CYAN'  :'\x1b[36m',
+'NORMAL':'\x1b[0m',
+'cursor_on'  :'\x1b[?25h',
+'cursor_off' :'\x1b[?25l',
+}
+
+got_tty = not os.environ.get('TERM', 'dumb') in ['dumb', 'emacs']
+if got_tty:
+	try:
+		got_tty = sys.stderr.isatty()
+	except AttributeError:
+		got_tty = False
+
+if (not got_tty and os.environ.get('TERM', 'dumb') != 'msys') or _nocolor:
+	colors_lst['USE'] = False
+
+def get_term_cols():
+	return 80
+
+# If console packages are available, replace the dummy function with a real
+# implementation
+try:
+	import struct, fcntl, termios
+except ImportError:
+	pass
+else:
+	if got_tty:
+		def get_term_cols_real():
+			"""
+			Private use only.
+			"""
+
+			dummy_lines, cols = struct.unpack("HHHH", \
+			fcntl.ioctl(sys.stderr.fileno(),termios.TIOCGWINSZ , \
+			struct.pack("HHHH", 0, 0, 0, 0)))[:2]
+			return cols
+		# try the function once to see if it really works
+		try:
+			get_term_cols_real()
+		except:
+			pass
+		else:
+			get_term_cols = get_term_cols_real
+
+get_term_cols.__doc__ = """
+	Get the console width in characters.
+
+	:return: the number of characters per line
+	:rtype: int
+	"""
+
+def get_color(cl):
+	if not colors_lst['USE']: return ''
+	return colors_lst.get(cl, '')
+
+class color_dict(object):
+	"""attribute-based color access, eg: colors.PINK"""
+	def __getattr__(self, a):
+		return get_color(a)
+	def __call__(self, a):
+		return get_color(a)
+
+colors = color_dict()
+
+re_log = re.compile(r'(\w+): (.*)', re.M)
+class log_filter(logging.Filter):
+	"""
+	The waf logs are of the form 'name: message', and can be filtered by 'waf --zones=name'.
+	For example, the following::
+
+		from waflib import Logs
+		Logs.debug('test: here is a message')
+
+	Will be displayed only when executing::
+
+		$ waf --zones=test
+	"""
+	def __init__(self, name=None):
+		pass
+
+	def filter(self, rec):
+		"""
+		filter a record, adding the colors automatically
+
+		* error: red
+		* warning: yellow
+
+		:param rec: message to record
+		"""
+
+		rec.c1 = colors.PINK
+		rec.c2 = colors.NORMAL
+		rec.zone = rec.module
+		if rec.levelno >= logging.INFO:
+			if rec.levelno >= logging.ERROR:
+				rec.c1 = colors.RED
+			elif rec.levelno >= logging.WARNING:
+				rec.c1 = colors.YELLOW
+			else:
+				rec.c1 = colors.GREEN
+			return True
+
+		m = re_log.match(rec.msg)
+		if m:
+			rec.zone = m.group(1)
+			rec.msg = m.group(2)
+
+		if zones:
+			return getattr(rec, 'zone', '') in zones or '*' in zones
+		elif not verbose > 2:
+			return False
+		return True
+
+class formatter(logging.Formatter):
+	"""Simple log formatter which handles colors"""
+	def __init__(self):
+		logging.Formatter.__init__(self, LOG_FORMAT, HOUR_FORMAT)
+
+	def format(self, rec):
+		"""Messages in warning, error or info mode are displayed in color by default"""
+		if rec.levelno >= logging.WARNING or rec.levelno == logging.INFO:
+			try:
+				msg = rec.msg.decode('utf-8')
+			except:
+				msg = rec.msg
+			return '%s%s%s' % (rec.c1, msg, rec.c2)
+		return logging.Formatter.format(self, rec)
+
+log = None
+"""global logger for Logs.debug, Logs.error, etc"""
+
+def debug(*k, **kw):
+	"""
+	Wrap logging.debug, the output is filtered for performance reasons
+	"""
+	if verbose:
+		k = list(k)
+		k[0] = k[0].replace('\n', ' ')
+		global log
+		log.debug(*k, **kw)
+
+def error(*k, **kw):
+	"""
+	Wrap logging.errors, display the origin of the message when '-vv' is set
+	"""
+	global log
+	log.error(*k, **kw)
+	if verbose > 2:
+		st = traceback.extract_stack()
+		if st:
+			st = st[:-1]
+			buf = []
+			for filename, lineno, name, line in st:
+				buf.append('  File "%s", line %d, in %s' % (filename, lineno, name))
+				if line:
+					buf.append('	%s' % line.strip())
+			if buf: log.error("\n".join(buf))
+
+def warn(*k, **kw):
+	"""
+	Wrap logging.warn
+	"""
+	global log
+	log.warn(*k, **kw)
+
+def info(*k, **kw):
+	"""
+	Wrap logging.info
+	"""
+	global log
+	log.info(*k, **kw)
+
+def init_log():
+	"""
+	Initialize the loggers globally
+	"""
+	global log
+	log = logging.getLogger('waflib')
+	log.handlers = []
+	log.filters = []
+	hdlr = logging.StreamHandler()
+	hdlr.setFormatter(formatter())
+	log.addHandler(hdlr)
+	log.addFilter(log_filter())
+	log.setLevel(logging.DEBUG)
+
+def make_logger(path, name):
+	"""
+	Create a simple logger, which is often used to redirect the context command output::
+
+		from waflib import Logs
+		bld.logger = Logs.make_logger('test.log', 'build')
+		bld.check(header_name='sadlib.h', features='cxx cprogram', mandatory=False)
+		bld.logger = None
+
+	:param path: file name to write the log output to
+	:type path: string
+	:param name: logger name (loggers are reused)
+	:type name: string
+	"""
+	logger = logging.getLogger(name)
+	hdlr = logging.FileHandler(path, 'w')
+	formatter = logging.Formatter('%(message)s')
+	hdlr.setFormatter(formatter)
+	logger.addHandler(hdlr)
+	logger.setLevel(logging.DEBUG)
+	return logger
+
+def make_mem_logger(name, to_log, size=10000):
+	"""
+	Create a memory logger to avoid writing concurrently to the main logger
+	"""
+	from logging.handlers import MemoryHandler
+	logger = logging.getLogger(name)
+	hdlr = MemoryHandler(size, target=to_log)
+	formatter = logging.Formatter('%(message)s')
+	hdlr.setFormatter(formatter)
+	logger.addHandler(hdlr)
+	logger.memhandler = hdlr
+	logger.setLevel(logging.DEBUG)
+	return logger
+
+def pprint(col, str, label='', sep='\n'):
+	"""
+	Print messages in color immediately on stderr::
+
+		from waflib import Logs
+		Logs.pprint('RED', 'Something bad just happened')
+
+	:param col: color name to use in :py:const:`Logs.colors_lst`
+	:type col: string
+	:param str: message to display
+	:type str: string or a value that can be printed by %s
+	:param label: a message to add after the colored output
+	:type label: string
+	:param sep: a string to append at the end (line separator)
+	:type sep: string
+	"""
+	sys.stderr.write("%s%s%s %s%s" % (colors(col), str, colors.NORMAL, label, sep))
+
diff --git a/xpdeint/waf/waflib/Logs.pyc b/xpdeint/waf/waflib/Logs.pyc
new file mode 100644
index 0000000..56c5fba
Binary files /dev/null and b/xpdeint/waf/waflib/Logs.pyc differ
diff --git a/xpdeint/waf/waflib/Node.py b/xpdeint/waf/waflib/Node.py
new file mode 100644
index 0000000..a7571c3
--- /dev/null
+++ b/xpdeint/waf/waflib/Node.py
@@ -0,0 +1,845 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005-2010 (ita)
+
+"""
+Node: filesystem structure, contains lists of nodes
+
+#. Each file/folder is represented by exactly one node.
+
+#. Some potential class properties are stored on :py:class:`waflib.Build.BuildContext` : nodes to depend on, etc.
+   Unused class members can increase the `.wafpickle` file size sensibly.
+
+#. Node objects should never be created directly, use
+   the methods :py:func:`Node.make_node` or :py:func:`Node.find_node`
+
+#. The methods :py:func:`Node.find_resource`, :py:func:`Node.find_dir` :py:func:`Node.find_or_declare` should be
+   used when a build context is present
+
+#. Each instance of :py:class:`waflib.Context.Context` has a unique :py:class:`Node` subclass.
+   (:py:class:`waflib.Node.Nod3`, see the :py:class:`waflib.Context.Context` initializer). A reference to the context owning a node is held as self.ctx
+"""
+
+import os, re, sys, shutil
+from waflib import Utils, Errors
+
+exclude_regs = '''
+**/*~
+**/#*#
+**/.#*
+**/%*%
+**/._*
+**/CVS
+**/CVS/**
+**/.cvsignore
+**/SCCS
+**/SCCS/**
+**/vssver.scc
+**/.svn
+**/.svn/**
+**/BitKeeper
+**/.git
+**/.git/**
+**/.gitignore
+**/.bzr
+**/.bzrignore
+**/.bzr/**
+**/.hg
+**/.hg/**
+**/_MTN
+**/_MTN/**
+**/.arch-ids
+**/{arch}
+**/_darcs
+**/_darcs/**
+**/.DS_Store'''
+"""
+Ant patterns for files and folders to exclude while doing the
+recursive traversal in :py:meth:`waflib.Node.Node.ant_glob`
+"""
+
+# TODO optimize split_path by performing a replacement when unpacking?
+
+def split_path(path):
+	"""
+	Split a path by os.sep (This is not os.path.split)
+
+	:param path: path to split
+	:type path: string
+	:rtype: list of string
+	:return: the path, split
+	"""
+	return path.split('/')
+
+def split_path_cygwin(path):
+	if path.startswith('//'):
+		ret = path.split('/')[2:]
+		ret[0] = '/' + ret[0]
+		return ret
+	return path.split('/')
+
+re_sp = re.compile('[/\\\\]')
+def split_path_win32(path):
+	if path.startswith('\\\\'):
+		ret = re.split(re_sp, path)[2:]
+		ret[0] = '\\' + ret[0]
+		return ret
+	return re.split(re_sp, path)
+
+if sys.platform == 'cygwin':
+	split_path = split_path_cygwin
+elif Utils.is_win32:
+	split_path = split_path_win32
+
+class Node(object):
+	"""
+	This class is organized in two parts
+
+	* The basic methods meant for filesystem access (compute paths, create folders, etc)
+	* The methods bound to a :py:class:`waflib.Build.BuildContext` (require ``bld.srcnode`` and ``bld.bldnode``)
+	"""
+
+	__slots__ = ('name', 'sig', 'children', 'parent', 'cache_abspath', 'cache_isdir')
+	def __init__(self, name, parent):
+		self.name = name
+		self.parent = parent
+
+		if parent:
+			if name in parent.children:
+				raise Errors.WafError('node %s exists in the parent files %r already' % (name, parent))
+			parent.children[name] = self
+
+	def __setstate__(self, data):
+		"Deserializes from data"
+		self.name = data[0]
+		self.parent = data[1]
+		if data[2] is not None:
+			self.children = data[2]
+		if data[3] is not None:
+			self.sig = data[3]
+
+	def __getstate__(self):
+		"Serialize the node info"
+		return (self.name, self.parent, getattr(self, 'children', None), getattr(self, 'sig', None))
+
+	def __str__(self):
+		"String representation (name), for debugging purposes"
+		return self.name
+
+	def __repr__(self):
+		"String representation (abspath), for debugging purposes"
+		return self.abspath()
+
+	def __hash__(self):
+		"Node hash, used for storage in dicts. This hash is not persistent."
+		return id(self)
+
+	def __eq__(self, node):
+		"Node comparison, based on the IDs"
+		return id(self) == id(node)
+
+	def __copy__(self):
+		"Implemented to prevent nodes from being copied (raises an exception)"
+		raise Errors.WafError('nodes are not supposed to be copied')
+
+	def read(self, flags='r'):
+		"""
+		Return the contents of the file represented by this node::
+
+			def build(bld):
+				bld.path.find_node('wscript').read()
+
+		:type  fname: string
+		:param fname: Path to file
+		:type  m: string
+		:param m: Open mode
+		:rtype: string
+		:return: File contents
+		"""
+		return Utils.readf(self.abspath(), flags)
+
+	def write(self, data, flags='w'):
+		"""
+		Write some text to the physical file represented by this node::
+
+			def build(bld):
+				bld.path.make_node('foo.txt').write('Hello, world!')
+
+		:type  data: string
+		:param data: data to write
+		:type  flags: string
+		:param flags: Write mode
+		"""
+		f = None
+		try:
+			f = open(self.abspath(), flags)
+			f.write(data)
+		finally:
+			if f:
+				f.close()
+
+	def chmod(self, val):
+		"""
+		Change file/dir permissions::
+
+			def build(bld):
+				bld.path.chmod(493) # 0755
+		"""
+		os.chmod(self.abspath(), val)
+
+	def delete(self):
+		"""Delete the file/folder physically (but not the node)"""
+		try:
+			if getattr(self, 'children', None):
+				shutil.rmtree(self.abspath())
+			else:
+				os.unlink(self.abspath())
+		except:
+			pass
+
+		try:
+			delattr(self, 'children')
+		except:
+			pass
+
+	def suffix(self):
+		"""Return the file extension"""
+		k = max(0, self.name.rfind('.'))
+		return self.name[k:]
+
+	def height(self):
+		"""Depth in the folder hierarchy from the filesystem root or from all the file drives"""
+		d = self
+		val = -1
+		while d:
+			d = d.parent
+			val += 1
+		return val
+
+	def listdir(self):
+		"""List the folder contents"""
+		lst = Utils.listdir(self.abspath())
+		lst.sort()
+		return lst
+
+	def mkdir(self):
+		"""
+		Create a folder represented by this node, creating intermediate nodes as needed
+		An exception will be raised only when the folder cannot possibly exist there
+		"""
+		if getattr(self, 'cache_isdir', None):
+			return
+
+		try:
+			self.parent.mkdir()
+		except:
+			pass
+
+		if self.name:
+			try:
+				os.makedirs(self.abspath())
+			except OSError:
+				pass
+
+			if not os.path.isdir(self.abspath()):
+				raise Errors.WafError('Could not create the directory %s' % self.abspath())
+
+			try:
+				self.children
+			except:
+				self.children = {}
+
+		self.cache_isdir = True
+
+	def find_node(self, lst):
+		"""
+		Find a node on the file system (files or folders), create intermediate nodes as needed
+
+		:param lst: path
+		:type lst: string or list of string
+		"""
+
+		if isinstance(lst, str):
+			lst = [x for x in split_path(lst) if x and x != '.']
+
+		cur = self
+		for x in lst:
+			if x == '..':
+				cur = cur.parent or cur
+				continue
+
+			try:
+				if x in cur.children:
+					cur = cur.children[x]
+					continue
+			except:
+				cur.children = {}
+
+			# optimistic: create the node first then look if it was correct to do so
+			cur = self.__class__(x, cur)
+			try:
+				os.stat(cur.abspath())
+			except:
+				del cur.parent.children[x]
+				return None
+
+		ret = cur
+
+		try:
+			os.stat(ret.abspath())
+		except:
+			del ret.parent.children[ret.name]
+			return None
+
+		try:
+			while not getattr(cur.parent, 'cache_isdir', None):
+				cur = cur.parent
+				cur.cache_isdir = True
+		except AttributeError:
+			pass
+
+		return ret
+
+	def make_node(self, lst):
+		"""
+		Find or create a node without looking on the filesystem
+
+		:param lst: path
+		:type lst: string or list of string
+		"""
+		if isinstance(lst, str):
+			lst = [x for x in split_path(lst) if x and x != '.']
+
+		cur = self
+		for x in lst:
+			if x == '..':
+				cur = cur.parent or cur
+				continue
+
+			if getattr(cur, 'children', {}):
+				if x in cur.children:
+					cur = cur.children[x]
+					continue
+			else:
+				cur.children = {}
+			cur = self.__class__(x, cur)
+		return cur
+
+	def search(self, lst):
+		"""
+		Search for a node without looking on the filesystem
+
+		:param lst: path
+		:type lst: string or list of string
+		"""
+		if isinstance(lst, str):
+			lst = [x for x in split_path(lst) if x and x != '.']
+
+		cur = self
+		try:
+			for x in lst:
+				if x == '..':
+					cur = cur.parent or cur
+				else:
+					cur = cur.children[x]
+			return cur
+		except:
+			pass
+
+	def path_from(self, node):
+		"""
+		Path of this node seen from the other::
+
+			def build(bld):
+				n1 = bld.path.find_node('foo/bar/xyz.txt')
+				n2 = bld.path.find_node('foo/stuff/')
+				n1.path_from(n2) # './bar/xyz.txt'
+
+		:param node: path to use as a reference
+		:type node: :py:class:`waflib.Node.Node`
+		"""
+
+		c1 = self
+		c2 = node
+
+		c1h = c1.height()
+		c2h = c2.height()
+
+		lst = []
+		up = 0
+
+		while c1h > c2h:
+			lst.append(c1.name)
+			c1 = c1.parent
+			c1h -= 1
+
+		while c2h > c1h:
+			up += 1
+			c2 = c2.parent
+			c2h -= 1
+
+		while id(c1) != id(c2):
+			lst.append(c1.name)
+			up += 1
+
+			c1 = c1.parent
+			c2 = c2.parent
+
+		for i in range(up):
+			lst.append('..')
+		lst.reverse()
+		return os.sep.join(lst) or '.'
+
+	def abspath(self):
+		"""
+		Absolute path. A cache is kept in the context as ``cache_node_abspath``
+		"""
+		try:
+			return self.cache_abspath
+		except:
+			pass
+		# think twice before touching this (performance + complexity + correctness)
+
+		if os.sep == '/':
+			if not self.parent:
+				val = os.sep
+			elif not self.parent.name:
+				val = os.sep + self.name
+			else:
+				val = self.parent.abspath() + os.sep + self.name
+		else:
+			if not self.parent:
+				val = ''
+			elif not self.parent.name:
+				val = self.name + os.sep
+			else:
+				val = self.parent.abspath().rstrip(os.sep) + os.sep + self.name
+
+		self.cache_abspath = val
+		return val
+
+	def is_child_of(self, node):
+		"""
+		Does this node belong to the subtree node?::
+
+			def build(bld):
+				node = bld.path.find_node('wscript')
+				node.is_child_of(bld.path) # True
+
+		:param node: path to use as a reference
+		:type node: :py:class:`waflib.Node.Node`
+		"""
+		p = self
+		diff = self.height() - node.height()
+		while diff > 0:
+			diff -= 1
+			p = p.parent
+		return id(p) == id(node)
+
+	def ant_iter(self, accept=None, maxdepth=25, pats=[], dir=False, src=True, remove=True):
+		"""
+		Semi-private and recursive method used by ant_glob.
+
+		:param accept: function used for accepting/rejecting a node, returns the patterns that can be still accepted in recursion
+		:type accept: function
+		:param maxdepth: maximum depth in the filesystem (25)
+		:type maxdepth: int
+		:param pats: list of patterns to accept and list of patterns to exclude
+		:type pats: tuple
+		:param dir: return folders too (False by default)
+		:type dir: bool
+		:param src: return files (True by default)
+		:type src: bool
+		:param remove: remove files/folders that do not exist (True by default)
+		:type remove: bool
+		"""
+		dircont = self.listdir()
+		dircont.sort()
+
+		try:
+			lst = set(self.children.keys())
+			if remove:
+				for x in lst - set(dircont):
+					del self.children[x]
+		except:
+			self.children = {}
+
+		for name in dircont:
+			npats = accept(name, pats)
+			if npats and npats[0]:
+				accepted = [] in npats[0]
+
+				node = self.make_node([name])
+
+				isdir = os.path.isdir(node.abspath())
+				if accepted:
+					if isdir:
+						if dir:
+							yield node
+					else:
+						if src:
+							yield node
+
+				if getattr(node, 'cache_isdir', None) or isdir:
+					node.cache_isdir = True
+					if maxdepth:
+						for k in node.ant_iter(accept=accept, maxdepth=maxdepth - 1, pats=npats, dir=dir, src=src):
+							yield k
+		raise StopIteration
+
+	def ant_glob(self, *k, **kw):
+		"""
+		This method is used for finding files across folders. It behaves like ant patterns:
+
+		* ``**/*`` find all files recursively
+		* ``**/*.class`` find all files ending by .class
+		* ``..`` find files having two dot characters
+
+		For example::
+
+			def configure(cfg):
+				cfg.path.ant_glob('**/*.cpp') # find all .cpp files
+				cfg.root.ant_glob('etc/*.txt') # using the filesystem root can be slow
+				cfg.path.ant_glob('*.cpp', excl=['*.c'], src=True, dir=False)
+
+		For more information see http://ant.apache.org/manual/dirtasks.html
+
+		The nodes that correspond to files and folders that do not exist will be removed
+
+		:param incl: ant patterns or list of patterns to include
+		:type incl: string or list of strings
+		:param excl: ant patterns or list of patterns to exclude
+		:type excl: string or list of strings
+		:param dir: return folders too (False by default)
+		:type dir: bool
+		:param src: return files (True by default)
+		:type src: bool
+		:param remove: remove files/folders that do not exist (True by default)
+		:type remove: bool
+		:param maxdepth: maximum depth of recursion
+		:type maxdepth: int
+		"""
+
+		src = kw.get('src', True)
+		dir = kw.get('dir', False)
+
+		excl = kw.get('excl', exclude_regs)
+		incl = k and k[0] or kw.get('incl', '**')
+
+		def to_pat(s):
+			lst = Utils.to_list(s)
+			ret = []
+			for x in lst:
+				x = x.replace('\\', '/').replace('//', '/')
+				if x.endswith('/'):
+					x += '**'
+				lst2 = x.split('/')
+				accu = []
+				for k in lst2:
+					if k == '**':
+						accu.append(k)
+					else:
+						k = k.replace('.', '[.]').replace('*','.*').replace('?', '.').replace('+', '\\+')
+						k = '^%s$' % k
+						try:
+							#print "pattern", k
+							accu.append(re.compile(k))
+						except Exception as e:
+							raise Errors.WafError("Invalid pattern: %s" % k, e)
+				ret.append(accu)
+			return ret
+
+		def filtre(name, nn):
+			ret = []
+			for lst in nn:
+				if not lst:
+					pass
+				elif lst[0] == '**':
+					ret.append(lst)
+					if len(lst) > 1:
+						if lst[1].match(name):
+							ret.append(lst[2:])
+					else:
+						ret.append([])
+				elif lst[0].match(name):
+					ret.append(lst[1:])
+			return ret
+
+		def accept(name, pats):
+			nacc = filtre(name, pats[0])
+			nrej = filtre(name, pats[1])
+			if [] in nrej:
+				nacc = []
+			return [nacc, nrej]
+
+		ret = [x for x in self.ant_iter(accept=accept, pats=[to_pat(incl), to_pat(excl)], maxdepth=25, dir=dir, src=src, remove=kw.get('remove', True))]
+		if kw.get('flat', False):
+			return ' '.join([x.path_from(self) for x in ret])
+
+		return ret
+
+	def find_nodes(self, find_dirs=True, find_files=True, match_fun=lambda x: True):
+		# FIXME not part of the stable API: find_node vs find_nodes? consistency with argument names on other functions?
+		x = """
+		Recursively finds nodes::
+
+			def configure(cnf):
+				cnf.find_nodes()
+
+		:param find_dirs: whether to return directories
+		:param find_files: whether to return files
+		:param match_fun: matching function, taking a node as parameter
+		:rtype generator
+		:return: a generator that iterates over all the requested files
+		"""
+		files = self.listdir()
+		for f in files:
+			node = self.make_node([f])
+			if os.path.isdir(node.abspath()):
+				if find_dirs and match_fun(node):
+					yield node
+				gen = node.find_nodes(find_dirs, find_files, match_fun)
+				for g in gen:
+					yield g
+			else:
+				if find_files and match_fun(node):
+					yield node
+
+
+	# --------------------------------------------------------------------------------
+	# the following methods require the source/build folders (bld.srcnode/bld.bldnode)
+	# using a subclass is a possibility, but is that really necessary?
+	# --------------------------------------------------------------------------------
+
+	def is_src(self):
+		"""
+		True if the node is below the source directory
+		note: !is_src does not imply is_bld()
+
+		:rtype: bool
+		"""
+		cur = self
+		x = id(self.ctx.srcnode)
+		y = id(self.ctx.bldnode)
+		while cur.parent:
+			if id(cur) == y:
+				return False
+			if id(cur) == x:
+				return True
+			cur = cur.parent
+		return False
+
+	def is_bld(self):
+		"""
+		True if the node is below the build directory
+		note: !is_bld does not imply is_src
+
+		:rtype: bool
+		"""
+		cur = self
+		y = id(self.ctx.bldnode)
+		while cur.parent:
+			if id(cur) == y:
+				return True
+			cur = cur.parent
+		return False
+
+	def get_src(self):
+		"""
+		Return the equivalent src node (or self if not possible)
+
+		:rtype: :py:class:`waflib.Node.Node`
+		"""
+		cur = self
+		x = id(self.ctx.srcnode)
+		y = id(self.ctx.bldnode)
+		lst = []
+		while cur.parent:
+			if id(cur) == y:
+				lst.reverse()
+				return self.ctx.srcnode.make_node(lst)
+			if id(cur) == x:
+				return self
+			lst.append(cur.name)
+			cur = cur.parent
+		return self
+
+	def get_bld(self):
+		"""
+		Return the equivalent bld node (or self if not possible)
+
+		:rtype: :py:class:`waflib.Node.Node`
+		"""
+		cur = self
+		x = id(self.ctx.srcnode)
+		y = id(self.ctx.bldnode)
+		lst = []
+		while cur.parent:
+			if id(cur) == y:
+				return self
+			if id(cur) == x:
+				lst.reverse()
+				return self.ctx.bldnode.make_node(lst)
+			lst.append(cur.name)
+			cur = cur.parent
+		# the file is external to the current project, make a fake root in the current build directory
+		lst.reverse()
+		return self.ctx.bldnode.make_node(['__root__'] + lst)
+
+	def find_resource(self, lst):
+		"""
+		Try to find a declared build node or a source file
+
+		:param lst: path
+		:type lst: string or list of string
+		"""
+		if isinstance(lst, str):
+			lst = [x for x in split_path(lst) if x and x != '.']
+
+		node = self.get_bld().search(lst)
+		if not node:
+			self = self.get_src()
+			node = self.find_node(lst)
+		try:
+			pat = node.abspath()
+			if os.path.isdir(pat):
+				return None
+		except:
+			pass
+		return node
+
+	def find_or_declare(self, lst):
+		"""
+		if 'self' is in build directory, try to return an existing node
+		if no node is found, go to the source directory
+		try to find an existing node in the source directory
+		if no node is found, create it in the build directory
+
+		:param lst: path
+		:type lst: string or list of string
+		"""
+		if isinstance(lst, str):
+			lst = [x for x in split_path(lst) if x and x != '.']
+
+		node = self.get_bld().search(lst)
+		if node:
+			if not os.path.isfile(node.abspath()):
+				node.sig = None
+				try:
+					node.parent.mkdir()
+				except:
+					pass
+			return node
+		self = self.get_src()
+		node = self.find_node(lst)
+		if node:
+			if not os.path.isfile(node.abspath()):
+				node.sig = None
+				try:
+					node.parent.mkdir()
+				except:
+					pass
+			return node
+		node = self.get_bld().make_node(lst)
+		node.parent.mkdir()
+		return node
+
+	def find_dir(self, lst):
+		"""
+		Search for a folder in the filesystem
+
+		:param lst: path
+		:type lst: string or list of string
+		"""
+		if isinstance(lst, str):
+			lst = [x for x in split_path(lst) if x and x != '.']
+
+		node = self.find_node(lst)
+		try:
+			if not os.path.isdir(node.abspath()):
+				return None
+		except (OSError, AttributeError):
+			# the node might be None, and raise an AttributeError
+			return None
+		return node
+
+	# helpers for building things
+	def change_ext(self, ext, ext_in=None):
+		"""
+		:return: A build node of the same path, but with a different extension
+		:rtype: :py:class:`waflib.Node.Node`
+		"""
+		name = self.name
+		if ext_in is None:
+			k = name.rfind('.')
+			if k >= 0:
+				name = name[:k] + ext
+			else:
+				name = name + ext
+		else:
+			name = name[:- len(ext_in)] + ext
+
+		return self.parent.find_or_declare([name])
+
+	def nice_path(self, env=None):
+		"""
+		Return the path seen from the launch directory. It is often used for printing nodes in the console to open
+		files easily.
+
+		:param env: unused, left for compatibility with waf 1.5
+		"""
+		return self.path_from(self.ctx.launch_node())
+
+	def bldpath(self):
+		"Path seen from the build directory default/src/foo.cpp"
+		return self.path_from(self.ctx.bldnode)
+
+	def srcpath(self):
+		"Path seen from the source directory ../src/foo.cpp"
+		return self.path_from(self.ctx.srcnode)
+
+	def relpath(self):
+		"If a file in the build directory, bldpath, else srcpath"
+		cur = self
+		x = id(self.ctx.bldnode)
+		while cur.parent:
+			if id(cur) == x:
+				return self.bldpath()
+			cur = cur.parent
+		return self.srcpath()
+
+	def bld_dir(self):
+		"Build path without the file name"
+		return self.parent.bldpath()
+
+	def bld_base(self):
+		"Build path without the extension: src/dir/foo(.cpp)"
+		s = os.path.splitext(self.name)[0]
+		return self.bld_dir() + os.sep + s
+
+	def get_bld_sig(self):
+		"""
+		Node signature, assuming the file is in the build directory
+		"""
+		try:
+			ret = self.ctx.hash_cache[id(self)]
+		except KeyError:
+			pass
+		except AttributeError:
+			self.ctx.hash_cache = {}
+		else:
+			return ret
+
+		if not self.is_bld() or self.ctx.bldnode is self.ctx.srcnode:
+			self.sig = Utils.h_file(self.abspath())
+		self.ctx.hash_cache[id(self)] = ret = self.sig
+		return ret
+
+pickle_lock = Utils.threading.Lock()
+"""Lock mandatory for thread-safe node serialization"""
+
+class Nod3(Node):
+	"""Mandatory subclass for thread-safe node serialization"""
+	pass # do not remove
+
+
diff --git a/xpdeint/waf/waflib/Node.pyc b/xpdeint/waf/waflib/Node.pyc
new file mode 100644
index 0000000..001dc7f
Binary files /dev/null and b/xpdeint/waf/waflib/Node.pyc differ
diff --git a/xpdeint/waf/waflib/Options.py b/xpdeint/waf/waflib/Options.py
new file mode 100644
index 0000000..19d8360
--- /dev/null
+++ b/xpdeint/waf/waflib/Options.py
@@ -0,0 +1,252 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Scott Newton, 2005 (scottn)
+# Thomas Nagy, 2006-2010 (ita)
+
+"""
+Support for waf command-line options
+
+Provides default command-line options,
+as well as custom ones, used by the ``options`` wscript function.
+
+"""
+
+import os, tempfile, optparse, sys, re
+from waflib import Logs, Utils, Context
+
+cmds = 'distclean configure build install clean uninstall check dist distcheck'.split()
+"""
+Constant representing the default waf commands displayed in::
+
+	$ waf --help
+
+"""
+
+options = {}
+"""
+A dictionary representing the command-line options::
+
+	$ waf --foo=bar
+
+"""
+
+commands = []
+"""
+List of commands to execute extracted from the command-line. This list is consumed during the execution, see :py:func:`waflib.Scripting.run_commands`.
+"""
+
+lockfile = os.environ.get('WAFLOCK', '.lock-waf_%s_build' % sys.platform)
+try: cache_global = os.path.abspath(os.environ['WAFCACHE'])
+except KeyError: cache_global = ''
+platform = Utils.unversioned_sys_platform()
+
+
+class opt_parser(optparse.OptionParser):
+	"""
+	Command-line options parser.
+	"""
+	def __init__(self, ctx):
+		optparse.OptionParser.__init__(self, conflict_handler="resolve", version='waf %s (%s)' % (Context.WAFVERSION, Context.WAFREVISION))
+
+		self.formatter.width = Logs.get_term_cols()
+		p = self.add_option
+		self.ctx = ctx
+
+		jobs = ctx.jobs()
+		p('-j', '--jobs',     dest='jobs',    default=jobs, type='int', help='amount of parallel jobs (%r)' % jobs)
+		p('-k', '--keep',     dest='keep',    default=0,     action='count', help='keep running happily even if errors are found')
+		p('-v', '--verbose',  dest='verbose', default=0,     action='count', help='verbosity level -v -vv or -vvv [default: 0]')
+		p('--nocache',        dest='nocache', default=False, action='store_true', help='ignore the WAFCACHE (if set)')
+		p('--zones',          dest='zones',   default='',    action='store', help='debugging zones (task_gen, deps, tasks, etc)')
+
+		gr = optparse.OptionGroup(self, 'configure options')
+		self.add_option_group(gr)
+
+		gr.add_option('-o', '--out', action='store', default='', help='build dir for the project', dest='out')
+		gr.add_option('-t', '--top', action='store', default='', help='src dir for the project', dest='top')
+
+		default_prefix = os.environ.get('PREFIX')
+		if not default_prefix:
+			if platform == 'win32':
+				d = tempfile.gettempdir()
+				default_prefix = d[0].upper() + d[1:]
+				# win32 preserves the case, but gettempdir does not
+			else:
+				default_prefix = '/usr/local/'
+		gr.add_option('--prefix', dest='prefix', default=default_prefix, help='installation prefix [default: %r]' % default_prefix)
+		gr.add_option('--download', dest='download', default=False, action='store_true', help='try to download the tools if missing')
+
+
+		gr = optparse.OptionGroup(self, 'build and install options')
+		self.add_option_group(gr)
+
+		gr.add_option('-p', '--progress', dest='progress_bar', default=0, action='count', help= '-p: progress bar; -pp: ide output')
+		gr.add_option('--targets',        dest='targets', default='', action='store', help='task generators, e.g. "target1,target2"')
+
+		gr = optparse.OptionGroup(self, 'step options')
+		self.add_option_group(gr)
+		gr.add_option('--files',          dest='files', default='', action='store', help='files to process, by regexp, e.g. "*/main.c,*/test/main.o"')
+
+		default_destdir = os.environ.get('DESTDIR', '')
+		gr = optparse.OptionGroup(self, 'install/uninstall options')
+		self.add_option_group(gr)
+		gr.add_option('--destdir', help='installation root [default: %r]' % default_destdir, default=default_destdir, dest='destdir')
+		gr.add_option('-f', '--force', dest='force', default=False, action='store_true', help='force file installation')
+
+	def get_usage(self):
+		"""
+		Return the message to print on ``waf --help``
+		"""
+		cmds_str = {}
+		for cls in Context.classes:
+			if not cls.cmd or cls.cmd == 'options':
+				continue
+
+			s = cls.__doc__ or ''
+			cmds_str[cls.cmd] = s
+
+		if Context.g_module:
+			for (k, v) in Context.g_module.__dict__.items():
+				if k in ['options', 'init', 'shutdown']:
+					continue
+
+				if type(v) is type(Context.create_context):
+					if v.__doc__ and not k.startswith('_'):
+						cmds_str[k] = v.__doc__
+
+		just = 0
+		for k in cmds_str:
+			just = max(just, len(k))
+
+		lst = ['  %s: %s' % (k.ljust(just), v) for (k, v) in cmds_str.items()]
+		lst.sort()
+		ret = '\n'.join(lst)
+
+		return '''waf [commands] [options]
+
+Main commands (example: ./waf build -j4)
+%s
+''' % ret
+
+
+class OptionsContext(Context.Context):
+	"""
+	Collect custom options from wscript files and parses the command line.
+	Set the global :py:const:`waflib.Options.commands` and :py:const:`waflib.Options.options` values.
+	"""
+
+	cmd = 'options'
+	fun = 'options'
+
+	def __init__(self, **kw):
+		super(OptionsContext, self).__init__(**kw)
+
+		self.parser = opt_parser(self)
+		"""Instance of :py:class:`waflib.Options.opt_parser`"""
+
+		self.option_groups = {}
+
+	def jobs(self):
+		"""
+		Find the amount of cpu cores to set the default amount of tasks executed in parallel. At
+		runtime the options can be obtained from :py:const:`waflib.Options.options` ::
+
+			from waflib.Options import options
+			njobs = options.jobs
+
+		:return: the amount of cpu cores
+		:rtype: int
+		"""
+		count = int(os.environ.get('JOBS', 0))
+		if count < 1:
+			if 'NUMBER_OF_PROCESSORS' in os.environ:
+				# on Windows, use the NUMBER_OF_PROCESSORS environment variable
+				count = int(os.environ.get('NUMBER_OF_PROCESSORS', 1))
+			else:
+				# on everything else, first try the POSIX sysconf values
+				if hasattr(os, 'sysconf_names'):
+					if 'SC_NPROCESSORS_ONLN' in os.sysconf_names:
+						count = int(os.sysconf('SC_NPROCESSORS_ONLN'))
+					elif 'SC_NPROCESSORS_CONF' in os.sysconf_names:
+						count = int(os.sysconf('SC_NPROCESSORS_CONF'))
+				if not count and os.name not in ('nt', 'java'):
+					try:
+						tmp = self.cmd_and_log(['sysctl', '-n', 'hw.ncpu'], quiet=0)
+					except Exception:
+						pass
+					else:
+						if re.match('^[0-9]+$', tmp):
+							count = int(tmp)
+		if count < 1:
+			count = 1
+		elif count > 1024:
+			count = 1024
+		return count
+
+	def add_option(self, *k, **kw):
+		"""
+		Wrapper for optparse.add_option::
+
+			def options(ctx):
+				ctx.add_option('-u', '--use', dest='use', default=False, action='store_true',
+					help='a boolean option')
+		"""
+		self.parser.add_option(*k, **kw)
+
+	def add_option_group(self, *k, **kw):
+		"""
+		Wrapper for optparse.add_option_group::
+
+			def options(ctx):
+				ctx.add_option_group('some options')
+				gr.add_option('-u', '--use', dest='use', default=False, action='store_true')
+		"""
+		try:
+			gr = self.option_groups[k[0]]
+		except:
+			gr = self.parser.add_option_group(*k, **kw)
+		self.option_groups[k[0]] = gr
+		return gr
+
+	def get_option_group(self, opt_str):
+		"""
+		Wrapper for optparse.get_option_group::
+
+			def options(ctx):
+				gr = ctx.get_option_group('configure options')
+				gr.add_option('-o', '--out', action='store', default='',
+					help='build dir for the project', dest='out')
+
+		"""
+		try:
+			return self.option_groups[opt_str]
+		except KeyError:
+			for group in self.parser.option_groups:
+				if group.title == opt_str:
+					return group
+			return None
+
+	def parse_args(self, _args=None):
+		"""
+		Parse arguments from a list (not bound to the command-line).
+
+		:param _args: arguments
+		:type _args: list of strings
+		"""
+		global options, commands
+		(options, leftover_args) = self.parser.parse_args(args=_args)
+		commands = leftover_args
+
+		if options.destdir:
+			options.destdir = os.path.abspath(os.path.expanduser(options.destdir))
+
+		if options.verbose >= 1:
+			self.load('errcheck')
+
+	def execute(self):
+		"""
+		See :py:func:`waflib.Context.Context.execute`
+		"""
+		super(OptionsContext, self).execute()
+		self.parse_args()
+
diff --git a/xpdeint/waf/waflib/Options.pyc b/xpdeint/waf/waflib/Options.pyc
new file mode 100644
index 0000000..7a77d74
Binary files /dev/null and b/xpdeint/waf/waflib/Options.pyc differ
diff --git a/xpdeint/waf/waflib/Runner.py b/xpdeint/waf/waflib/Runner.py
new file mode 100644
index 0000000..ee288d3
--- /dev/null
+++ b/xpdeint/waf/waflib/Runner.py
@@ -0,0 +1,360 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005-2010 (ita)
+
+"""
+Runner.py: Task scheduling and execution
+
+"""
+
+import random, atexit
+try:
+	from queue import Queue
+except:
+	from Queue import Queue
+from waflib import Utils, Task, Errors, Logs
+
+GAP = 10
+"""
+Wait for free tasks if there are at least ``GAP * njobs`` in queue
+"""
+
+class TaskConsumer(Utils.threading.Thread):
+	"""
+	Task consumers belong to a pool of workers
+
+	They wait for tasks in the queue and then use ``task.process(...)``
+	"""
+	def __init__(self):
+		Utils.threading.Thread.__init__(self)
+		self.ready = Queue()
+		"""
+		Obtain :py:class:`waflib.Task.TaskBase` instances from this queue.
+		"""
+		self.setDaemon(1)
+		self.start()
+
+	def run(self):
+		"""
+		Loop over the tasks to execute
+		"""
+		try:
+			self.loop()
+		except:
+			pass
+
+	def loop(self):
+		"""
+		Obtain tasks from :py:attr:`waflib.Runner.TaskConsumer.ready` and call
+		:py:meth:`waflib.Task.TaskBase.process`. If the object is a function, execute it.
+		"""
+		while 1:
+			tsk = self.ready.get()
+			if not isinstance(tsk, Task.TaskBase):
+				tsk(self)
+			else:
+				tsk.process()
+
+pool = Queue()
+"""
+Pool of task consumer objects
+"""
+
+def get_pool():
+	"""
+	Obtain a task consumer from :py:attr:`waflib.Runner.pool`.
+	Do not forget to put it back by using :py:func:`waflib.Runner.put_pool`
+	and reset properly (original waiting queue).
+
+	:rtype: :py:class:`waflib.Runner.TaskConsumer`
+	"""
+	try:
+		return pool.get(False)
+	except:
+		return TaskConsumer()
+
+def put_pool(x):
+	"""
+	Return a task consumer to the thread pool :py:attr:`waflib.Runner.pool`
+
+	:param x: task consumer object
+	:type x: :py:class:`waflib.Runner.TaskConsumer`
+	"""
+	pool.put(x)
+
+def _free_resources():
+	global pool
+	lst = []
+	while pool.qsize():
+		lst.append(pool.get())
+	for x in lst:
+		x.ready.put(None)
+	for x in lst:
+		x.join()
+	pool = None
+atexit.register(_free_resources)
+
+class Parallel(object):
+	"""
+	Schedule the tasks obtained from the build context for execution.
+	"""
+	def __init__(self, bld, j=2):
+		"""
+		The initialization requires a build context reference
+		for computing the total number of jobs.
+		"""
+
+		self.numjobs = j
+		"""
+		Number of consumers in the pool
+		"""
+
+		self.bld = bld
+		"""
+		Instance of :py:class:`waflib.Build.BuildContext`
+		"""
+
+		self.outstanding = []
+		"""List of :py:class:`waflib.Task.TaskBase` that may be ready to be executed"""
+
+		self.frozen = []
+		"""List of :py:class:`waflib.Task.TaskBase` that cannot be executed immediately"""
+
+		self.out = Queue(0)
+		"""List of :py:class:`waflib.Task.TaskBase` returned by the task consumers"""
+
+		self.count = 0
+		"""Amount of tasks that may be processed by :py:class:`waflib.Runner.TaskConsumer`"""
+
+		self.processed = 1
+		"""Amount of tasks processed"""
+
+		self.stop = False
+		"""Error flag to stop the build"""
+
+		self.error = []
+		"""Tasks that could not be executed"""
+
+		self.biter = None
+		"""Task iterator which must give groups of parallelizable tasks when calling ``next()``"""
+
+		self.dirty = False
+		"""Flag to indicate that tasks have been executed, and that the build cache must be saved (call :py:meth:`waflib.Build.BuildContext.store`)"""
+
+	def get_next_task(self):
+		"""
+		Obtain the next task to execute.
+
+		:rtype: :py:class:`waflib.Task.TaskBase`
+		"""
+		if not self.outstanding:
+			return None
+		return self.outstanding.pop(0)
+
+	def postpone(self, tsk):
+		"""
+		A task cannot be executed at this point, put it in the list :py:attr:`waflib.Runner.Parallel.frozen`.
+
+		:param tsk: task
+		:type tsk: :py:class:`waflib.Task.TaskBase`
+		"""
+		if random.randint(0, 1):
+			self.frozen.insert(0, tsk)
+		else:
+			self.frozen.append(tsk)
+
+	def refill_task_list(self):
+		"""
+		Put the next group of tasks to execute in :py:attr:`waflib.Runner.Parallel.outstanding`.
+		"""
+		while self.count > self.numjobs * GAP:
+			self.get_out()
+
+		while not self.outstanding:
+			if self.count:
+				self.get_out()
+			elif self.frozen:
+				try:
+					cond = self.deadlock == self.processed
+				except:
+					pass
+				else:
+					if cond:
+						msg = 'check the build order for the tasks'
+						for tsk in self.frozen:
+							if not tsk.run_after:
+								msg = 'check the methods runnable_status'
+								break
+						lst = []
+						for tsk in self.frozen:
+							lst.append('%s\t-> %r' % (repr(tsk), [id(x) for x in tsk.run_after]))
+						raise Errors.WafError('Deadlock detected: %s%s' % (msg, ''.join(lst)))
+				self.deadlock = self.processed
+
+			if self.frozen:
+				self.outstanding += self.frozen
+				self.frozen = []
+			elif not self.count:
+				self.outstanding.extend(next(self.biter))
+				self.total = self.bld.total()
+				break
+
+	def add_more_tasks(self, tsk):
+		"""
+		Tasks may be added dynamically during the build by binding them to the task :py:attr:`waflib.Task.TaskBase.more_tasks`
+
+		:param tsk: task
+		:type tsk: :py:attr:`waflib.Task.TaskBase`
+		"""
+		if getattr(tsk, 'more_tasks', None):
+			self.outstanding += tsk.more_tasks
+			self.total += len(tsk.more_tasks)
+
+	def get_out(self):
+		"""
+		Obtain one task returned from the task consumers, and update the task count. Add more tasks if necessary through
+		:py:attr:`waflib.Runner.Parallel.add_more_tasks`.
+
+		:rtype: :py:attr:`waflib.Task.TaskBase`
+		"""
+		tsk = self.out.get()
+		if not self.stop:
+			self.add_more_tasks(tsk)
+		self.count -= 1
+		self.dirty = True
+
+	def error_handler(self, tsk):
+		"""
+		Called when a task cannot be executed. The flag :py:attr:`waflib.Runner.Parallel.stop` is set, unless
+		the build is executed with::
+
+			$ waf build -k
+
+		:param tsk: task
+		:type tsk: :py:attr:`waflib.Task.TaskBase`
+		"""
+		if not self.bld.keep:
+			self.stop = True
+		self.error.append(tsk)
+
+	def add_task(self, tsk):
+		"""
+		Pass a task to a consumer.
+
+		:param tsk: task
+		:type tsk: :py:attr:`waflib.Task.TaskBase`
+		"""
+		try:
+			self.pool
+		except AttributeError:
+			self.init_task_pool()
+		self.ready.put(tsk)
+
+	def init_task_pool(self):
+		# lazy creation, and set a common pool for all task consumers
+		pool = self.pool = [get_pool() for i in range(self.numjobs)]
+		self.ready = Queue(0)
+		def setq(consumer):
+			consumer.ready = self.ready
+		for x in pool:
+			x.ready.put(setq)
+		return pool
+
+	def free_task_pool(self):
+		# return the consumers, setting a different queue for each of them
+		def setq(consumer):
+			consumer.ready = Queue(0)
+			self.out.put(self)
+		try:
+			pool = self.pool
+		except:
+			pass
+		else:
+			for x in pool:
+				self.ready.put(setq)
+			for x in pool:
+				self.get_out()
+			for x in pool:
+				put_pool(x)
+			self.pool = []
+
+	def start(self):
+		"""
+		Give tasks to :py:class:`waflib.Runner.TaskConsumer` instances until the build finishes or the ``stop`` flag is set.
+		If only one job is used, then execute the tasks one by one, without consumers.
+		"""
+
+		self.total = self.bld.total()
+
+		while not self.stop:
+
+			self.refill_task_list()
+
+			# consider the next task
+			tsk = self.get_next_task()
+			if not tsk:
+				if self.count:
+					# tasks may add new ones after they are run
+					continue
+				else:
+					# no tasks to run, no tasks running, time to exit
+					break
+
+			if tsk.hasrun:
+				# if the task is marked as "run", just skip it
+				self.processed += 1
+				continue
+
+			if self.stop: # stop immediately after a failure was detected
+				break
+
+			try:
+				st = tsk.runnable_status()
+			except Exception:
+				self.processed += 1
+				# TODO waf 1.7 this piece of code should go in the error_handler
+				tsk.err_msg = Utils.ex_stack()
+				if not self.stop and self.bld.keep:
+					tsk.hasrun = Task.SKIPPED
+					if self.bld.keep == 1:
+						# if -k stop at the first exception, if -kk try to go as far as possible
+						if Logs.verbose > 1 or not self.error:
+							self.error.append(tsk)
+						self.stop = True
+					else:
+						if Logs.verbose > 1:
+							self.error.append(tsk)
+					continue
+				tsk.hasrun = Task.EXCEPTION
+				self.error_handler(tsk)
+				continue
+
+			if st == Task.ASK_LATER:
+				self.postpone(tsk)
+			elif st == Task.SKIP_ME:
+				self.processed += 1
+				tsk.hasrun = Task.SKIPPED
+				self.add_more_tasks(tsk)
+			else:
+				# run me: put the task in ready queue
+				tsk.position = (self.processed, self.total)
+				self.count += 1
+				tsk.master = self
+				self.processed += 1
+
+				if self.numjobs == 1:
+					tsk.process()
+				else:
+					self.add_task(tsk)
+
+		# self.count represents the tasks that have been made available to the consumer threads
+		# collect all the tasks after an error else the message may be incomplete
+		while self.error and self.count:
+			self.get_out()
+
+		#print loop
+		assert (self.count == 0 or self.stop)
+
+		# free the task pool, if any
+		self.free_task_pool()
+
diff --git a/xpdeint/waf/waflib/Runner.pyc b/xpdeint/waf/waflib/Runner.pyc
new file mode 100644
index 0000000..c10c2d5
Binary files /dev/null and b/xpdeint/waf/waflib/Runner.pyc differ
diff --git a/xpdeint/waf/waflib/Scripting.py b/xpdeint/waf/waflib/Scripting.py
new file mode 100644
index 0000000..f229fe4
--- /dev/null
+++ b/xpdeint/waf/waflib/Scripting.py
@@ -0,0 +1,574 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005-2010 (ita)
+
+"Module called for configuring, compiling and installing targets"
+
+import os, shutil, traceback, errno, sys, stat
+from waflib import Utils, Configure, Logs, Options, ConfigSet, Context, Errors, Build, Node
+
+build_dir_override = None
+
+no_climb_commands = ['configure']
+
+default_cmd = "build"
+
+def waf_entry_point(current_directory, version, wafdir):
+	"""
+	This is the main entry point, all Waf execution starts here.
+
+	:param current_directory: absolute path representing the current directory
+	:type current_directory: string
+	:param version: version number
+	:type version: string
+	:param wafdir: absolute path representing the directory of the waf library
+	:type wafdir: string
+	"""
+
+	Logs.init_log()
+
+	if Context.WAFVERSION != version:
+		Logs.error('Waf script %r and library %r do not match (directory %r)' % (version, Context.WAFVERSION, wafdir))
+		sys.exit(1)
+
+	if '--version' in sys.argv:
+		ctx = Context.create_context('options')
+		ctx.curdir = current_directory
+		ctx.parse_args()
+		sys.exit(0)
+
+	Context.waf_dir = wafdir
+	Context.launch_dir = current_directory
+
+	# if 'configure' is in the commands, do not search any further
+	no_climb = os.environ.get('NOCLIMB', None)
+	if not no_climb:
+		for k in no_climb_commands:
+			if k in sys.argv:
+				no_climb = True
+				break
+
+	# try to find a lock file (if the project was configured)
+	# at the same time, store the first wscript file seen
+	cur = current_directory
+	while cur:
+		lst = os.listdir(cur)
+		if Options.lockfile in lst:
+			env = ConfigSet.ConfigSet()
+			try:
+				env.load(os.path.join(cur, Options.lockfile))
+				ino = os.stat(cur)[stat.ST_INO]
+			except Exception:
+				pass
+			else:
+				# check if the folder was not moved
+				for x in [env.run_dir, env.top_dir, env.out_dir]:
+					if Utils.is_win32:
+						if cur == x:
+							load = True
+							break
+					else:
+						# if the filesystem features symlinks, compare the inode numbers
+						try:
+							ino2 = os.stat(x)[stat.ST_INO]
+						except:
+							pass
+						else:
+							if ino == ino2:
+								load = True
+								break
+				else:
+					Logs.warn('invalid lock file in %s' % cur)
+					load = False
+
+				if load:
+					Context.run_dir = env.run_dir
+					Context.top_dir = env.top_dir
+					Context.out_dir = env.out_dir
+					break
+
+		if not Context.run_dir:
+			if Context.WSCRIPT_FILE in lst:
+				Context.run_dir = cur
+
+		next = os.path.dirname(cur)
+		if next == cur:
+			break
+		cur = next
+
+		if no_climb:
+			break
+
+	if not Context.run_dir:
+		if '-h' in sys.argv or '--help' in sys.argv:
+			Logs.warn('No wscript file found: the help message may be incomplete')
+			ctx = Context.create_context('options')
+			ctx.curdir = current_directory
+			ctx.parse_args()
+			sys.exit(0)
+		Logs.error('Waf: Run from a directory containing a file named %r' % Context.WSCRIPT_FILE)
+		sys.exit(1)
+
+	try:
+		os.chdir(Context.run_dir)
+	except OSError:
+		Logs.error('Waf: The folder %r is unreadable' % Context.run_dir)
+		sys.exit(1)
+
+	try:
+		set_main_module(Context.run_dir + os.sep + Context.WSCRIPT_FILE)
+	except Errors.WafError as e:
+		Logs.pprint('RED', e.verbose_msg)
+		Logs.error(str(e))
+		sys.exit(1)
+	except Exception as e:
+		Logs.error('Waf: The wscript in %r is unreadable' % Context.run_dir, e)
+		traceback.print_exc(file=sys.stdout)
+		sys.exit(2)
+
+	"""
+	import cProfile, pstats
+	cProfile.runctx("import Scripting; Scripting.run_commands()", {}, {}, 'profi.txt')
+	p = pstats.Stats('profi.txt')
+	p.sort_stats('time').print_stats(25)
+	"""
+	try:
+		run_commands()
+	except Errors.WafError as e:
+		if Logs.verbose > 1:
+			Logs.pprint('RED', e.verbose_msg)
+		Logs.error(e.msg)
+		sys.exit(1)
+	except Exception as e:
+		traceback.print_exc(file=sys.stdout)
+		sys.exit(2)
+	except KeyboardInterrupt:
+		Logs.pprint('RED', 'Interrupted')
+		sys.exit(68)
+	#"""
+
+def set_main_module(file_path):
+	"""
+	Read the main wscript file into :py:const:`waflib.Context.Context.g_module` and
+	bind default functions such as ``init``, ``dist``, ``distclean`` if not defined.
+	Called by :py:func:`waflib.Scripting.waf_entry_point` during the initialization.
+
+	:param file_path: absolute path representing the top-level wscript file
+	:type file_path: string
+	"""
+	Context.g_module = Context.load_module(file_path)
+	Context.g_module.root_path = file_path
+
+	# note: to register the module globally, use the following:
+	# sys.modules['wscript_main'] = g_module
+
+	def set_def(obj):
+		name = obj.__name__
+		if not name in Context.g_module.__dict__:
+			setattr(Context.g_module, name, obj)
+	for k in [update, dist, distclean, distcheck, update]:
+		set_def(k)
+	# add dummy init and shutdown functions if they're not defined
+	if not 'init' in Context.g_module.__dict__:
+		Context.g_module.init = Utils.nada
+	if not 'shutdown' in Context.g_module.__dict__:
+		Context.g_module.shutdown = Utils.nada
+	if not 'options' in Context.g_module.__dict__:
+		Context.g_module.options = Utils.nada
+
+def parse_options():
+	"""
+	Parse the command-line options and initialize the logging system.
+	Called by :py:func:`waflib.Scripting.waf_entry_point` during the initialization.
+	"""
+	Context.create_context('options').execute()
+
+	if not Options.commands:
+		Options.commands = [default_cmd]
+
+	# process some internal Waf options
+	Logs.verbose = Options.options.verbose
+	Logs.init_log()
+
+	if Options.options.zones:
+		Logs.zones = Options.options.zones.split(',')
+		if not Logs.verbose:
+			Logs.verbose = 1
+	elif Logs.verbose > 0:
+		Logs.zones = ['runner']
+
+	if Logs.verbose > 2:
+		Logs.zones = ['*']
+
+def run_command(cmd_name):
+	"""
+	Execute a single command. Called by :py:func:`waflib.Scripting.run_commands`.
+
+	:param cmd_name: command to execute, like ``build``
+	:type cmd_name: string
+	"""
+	ctx = Context.create_context(cmd_name)
+	ctx.options = Options.options # provided for convenience
+	ctx.cmd = cmd_name
+	ctx.execute()
+	return ctx
+
+def run_commands():
+	"""
+	Execute the commands that were given on the command-line, and the other options
+	Called by :py:func:`waflib.Scripting.waf_entry_point` during the initialization, and executed
+	after :py:func:`waflib.Scripting.parse_options`.
+	"""
+	parse_options()
+	run_command('init')
+	while Options.commands:
+		cmd_name = Options.commands.pop(0)
+
+		timer = Utils.Timer()
+		run_command(cmd_name)
+		if not Options.options.progress_bar:
+			elapsed = ' (%s)' % str(timer)
+			Logs.info('%r finished successfully%s' % (cmd_name, elapsed))
+	run_command('shutdown')
+
+###########################################################################################
+
+def _can_distclean(name):
+	# WARNING: this method may disappear anytime
+	for k in '.o .moc .exe'.split():
+		if name.endswith(k):
+			return True
+	return False
+
+def distclean_dir(dirname):
+	"""
+	Distclean function called in the particular case when::
+
+		top == out
+
+	:param dirname: absolute path of the folder to clean
+	:type dirname: string
+	"""
+	for (root, dirs, files) in os.walk(dirname):
+		for f in files:
+			if _can_distclean(f):
+				fname = root + os.sep + f
+				try:
+					os.unlink(fname)
+				except:
+					Logs.warn('could not remove %r' % fname)
+
+	for x in [Context.DBFILE, 'config.log']:
+		try:
+			os.unlink(x)
+		except:
+			pass
+
+	try:
+		shutil.rmtree('c4che')
+	except:
+		pass
+
+def distclean(ctx):
+	'''removes the build directory'''
+	lst = os.listdir('.')
+	for f in lst:
+		if f == Options.lockfile:
+			try:
+				proj = ConfigSet.ConfigSet(f)
+			except:
+				Logs.warn('could not read %r' % f)
+				continue
+
+			if proj['out_dir'] != proj['top_dir']:
+				try:
+					shutil.rmtree(proj['out_dir'])
+				except IOError:
+					pass
+				except OSError as e:
+					if e.errno != errno.ENOENT:
+						Logs.warn('project %r cannot be removed' % proj[Context.OUT])
+			else:
+				distclean_dir(proj['out_dir'])
+
+			for k in (proj['out_dir'], proj['top_dir'], proj['run_dir']):
+				try:
+					os.remove(os.path.join(k, Options.lockfile))
+				except OSError as e:
+					if e.errno != errno.ENOENT:
+						Logs.warn('file %r cannot be removed' % f)
+
+		# remove the local waf cache
+		if f.startswith('.waf-') and not Options.commands:
+			shutil.rmtree(f, ignore_errors=True)
+
+class Dist(Context.Context):
+	"""
+	Create an archive containing the project source code::
+
+		$ waf dist
+	"""
+	cmd = 'dist'
+	fun = 'dist'
+	algo = 'tar.bz2'
+	ext_algo = {}
+
+	def execute(self):
+		"""
+		See :py:func:`waflib.Context.Context.execute`
+		"""
+		self.recurse([os.path.dirname(Context.g_module.root_path)])
+		self.archive()
+
+	def archive(self):
+		"""
+		Create the archive.
+		"""
+		import tarfile
+
+		arch_name = self.get_arch_name()
+
+		try:
+			self.base_path
+		except:
+			self.base_path = self.path
+
+		node = self.base_path.make_node(arch_name)
+		try:
+			node.delete()
+		except:
+			pass
+
+		files = self.get_files()
+
+		if self.algo.startswith('tar.'):
+			tar = tarfile.open(arch_name, 'w:' + self.algo.replace('tar.', ''))
+
+			for x in files:
+				self.add_tar_file(x, tar)
+			tar.close()
+		elif self.algo == 'zip':
+			import zipfile
+			zip = zipfile.ZipFile(arch_name, 'w', compression=zipfile.ZIP_DEFLATED)
+
+			for x in files:
+				archive_name = self.get_base_name() + '/' + x.path_from(self.base_path)
+				zip.write(x.abspath(), archive_name, zipfile.ZIP_DEFLATED)
+			zip.close()
+		else:
+			self.fatal('Valid algo types are tar.bz2, tar.gz or zip')
+
+		try:
+			from hashlib import sha1 as sha
+		except ImportError:
+			from sha import sha
+		try:
+			digest = " (sha=%r)" % sha(node.read()).hexdigest()
+		except:
+			digest = ''
+
+		Logs.info('New archive created: %s%s' % (self.arch_name, digest))
+
+	def get_tar_path(self, node):
+		"""
+		return the path to use for a node in the tar archive, the purpose of this
+		is to let subclases resolve symbolic links or to change file names
+		"""
+		return node.abspath()
+
+	def add_tar_file(self, x, tar):
+		"""
+		Add a file to the tar archive. Transform symlinks into files if the files lie out of the project tree.
+		"""
+		p = self.get_tar_path(x)
+		tinfo = tar.gettarinfo(name=p, arcname=self.get_tar_prefix() + '/' + x.path_from(self.base_path))
+		tinfo.uid   = 0
+		tinfo.gid   = 0
+		tinfo.uname = 'root'
+		tinfo.gname = 'root'
+
+		fu = None
+		try:
+			fu = open(p, 'rb')
+			tar.addfile(tinfo, fileobj=fu)
+		finally:
+			if fu:
+				fu.close()
+
+	def get_tar_prefix(self):
+		try:
+			return self.tar_prefix
+		except:
+			return self.get_base_name()
+
+	def get_arch_name(self):
+		"""
+		Return the name of the archive to create. Change the default value by setting *arch_name*::
+
+			def dist(ctx):
+				ctx.arch_name = 'ctx.tar.bz2'
+
+		:rtype: string
+		"""
+		try:
+			self.arch_name
+		except:
+			self.arch_name = self.get_base_name() + '.' + self.ext_algo.get(self.algo, self.algo)
+		return self.arch_name
+
+	def get_base_name(self):
+		"""
+		Return the default name of the main directory in the archive, which is set to *appname-version*.
+		Set the attribute *base_name* to change the default value::
+
+			def dist(ctx):
+				ctx.base_name = 'files'
+
+		:rtype: string
+		"""
+		try:
+			self.base_name
+		except:
+			appname = getattr(Context.g_module, Context.APPNAME, 'noname')
+			version = getattr(Context.g_module, Context.VERSION, '1.0')
+			self.base_name = appname + '-' + version
+		return self.base_name
+
+	def get_excl(self):
+		"""
+		Return the patterns to exclude for finding the files in the top-level directory. Set the attribute *excl*
+		to change the default value::
+
+			def dist(ctx):
+				ctx.excl = 'build **/*.o **/*.class'
+
+		:rtype: string
+		"""
+		try:
+			return self.excl
+		except:
+			self.excl = Node.exclude_regs + ' **/waf-1.6.* **/.waf-1.6* **/*~ **/*.rej **/*.orig **/*.pyc **/*.pyo **/*.bak **/*.swp **/.lock-w*'
+			nd = self.root.find_node(Context.out_dir)
+			if nd:
+				self.excl += ' ' + nd.path_from(self.base_path)
+			return self.excl
+
+	def get_files(self):
+		"""
+		The files to package are searched automatically by :py:func:`waflib.Node.Node.ant_glob`. Set
+		*files* to prevent this behaviour::
+
+			def dist(ctx):
+				ctx.files = ctx.path.find_node('wscript')
+
+		The files are searched from the directory 'base_path', to change it, set::
+
+			def dist(ctx):
+				ctx.base_path = path
+
+		:rtype: list of :py:class:`waflib.Node.Node`
+		"""
+		try:
+			files = self.files
+		except:
+			files = self.base_path.ant_glob('**/*', excl=self.get_excl())
+		return files
+
+
+def dist(ctx):
+	'''makes a tarball for redistributing the sources'''
+	pass
+
+class DistCheck(Dist):
+	"""
+	Create an archive of the project, and try to build the project in a temporary directory::
+
+		$ waf distcheck
+	"""
+
+	fun = 'distcheck'
+	cmd = 'distcheck'
+
+	def execute(self):
+		"""
+		See :py:func:`waflib.Context.Context.execute`
+		"""
+		self.recurse([os.path.dirname(Context.g_module.root_path)])
+		self.archive()
+		self.check()
+
+	def check(self):
+		"""
+		Create the archive, uncompress it and try to build the project
+		"""
+		import tempfile, tarfile
+
+		t = None
+		try:
+			t = tarfile.open(self.get_arch_name())
+			for x in t:
+				t.extract(x)
+		finally:
+			if t:
+				t.close()
+
+		instdir = tempfile.mkdtemp('.inst', self.get_base_name())
+		ret = Utils.subprocess.Popen([sys.argv[0], 'configure', 'install', 'uninstall', '--destdir=' + instdir], cwd=self.get_base_name()).wait()
+		if ret:
+			raise Errors.WafError('distcheck failed with code %i' % ret)
+
+		if os.path.exists(instdir):
+			raise Errors.WafError('distcheck succeeded, but files were left in %s' % instdir)
+
+		shutil.rmtree(self.get_base_name())
+
+
+def distcheck(ctx):
+	'''checks if the project compiles (tarball from 'dist')'''
+	pass
+
+def update(ctx):
+	'''updates the plugins from the *waflib/extras* directory'''
+	lst = Options.options.files.split(',')
+	if not lst:
+		lst = [x for x in Utils.listdir(Context.waf_dir + '/waflib/extras') if x.endswith('.py')]
+	for x in lst:
+		tool = x.replace('.py', '')
+		try:
+			Configure.download_tool(tool, force=True, ctx=ctx)
+		except Errors.WafError:
+			Logs.error('Could not find the tool %s in the remote repository' % x)
+
+def autoconfigure(execute_method):
+	"""
+	Decorator used to set the commands that can be configured automatically
+	"""
+	def execute(self):
+		if not Configure.autoconfig:
+			return execute_method(self)
+
+		env = ConfigSet.ConfigSet()
+		do_config = False
+		try:
+			env.load(os.path.join(Context.top_dir, Options.lockfile))
+		except Exception:
+			Logs.warn('Configuring the project')
+			do_config = True
+		else:
+			if env.run_dir != Context.run_dir:
+				do_config = True
+			else:
+				h = 0
+				for f in env['files']:
+					h = hash((h, Utils.readf(f, 'rb')))
+				do_config = h != env.hash
+
+		if do_config:
+			Options.commands.insert(0, self.cmd)
+			Options.commands.insert(0, 'configure')
+			return
+
+		return execute_method(self)
+	return execute
+Build.BuildContext.execute = autoconfigure(Build.BuildContext.execute)
+
diff --git a/xpdeint/waf/waflib/Scripting.pyc b/xpdeint/waf/waflib/Scripting.pyc
new file mode 100644
index 0000000..ef156e0
Binary files /dev/null and b/xpdeint/waf/waflib/Scripting.pyc differ
diff --git a/xpdeint/waf/waflib/Task.py b/xpdeint/waf/waflib/Task.py
new file mode 100644
index 0000000..4ae2564
--- /dev/null
+++ b/xpdeint/waf/waflib/Task.py
@@ -0,0 +1,1239 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005-2010 (ita)
+
+"""
+Tasks represent atomic operations such as processes.
+"""
+
+import os, shutil, re, tempfile
+from waflib import Utils, Logs, Errors
+
+# task states
+NOT_RUN = 0
+"""The task was not executed yet"""
+
+MISSING = 1
+"""The task has been executed but the files have not been created"""
+
+CRASHED = 2
+"""The task execution returned a non-zero exit status"""
+
+EXCEPTION = 3
+"""An exception occured in the task execution"""
+
+SKIPPED = 8
+"""The task did not have to be executed"""
+
+SUCCESS = 9
+"""The task was successfully executed"""
+
+ASK_LATER = -1
+"""The task is not ready to be executed"""
+
+SKIP_ME = -2
+"""The task does not need to be executed"""
+
+RUN_ME = -3
+"""The task must be executed"""
+
+COMPILE_TEMPLATE_SHELL = '''
+def f(tsk):
+	env = tsk.env
+	gen = tsk.generator
+	bld = gen.bld
+	wd = getattr(tsk, 'cwd', None)
+	def p(key):
+		s = env[key]
+		if isinstance(s, str): return '"' + s + '"'
+		return ' '.join('"' + x + '"' for x in s)
+	tsk.last_cmd = cmd = \'\'\' %s \'\'\' % s
+	return tsk.exec_command(cmd, cwd=wd, env=env.env or None)
+'''
+
+COMPILE_TEMPLATE_NOSHELL = '''
+def f(tsk):
+	env = tsk.env
+	gen = tsk.generator
+	bld = gen.bld
+	wd = getattr(tsk, 'cwd', None)
+	def to_list(xx):
+		if isinstance(xx, str): return [xx]
+		return xx
+	tsk.last_cmd = lst = []
+	%s
+	lst = [x for x in lst if x]
+	return tsk.exec_command(lst, cwd=wd, env=env.env or None)
+'''
+
+def cache_outputs(cls):
+	"""
+	Task class decorator applied to all task classes by default unless they define the attribute 'nocache'::
+
+		from waflib import Task
+		class foo(Task.Task):
+			nocache = True
+
+	If bld.cache_global is defined and if the task instances produces output nodes,
+	the files will be copied into a folder in the cache directory
+
+	The files may also be retrieved from that folder, if it exists
+	"""
+	m1 = cls.run
+	def run(self):
+		bld = self.generator.bld
+		if bld.cache_global and not bld.nocache:
+			if self.can_retrieve_cache():
+				return 0
+		return m1(self)
+	cls.run = run
+
+	m2 = cls.post_run
+	def post_run(self):
+		bld = self.generator.bld
+		ret = m2(self)
+		if bld.cache_global and not bld.nocache:
+			self.put_files_cache()
+		return ret
+	cls.post_run = post_run
+
+	return cls
+
+
+classes = {}
+"class tasks created by user scripts or Waf tools are kept in this dict name -> class object"
+
+class store_task_type(type):
+	"""
+	Metaclass: store the task types into :py:const:`waflib.Task.classes`.
+	The attribute 'run_str' will be processed to compute a method 'run' on the task class
+	The decorator :py:func:`waflib.Task.cache_outputs` is also applied to the class
+	"""
+	def __init__(cls, name, bases, dict):
+		super(store_task_type, cls).__init__(name, bases, dict)
+		name = cls.__name__
+
+		if name.endswith('_task'):
+			name = name.replace('_task', '')
+		if name != 'evil' and name != 'TaskBase':
+			global classes
+
+			if getattr(cls, 'run_str', None):
+				# if a string is provided, convert it to a method
+				(f, dvars) = compile_fun(cls.run_str, cls.shell)
+				cls.hcode = cls.run_str
+				cls.run_str = None
+				cls.run = f
+				cls.vars = list(set(cls.vars + dvars))
+				cls.vars.sort()
+			elif getattr(cls, 'run', None) and not 'hcode' in cls.__dict__:
+				# getattr(cls, 'hcode') would look in the upper classes
+				cls.hcode = Utils.h_fun(cls.run)
+
+			if not getattr(cls, 'nocache', None):
+				cls = cache_outputs(cls)
+
+			classes[name] = cls
+
+evil = store_task_type('evil', (object,), {})
+"Base class provided to avoid writing a metaclass, so the code can run in python 2.6 and 3.x unmodified"
+
+class TaskBase(evil):
+	"""
+	Base class for all Waf tasks, which should be seen as an interface.
+	For illustration purposes, instances of this class will execute the attribute
+	'fun' in :py:meth:`waflib.Task.TaskBase.run`. When in doubt, create
+	subclasses of :py:class:`waflib.Task.Task` instead.
+
+	Subclasses should override these methods:
+
+	#. __str__: string to display to the user
+	#. runnable_status: ask the task if it should be run, skipped, or if we have to ask later
+	#. run: let threads execute the task
+	#. post_run: let threads update the data regarding the task (cache)
+	"""
+
+	color = 'GREEN'
+	"""Color for the console display, see :py:const:`waflib.Logs.colors_lst`"""
+
+	ext_in = []
+	"""File extensions that objects of this task class might use"""
+
+	ext_out = []
+	"""File extensions that objects of this task class might create"""
+
+	before = []
+	"""List of task class names to execute before instances of this class"""
+
+	after = []
+	"""List of task class names to execute after instances of this class"""
+
+	hcode = ''
+	"""String representing an additional hash for the class representation"""
+
+	def __init__(self, *k, **kw):
+		"""
+		The base task class requires a task generator, which will be itself if missing
+		"""
+		self.hasrun = NOT_RUN
+		try:
+			self.generator = kw['generator']
+		except KeyError:
+			self.generator = self
+
+	def __repr__(self):
+		"for debugging purposes"
+		return '\n\t{task %r: %s %s}' % (self.__class__.__name__, id(self), str(getattr(self, 'fun', '')))
+
+	def __str__(self):
+		"string to display to the user"
+		if hasattr(self, 'fun'):
+			return 'executing: %s\n' % self.fun.__name__
+		return self.__class__.__name__ + '\n'
+
+	def __hash__(self):
+		"Very fast hashing scheme but not persistent (replace/implement in subclasses and see :py:meth:`waflib.Task.Task.uid`)"
+		return id(self)
+
+	def exec_command(self, cmd, **kw):
+		"""
+		Wrapper for :py:meth:`waflib.Context.Context.exec_command` which sets a current working directory to ``build.variant_dir``
+
+		:return: the return code
+		:rtype: int
+		"""
+		bld = self.generator.bld
+		try:
+			if not kw.get('cwd', None):
+				kw['cwd'] = bld.cwd
+		except AttributeError:
+			bld.cwd = kw['cwd'] = bld.variant_dir
+		return bld.exec_command(cmd, **kw)
+
+	def runnable_status(self):
+		"""
+		State of the task
+
+		:return: a task state in :py:const:`waflib.Task.RUN_ME`, :py:const:`waflib.Task.SKIP_ME` or :py:const:`waflib.Task.ASK_LATER`.
+		:rtype: int
+		"""
+		return RUN_ME
+
+	def process(self):
+		"""
+		Assume that the task has had a new attribute ``master`` which is an instance of :py:class:`waflib.Runner.Parallel`.
+		Execute the task and then put it back in the queue :py:attr:`waflib.Runner.Parallel.out` (may be replaced by subclassing).
+		"""
+		m = self.master
+		if m.stop:
+			m.out.put(self)
+			return
+
+		# remove the task signature immediately before it is executed
+		# in case of failure the task will be executed again
+		try:
+			del self.generator.bld.task_sigs[self.uid()]
+		except:
+			pass
+
+		try:
+			self.generator.bld.returned_tasks.append(self)
+			self.log_display(self.generator.bld)
+			ret = self.run()
+		except Exception:
+			self.err_msg = Utils.ex_stack()
+			self.hasrun = EXCEPTION
+
+			# TODO cleanup
+			m.error_handler(self)
+			m.out.put(self)
+			return
+
+		if ret:
+			self.err_code = ret
+			self.hasrun = CRASHED
+		else:
+			try:
+				self.post_run()
+			except Errors.WafError:
+				pass
+			except Exception:
+				self.err_msg = Utils.ex_stack()
+				self.hasrun = EXCEPTION
+			else:
+				self.hasrun = SUCCESS
+		if self.hasrun != SUCCESS:
+			m.error_handler(self)
+
+		m.out.put(self)
+
+	def run(self):
+		"""
+		Execute the task (executed by threads). Override in subclasses.
+
+		:rtype: int
+		"""
+		if hasattr(self, 'fun'):
+			return self.fun(self)
+		return 0
+
+	def post_run(self):
+		"Update the cache files (executed by threads). Override in subclasses."
+		pass
+
+	def log_display(self, bld):
+		"Write the execution status on the context logger"
+		bld.to_log(self.display())
+
+	def display(self):
+		"""
+		Return an execution status for the console, the progress bar, or the IDE output.
+
+		:rtype: string
+		"""
+		col1 = Logs.colors(self.color)
+		col2 = Logs.colors.NORMAL
+		master = self.master
+
+		def cur():
+			# the current task position, computed as late as possible
+			tmp = -1
+			if hasattr(master, 'ready'):
+				tmp -= master.ready.qsize()
+			return master.processed + tmp
+
+		if self.generator.bld.progress_bar == 1:
+			return self.generator.bld.progress_line(cur(), master.total, col1, col2)
+
+		if self.generator.bld.progress_bar == 2:
+			ela = str(self.generator.bld.timer)
+			try:
+				ins  = ','.join([n.name for n in self.inputs])
+			except AttributeError:
+				ins = ''
+			try:
+				outs = ','.join([n.name for n in self.outputs])
+			except AttributeError:
+				outs = ''
+			return '|Total %s|Current %s|Inputs %s|Outputs %s|Time %s|\n' % (master.total, cur(), ins, outs, ela)
+
+		s = str(self)
+		if not s:
+			return None
+
+		total = master.total
+		n = len(str(total))
+		fs = '[%%%dd/%%%dd] %%s%%s%%s' % (n, n)
+		return fs % (cur(), total, col1, s, col2)
+
+	def attr(self, att, default=None):
+		"""
+		Retrieve an attribute from the instance or from the class.
+
+		:param att: variable name
+		:type att: string
+		:param default: default value
+		"""
+		ret = getattr(self, att, self)
+		if ret is self: return getattr(self.__class__, att, default)
+		return ret
+
+	def hash_constraints(self):
+		"""
+		Identify a task type for all the constraints relevant for the scheduler: precedence, file production
+
+		:return: a hash value
+		:rtype: string
+		"""
+		cls = self.__class__
+		tup = (str(cls.before), str(cls.after), str(cls.ext_in), str(cls.ext_out), cls.__name__, cls.hcode)
+		h = hash(tup)
+		return h
+
+	def format_error(self):
+		"""
+		Error message to display to the user when a build fails
+
+		:rtype: string
+		"""
+		msg = getattr(self, 'last_cmd', '')
+		if getattr(self, "err_msg", None):
+			return self.err_msg
+		elif not self.hasrun:
+			return 'task was not executed for some reason'
+		elif self.hasrun == CRASHED:
+			try:
+				return ' -> task failed (exit status %r): %r\n%r' % (self.err_code, self, msg)
+			except AttributeError:
+				return ' -> task failed: %r\n%r' % (self, msg)
+		elif self.hasrun == MISSING:
+			return ' -> missing files: %r\n%r' % (self, msg)
+		else:
+			return 'invalid status %r' % self.hasrun
+
+	def colon(self, var1, var2):
+		"""
+		private function for the moment
+
+		used for scriptlet expressions such as ${FOO_ST:FOO}, for example, if
+		env.FOO_ST = ['-a', '-b']
+		env.FOO    = ['1', '2']
+		then the result will be ['-a', '-b', '1', '-a', '-b', '2']
+		"""
+		tmp = self.env[var1]
+		if isinstance(var2, str):
+			it = self.env[var2]
+		else:
+			it = var2
+		if isinstance(tmp, str):
+			return [tmp % '"' + x + '"' for x in it]
+		else:
+			if Logs.verbose and not tmp and it:
+				Logs.warn('Missing env variable %r for task %r (generator %r)' % (var1, self, self.generator))
+			lst = []
+			for y in it:
+				lst.extend(tmp)
+				lst.append('"' + y + '"')
+			return lst
+
+class Task(TaskBase):
+	"""
+	This class deals with the filesystem (:py:class:`waflib.Node.Node`). The method :py:class:`waflib.Task.Task.runnable_status`
+	uses a hash value (from :py:class:`waflib.Task.Task.signature`) which is persistent from build to build. When the value changes,
+	the task has to be executed. The method :py:class:`waflib.Task.Task.post_run` will assign the task signature to the output
+	nodes (if present).
+	"""
+	vars = []
+	"""Variables to depend on (class attribute used for :py:meth:`waflib.Task.Task.sig_vars`)"""
+
+	shell = False
+	"""Execute the command with the shell (class attribute)"""
+
+	def __init__(self, *k, **kw):
+		TaskBase.__init__(self, *k, **kw)
+
+		self.env = kw['env']
+		"""ConfigSet object (make sure to provide one)"""
+
+		self.inputs  = []
+		"""List of input nodes, which represent the files used by the task instance"""
+
+		self.outputs = []
+		"""List of output nodes, which represent the files created by the task instance"""
+
+		self.dep_nodes = []
+		"""List of additional nodes to depend on"""
+
+		self.run_after = set([])
+		"""Set of tasks that must be executed before this one"""
+
+		# Additionally, you may define the following
+		#self.dep_vars  = 'PREFIX DATADIR'
+
+	def __str__(self):
+		"string to display to the user"
+		env = self.env
+		src_str = ' '.join([a.nice_path(env) for a in self.inputs])
+		tgt_str = ' '.join([a.nice_path(env) for a in self.outputs])
+		if self.outputs: sep = ' -> '
+		else: sep = ''
+		return '%s: %s%s%s\n' % (self.__class__.__name__.replace('_task', ''), src_str, sep, tgt_str)
+
+	def __repr__(self):
+		"for debugging purposes"
+		return "".join(['\n\t{task %r: ' % id(self), self.__class__.__name__, " ", ",".join([x.name for x in self.inputs]), " -> ", ",".join([x.name for x in self.outputs]), '}'])
+
+	def uid(self):
+		"""
+		Return an identifier used to determine if tasks are up-to-date. Since the
+		identifier will be stored between executions, it must be:
+
+			- unique: no two tasks return the same value (for a given build context)
+			- the same for a given task instance
+
+		By default, the node paths, the class name, and the function are used
+		as inputs to compute a hash.
+
+		The pointer to the object (python built-in 'id') will change between build executions,
+		and must be avoided in such hashes.
+
+		:return: hash value
+		:rtype: string
+		"""
+		try:
+			return self.uid_
+		except AttributeError:
+			# this is not a real hot zone, but we want to avoid surprizes here
+			m = Utils.md5()
+			up = m.update
+			up(self.__class__.__name__.encode())
+			for x in self.inputs + self.outputs:
+				up(x.abspath().encode())
+			self.uid_ = m.digest()
+			return self.uid_
+
+	def set_inputs(self, inp):
+		"""
+		Append the nodes to the *inputs*
+
+		:param inp: input nodes
+		:type inp: node or list of nodes
+		"""
+		if isinstance(inp, list): self.inputs += inp
+		else: self.inputs.append(inp)
+
+	def set_outputs(self, out):
+		"""
+		Append the nodes to the *outputs*
+
+		:param out: output nodes
+		:type out: node or list of nodes
+		"""
+		if isinstance(out, list): self.outputs += out
+		else: self.outputs.append(out)
+
+	def set_run_after(self, task):
+		"""
+		Run this task only after *task*. Affect :py:meth:`waflib.Task.runnable_status`
+
+		:param task: task
+		:type task: :py:class:`waflib.Task.Task`
+		"""
+		# TODO: handle lists too?
+		assert isinstance(task, TaskBase)
+		self.run_after.add(task)
+
+	def signature(self):
+		"""
+		Task signatures are stored between build executions, they are use to track the changes
+		made to the input nodes (not to the outputs!). The signature hashes data from various sources:
+
+		* explicit dependencies: files listed in the inputs (list of node objects) :py:meth:`waflib.Task.Task.sig_explicit_deps`
+		* implicit dependencies: list of nodes returned by scanner methods (when present) :py:meth:`waflib.Task.Task.sig_implicit_deps`
+		* hashed data: variables/values read from task.__class__.vars/task.env :py:meth:`waflib.Task.Task.sig_vars`
+
+		If the signature is expected to give a different result, clear the cache kept in ``self.cache_sig``::
+
+			from waflib import Task
+			class cls(Task.Task):
+				def signature(self):
+					sig = super(Task.Task, self).signature()
+					delattr(self, 'cache_sig')
+					return super(Task.Task, self).signature()
+		"""
+		try: return self.cache_sig
+		except AttributeError: pass
+
+		self.m = Utils.md5()
+		self.m.update(self.hcode.encode())
+
+		# explicit deps
+		self.sig_explicit_deps()
+
+		# env vars
+		self.sig_vars()
+
+		# implicit deps / scanner results
+		if self.scan:
+			try:
+				self.sig_implicit_deps()
+			except Errors.TaskRescan:
+				return self.signature()
+
+		ret = self.cache_sig = self.m.digest()
+		return ret
+
+	def runnable_status(self):
+		"""
+		Override :py:meth:`waflib.Task.TaskBase.runnable_status` to determine if the task is ready
+		to be run (:py:attr:`waflib.Task.Task.run_after`)
+		"""
+		#return 0 # benchmarking
+
+		for t in self.run_after:
+			if not t.hasrun:
+				return ASK_LATER
+
+		bld = self.generator.bld
+
+		# first compute the signature
+		try:
+			new_sig = self.signature()
+		except Errors.TaskNotReady:
+			return ASK_LATER
+
+		# compare the signature to a signature computed previously
+		key = self.uid()
+		try:
+			prev_sig = bld.task_sigs[key]
+		except KeyError:
+			Logs.debug("task: task %r must run as it was never run before or the task code changed" % self)
+			return RUN_ME
+
+		# compare the signatures of the outputs
+		for node in self.outputs:
+			try:
+				if node.sig != new_sig:
+					return RUN_ME
+			except AttributeError:
+				Logs.debug("task: task %r must run as the output nodes do not exist" % self)
+				return RUN_ME
+
+		if new_sig != prev_sig:
+			return RUN_ME
+		return SKIP_ME
+
+	def post_run(self):
+		"""
+		Called after successful execution to update the cache data :py:class:`waflib.Node.Node` sigs
+		and :py:attr:`waflib.Build.BuildContext.task_sigs`.
+
+		The node signature is obtained from the task signature, but the output nodes may also get the signature
+		of their contents. See the class decorator :py:func:`waflib.Task.update_outputs` if you need this behaviour.
+		"""
+		bld = self.generator.bld
+		sig = self.signature()
+
+		for node in self.outputs:
+			# check if the node exists ..
+			try:
+				os.stat(node.abspath())
+			except OSError:
+				self.hasrun = MISSING
+				self.err_msg = '-> missing file: %r' % node.abspath()
+				raise Errors.WafError(self.err_msg)
+
+			# important, store the signature for the next run
+			node.sig = sig
+
+		bld.task_sigs[self.uid()] = self.cache_sig
+
+	def sig_explicit_deps(self):
+		"""
+		Used by :py:meth:`waflib.Task.Task.signature`, hash :py:attr:`waflib.Task.Task.inputs`
+		and :py:attr:`waflib.Task.Task.dep_nodes` signatures.
+
+		:rtype: hash value
+		"""
+		bld = self.generator.bld
+		upd = self.m.update
+
+		# the inputs
+		for x in self.inputs + self.dep_nodes:
+			try:
+				upd(x.get_bld_sig())
+			except (AttributeError, TypeError):
+				raise Errors.WafError('Missing node signature for %r (required by %r)' % (x, self))
+
+		# manual dependencies, they can slow down the builds
+		if bld.deps_man:
+			additional_deps = bld.deps_man
+			for x in self.inputs + self.outputs:
+				try:
+					d = additional_deps[id(x)]
+				except KeyError:
+					continue
+
+				for v in d:
+					if isinstance(v, bld.root.__class__):
+						try:
+							v = v.get_bld_sig()
+						except AttributeError:
+							raise Errors.WafError('Missing node signature for %r (required by %r)' % (v, self))
+					elif hasattr(v, '__call__'):
+						v = v() # dependency is a function, call it
+					upd(v)
+
+		return self.m.digest()
+
+	def sig_vars(self):
+		"""
+		Used by :py:meth:`waflib.Task.Task.signature`, hash :py:attr:`waflib.Task.Task.env` variables/values
+
+		:rtype: hash value
+		"""
+		bld = self.generator.bld
+		env = self.env
+		upd = self.m.update
+
+		# dependencies on the environment vars
+		act_sig = bld.hash_env_vars(env, self.__class__.vars)
+		upd(act_sig)
+
+		# additional variable dependencies, if provided
+		dep_vars = getattr(self, 'dep_vars', None)
+		if dep_vars:
+			upd(bld.hash_env_vars(env, dep_vars))
+
+		return self.m.digest()
+
+	scan = None
+	"""
+	This method, when provided, returns a tuple containing:
+
+	* a list of nodes corresponding to real files
+	* a list of names for files not found in path_lst
+
+	For example::
+
+		from waflib.Task import Task
+		class mytask(Task):
+			def scan(self, node):
+				return ((), ())
+
+	The first and second lists are stored in :py:attr:`waflib.Build.BuildContext.node_deps` and
+	:py:attr:`waflib.Build.BuildContext.raw_deps` respectively.
+	"""
+
+	def sig_implicit_deps(self):
+		"""
+		Used by :py:meth:`waflib.Task.Task.signature` hashes node signatures obtained by scanning for dependencies (:py:meth:`waflib.Task.Task.scan`).
+
+		The exception :py:class:`waflib.Errors.TaskRescan` is thrown
+		when a file has changed. When this occurs, :py:meth:`waflib.Task.Task.signature` is called
+		once again, and this method will be executed once again, this time calling :py:meth:`waflib.Task.Task.scan`
+		for searching the dependencies.
+
+		:rtype: hash value
+		"""
+
+		bld = self.generator.bld
+
+		# get the task signatures from previous runs
+		key = self.uid()
+		prev = bld.task_sigs.get((key, 'imp'), [])
+
+		# for issue #379
+		if prev:
+			try:
+				if prev == self.compute_sig_implicit_deps():
+					return prev
+			except:
+				# when a file was renamed (IOError usually), remove the stale nodes (headers in folders without source files)
+				# this will break the order calculation for headers created during the build in the source directory (should be uncommon)
+				# the behaviour will differ when top != out
+				for x in bld.node_deps.get(self.uid(), []):
+					if x.is_child_of(bld.srcnode):
+						try:
+							os.stat(x.abspath())
+						except:
+							try:
+								del x.parent.children[x.name]
+							except:
+								pass
+			del bld.task_sigs[(key, 'imp')]
+			raise Errors.TaskRescan('rescan')
+
+		# no previous run or the signature of the dependencies has changed, rescan the dependencies
+		(nodes, names) = self.scan()
+		if Logs.verbose:
+			Logs.debug('deps: scanner for %s returned %s %s' % (str(self), str(nodes), str(names)))
+
+		# store the dependencies in the cache
+		bld.node_deps[key] = nodes
+		bld.raw_deps[key] = names
+
+		# might happen
+		self.are_implicit_nodes_ready()
+
+		# recompute the signature and return it
+		try:
+			bld.task_sigs[(key, 'imp')] = sig = self.compute_sig_implicit_deps()
+		except:
+			if Logs.verbose:
+				for k in bld.node_deps.get(self.uid(), []):
+					try:
+						k.get_bld_sig()
+					except:
+						Logs.warn('Missing signature for node %r (may cause rebuilds)' % k)
+		else:
+			return sig
+
+	def compute_sig_implicit_deps(self):
+		"""
+		Used by :py:meth:`waflib.Task.Task.sig_implicit_deps` for computing the actual hash of the
+		:py:class:`waflib.Node.Node` returned by the scanner.
+
+		:return: hash value
+		:rtype: string
+		"""
+
+		upd = self.m.update
+
+		bld = self.generator.bld
+
+		self.are_implicit_nodes_ready()
+
+		# scanner returns a node that does not have a signature
+		# just *ignore* the error and let them figure out from the compiler output
+		# waf -k behaviour
+		for k in bld.node_deps.get(self.uid(), []):
+			upd(k.get_bld_sig())
+		return self.m.digest()
+
+	def are_implicit_nodes_ready(self):
+		"""
+		For each node returned by the scanner, see if there is a task behind it, and force the build order
+
+		The performance impact on null builds is nearly invisible (1.66s->1.86s), but this is due to
+		agressive caching (1.86s->28s)
+		"""
+		bld = self.generator.bld
+		try:
+			cache = bld.dct_implicit_nodes
+		except:
+			bld.dct_implicit_nodes = cache = {}
+
+		try:
+			dct = cache[bld.cur]
+		except KeyError:
+			dct = cache[bld.cur] = {}
+			for tsk in bld.cur_tasks:
+				for x in tsk.outputs:
+					dct[x] = tsk
+
+		modified = False
+		for x in bld.node_deps.get(self.uid(), []):
+			if x in dct:
+				self.run_after.add(dct[x])
+				modified = True
+
+		if modified:
+			for tsk in self.run_after:
+				if not tsk.hasrun:
+					#print "task is not ready..."
+					raise Errors.TaskNotReady('not ready')
+
+	def can_retrieve_cache(self):
+		"""
+		Used by :py:meth:`waflib.Task.cache_outputs`
+
+		Retrieve build nodes from the cache
+		update the file timestamps to help cleaning the least used entries from the cache
+		additionally, set an attribute 'cached' to avoid re-creating the same cache files
+
+		Suppose there are files in `cache/dir1/file1` and `cache/dir2/file2`:
+
+		#. read the timestamp of dir1
+		#. try to copy the files
+		#. look at the timestamp again, if it has changed, the data may have been corrupt (cache update by another process)
+		#. should an exception occur, ignore the data
+		"""
+
+		if not getattr(self, 'outputs', None):
+			return None
+
+		sig = self.signature()
+		ssig = Utils.to_hex(self.uid()) + Utils.to_hex(sig)
+
+		# first try to access the cache folder for the task
+		dname = os.path.join(self.generator.bld.cache_global, ssig)
+		try:
+			t1 = os.stat(dname).st_mtime
+		except OSError:
+			return None
+
+		for node in self.outputs:
+			orig = os.path.join(dname, node.name)
+			try:
+				shutil.copy2(orig, node.abspath())
+				# mark the cache file as used recently (modified)
+				os.utime(orig, None)
+			except (OSError, IOError):
+				Logs.debug('task: failed retrieving file')
+				return None
+
+		# is it the same folder?
+		try:
+			t2 = os.stat(dname).st_mtime
+		except OSError:
+			return None
+
+		if t1 != t2:
+			return None
+
+		for node in self.outputs:
+			node.sig = sig
+			if self.generator.bld.progress_bar < 1:
+				self.generator.bld.to_log('restoring from cache %r\n' % node.abspath())
+
+		self.cached = True
+		return True
+
+	def put_files_cache(self):
+		"""
+		Used by :py:func:`waflib.Task.cache_outputs` to store the build files in the cache
+		"""
+
+		# file caching, if possible
+		# try to avoid data corruption as much as possible
+		if getattr(self, 'cached', None):
+			return None
+		if not getattr(self, 'outputs', None):
+			return None
+
+		sig = self.signature()
+		ssig = Utils.to_hex(self.uid()) + Utils.to_hex(sig)
+		dname = os.path.join(self.generator.bld.cache_global, ssig)
+		tmpdir = tempfile.mkdtemp(prefix=self.generator.bld.cache_global + os.sep + 'waf')
+
+		try:
+			shutil.rmtree(dname)
+		except:
+			pass
+
+		try:
+			for node in self.outputs:
+				dest = os.path.join(tmpdir, node.name)
+				shutil.copy2(node.abspath(), dest)
+		except (OSError, IOError):
+			try:
+				shutil.rmtree(tmpdir)
+			except:
+				pass
+		else:
+			try:
+				os.rename(tmpdir, dname)
+			except OSError:
+				try:
+					shutil.rmtree(tmpdir)
+				except:
+					pass
+			else:
+				try:
+					os.chmod(dname, Utils.O755)
+				except:
+					pass
+
+def is_before(t1, t2):
+	"""
+	Return a non-zero value if task t1 is to be executed before task t2::
+
+		t1.ext_out = '.h'
+		t2.ext_in = '.h'
+		t2.after = ['t1']
+		t1.before = ['t2']
+		waflib.Task.is_before(t1, t2) # True
+
+	:param t1: task
+	:type t1: :py:class:`waflib.Task.TaskBase`
+	:param t2: task
+	:type t2: :py:class:`waflib.Task.TaskBase`
+	"""
+	to_list = Utils.to_list
+	for k in to_list(t2.ext_in):
+		if k in to_list(t1.ext_out):
+			return 1
+
+	if t1.__class__.__name__ in to_list(t2.after):
+		return 1
+
+	if t2.__class__.__name__ in to_list(t1.before):
+		return 1
+
+	return 0
+
+def set_file_constraints(tasks):
+	"""
+	Adds tasks to the task 'run_after' attribute based on the task inputs and outputs
+
+	:param tasks: tasks
+	:type tasks: list of :py:class:`waflib.Task.TaskBase`
+	"""
+	ins = Utils.defaultdict(set)
+	outs = Utils.defaultdict(set)
+	for x in tasks:
+		for a in getattr(x, 'inputs', []) + getattr(x, 'dep_nodes', []):
+			ins[id(a)].add(x)
+		for a in getattr(x, 'outputs', []):
+			outs[id(a)].add(x)
+
+	links = set(ins.keys()).intersection(outs.keys())
+	for k in links:
+		for a in ins[k]:
+			a.run_after.update(outs[k])
+
+def set_precedence_constraints(tasks):
+	"""
+	Add tasks to the task 'run_after' attribute based on the after/before/ext_out/ext_in attributes
+
+	:param tasks: tasks
+	:type tasks: list of :py:class:`waflib.Task.TaskBase`
+	"""
+	cstr_groups = Utils.defaultdict(list)
+	for x in tasks:
+		h = x.hash_constraints()
+		cstr_groups[h].append(x)
+
+	keys = list(cstr_groups.keys())
+	maxi = len(keys)
+
+	# this list should be short
+	for i in range(maxi):
+		t1 = cstr_groups[keys[i]][0]
+		for j in range(i + 1, maxi):
+			t2 = cstr_groups[keys[j]][0]
+
+			# add the constraints based on the comparisons
+			if is_before(t1, t2):
+				a = i
+				b = j
+			elif is_before(t2, t1):
+				a = j
+				b = i
+			else:
+				continue
+			for x in cstr_groups[keys[b]]:
+				x.run_after.update(cstr_groups[keys[a]])
+
+def funex(c):
+	"""
+	Compile a function by 'exec'
+
+	:param c: function to compile
+	:type c: string
+	:return: the function 'f' declared in the input string
+	:rtype: function
+	"""
+	dc = {}
+	exec(c, dc)
+	return dc['f']
+
+reg_act = re.compile(r"(?P<backslash>\\)|(?P<dollar>\$\$)|(?P<subst>\$\{(?P<var>\w+)(?P<code>.*?)\})", re.M)
+def compile_fun_shell(line):
+	"""
+	Create a compiled function to execute a process with the shell
+	WARNING: this method may disappear anytime, so use compile_fun instead
+	"""
+
+	extr = []
+	def repl(match):
+		g = match.group
+		if g('dollar'): return "$"
+		elif g('backslash'): return '\\\\'
+		elif g('subst'): extr.append((g('var'), g('code'))); return "%s"
+		return None
+
+	line = reg_act.sub(repl, line) or line
+
+	parm = []
+	dvars = []
+	app = parm.append
+	for (var, meth) in extr:
+		if var == 'SRC':
+			if meth: app('"\\"" + tsk.inputs%s + "\\""' % meth)
+			else: app('" ".join(["\\"" + a.path_from(bld.bldnode) + "\\"" for a in tsk.inputs])')
+		elif var == 'TGT':
+			if meth: app('"\\"" + tsk.outputs%s + "\\""' % meth)
+			else: app('" ".join(["\\"" + a.path_from(bld.bldnode) + "\\"" for a in tsk.outputs])')
+		elif meth:
+			if meth.startswith(':'):
+				m = meth[1:]
+				if m == 'SRC':
+					m = '[a.path_from(bld.bldnode) for a in tsk.inputs]'
+				elif m == 'TGT':
+					m = '[a.path_from(bld.bldnode) for a in tsk.outputs]'
+				elif m[:3] not in ('tsk', 'gen', 'bld'):
+					dvars.extend([var, meth[1:]])
+					m = '%r' % m
+				app('" ".join(tsk.colon(%r, %s))' % (var, m))
+			else:
+				app('%s%s' % (var, meth))
+		else:
+			if not var in dvars: dvars.append(var)
+			app("p('%s')" % var)
+	if parm: parm = "%% (%s) " % (',\n\t\t'.join(parm))
+	else: parm = ''
+
+	c = COMPILE_TEMPLATE_SHELL % (line, parm)
+
+	Logs.debug('action: %s' % c)
+	return (funex(c), dvars)
+
+def compile_fun_noshell(line):
+	"""
+	Create a compiled function to execute a process without the shell
+	WARNING: this method may disappear anytime, so use compile_fun instead
+	"""
+	extr = []
+	def repl(match):
+		g = match.group
+		if g('dollar'): return "$"
+		elif g('subst'): extr.append((g('var'), g('code'))); return "<<|@|>>"
+		return None
+
+	line2 = reg_act.sub(repl, line)
+	params = line2.split('<<|@|>>')
+	assert(extr)
+
+	buf = []
+	dvars = []
+	app = buf.append
+	for x in range(len(extr)):
+		params[x] = params[x].strip()
+		if params[x]:
+			app("lst.extend(%r)" % params[x].split())
+		(var, meth) = extr[x]
+		if var == 'SRC':
+			if meth: app('lst.append(tsk.inputs%s)' % meth)
+			else: app("lst.extend([a.path_from(bld.bldnode) for a in tsk.inputs])")
+		elif var == 'TGT':
+			if meth: app('lst.append(tsk.outputs%s)' % meth)
+			else: app("lst.extend([a.path_from(bld.bldnode) for a in tsk.outputs])")
+		elif meth:
+			if meth.startswith(':'):
+				m = meth[1:]
+				if m == 'SRC':
+					m = '[a.path_from(bld.bldnode) for a in tsk.inputs]'
+				elif m == 'TGT':
+					m = '[a.path_from(bld.bldnode) for a in tsk.outputs]'
+				elif m[:3] not in ('tsk', 'gen', 'bld'):
+					dvars.extend([var, m])
+					m = '%r' % m
+				app('lst.extend(tsk.colon(%r, %s))' % (var, m))
+			else:
+				app('lst.extend(gen.to_list(%s%s))' % (var, meth))
+		else:
+			app('lst.extend(to_list(env[%r]))' % var)
+			if not var in dvars: dvars.append(var)
+
+	if extr:
+		if params[-1]:
+			app("lst.extend(%r)" % params[-1].split())
+	fun = COMPILE_TEMPLATE_NOSHELL % "\n\t".join(buf)
+	Logs.debug('action: %s' % fun)
+	return (funex(fun), dvars)
+
+def compile_fun(line, shell=False):
+	"""
+	Parse a string expression such as "${CC} ${SRC} -o ${TGT}" and return a pair containing:
+
+	* the function created (compiled) for use as :py:meth:`waflib.Task.TaskBase.run`
+	* the list of variables that imply a dependency from self.env
+
+	for example::
+
+		from waflib.Task import compile_fun
+		compile_fun('cxx', '${CXX} -o ${TGT[0]} ${SRC} -I ${SRC[0].parent.bldpath()}')
+
+		def build(bld):
+			bld(source='wscript', rule='echo "foo\\${SRC[0].name}\\bar"')
+
+	The env variables (CXX, ..) on the task must not hold dicts (order)
+	The reserved keywords *TGT* and *SRC* represent the task input and output nodes
+
+	"""
+	if line.find('<') > 0 or line.find('>') > 0 or line.find('&&') > 0:
+		shell = True
+
+	if shell:
+		return compile_fun_shell(line)
+	else:
+		return compile_fun_noshell(line)
+
+def task_factory(name, func=None, vars=None, color='GREEN', ext_in=[], ext_out=[], before=[], after=[], shell=False, scan=None):
+	"""
+	Return a new task subclass with the function ``run`` compiled from the line given.
+	Provided for compatibility with waf 1.4-1.5, when we did not use metaclasses to register new objects.
+
+	:param func: method run
+	:type func: string or function
+	:param vars: list of variables to hash
+	:type vars: list of string
+	:param color: color to use
+	:type color: string
+	:param shell: when *func* is a string, enable/disable the use of the shell
+	:type shell: bool
+	:param scan: method scan
+	:type scan: function
+	:rtype: :py:class:`waflib.Task.Task`
+	"""
+
+	params = {
+		'vars': vars or [], # function arguments are static, and this one may be modified by the class
+		'color': color,
+		'name': name,
+		'ext_in': Utils.to_list(ext_in),
+		'ext_out': Utils.to_list(ext_out),
+		'before': Utils.to_list(before),
+		'after': Utils.to_list(after),
+		'shell': shell,
+		'scan': scan,
+	}
+
+	if isinstance(func, str):
+		params['run_str'] = func
+	else:
+		params['run'] = func
+
+	cls = type(Task)(name, (Task,), params)
+	global classes
+	classes[name] = cls
+	return cls
+
+
+def always_run(cls):
+	"""
+	Task class decorator
+
+	Set all task instances of this class to be executed whenever a build is started
+	The task signature is calculated, but the result of the comparation between
+	task signatures is bypassed
+	"""
+	old = cls.runnable_status
+	def always(self):
+		ret = old(self)
+		if ret == SKIP_ME:
+			ret = RUN_ME
+		return ret
+	cls.runnable_status = always
+	return cls
+
+def update_outputs(cls):
+	"""
+	Task class decorator
+
+	If you want to create files in the source directory. For example, to keep *foo.txt* in the source
+	directory, create it first and declare::
+
+		def build(bld):
+			bld(rule='cp ${SRC} ${TGT}', source='wscript', target='foo.txt', update_outputs=True)
+	"""
+	old_post_run = cls.post_run
+	def post_run(self):
+		old_post_run(self)
+		for node in self.outputs:
+			node.sig = Utils.h_file(node.abspath())
+			self.generator.bld.task_sigs[node.abspath()] = self.uid() # issue #1017
+	cls.post_run = post_run
+
+
+	old_runnable_status = cls.runnable_status
+	def runnable_status(self):
+		status = old_runnable_status(self)
+		if status != RUN_ME:
+			return status
+
+		try:
+			# by default, we check that the output nodes have the signature of the task
+			# perform a second check, returning 'SKIP_ME' as we are expecting that
+			# the signatures do not match
+			bld = self.generator.bld
+			prev_sig = bld.task_sigs[self.uid()]
+			if prev_sig == self.signature():
+				for x in self.outputs:
+					if not x.sig or bld.task_sigs[x.abspath()] != self.uid():
+						return RUN_ME
+				return SKIP_ME
+		except KeyError:
+			pass
+		except IndexError:
+			pass
+		except AttributeError:
+			pass
+		return RUN_ME
+	cls.runnable_status = runnable_status
+
+	return cls
+
+
diff --git a/xpdeint/waf/waflib/Task.pyc b/xpdeint/waf/waflib/Task.pyc
new file mode 100644
index 0000000..8ed391c
Binary files /dev/null and b/xpdeint/waf/waflib/Task.pyc differ
diff --git a/xpdeint/waf/waflib/TaskGen.py b/xpdeint/waf/waflib/TaskGen.py
new file mode 100644
index 0000000..3744ee0
--- /dev/null
+++ b/xpdeint/waf/waflib/TaskGen.py
@@ -0,0 +1,754 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005-2010 (ita)
+
+"""
+Task generators
+
+The class :py:class:`waflib.TaskGen.task_gen` encapsulates the creation of task objects (low-level code)
+The instances can have various parameters, but the creation of task nodes (Task.py)
+is always postponed. To achieve this, various methods are called from the method "apply"
+
+
+"""
+
+import copy, re
+from waflib import Task, Utils, Logs, Errors, ConfigSet
+
+feats = Utils.defaultdict(set)
+"""remember the methods declaring features"""
+
+class task_gen(object):
+	"""
+	Instances of this class create :py:class:`waflib.Task.TaskBase` when
+	calling the method :py:meth:`waflib.TaskGen.task_gen.post` from the main thread.
+	A few notes:
+
+	* The methods to call (*self.meths*) can be specified dynamically (removing, adding, ..)
+	* The 'features' are used to add methods to self.meths and then execute them
+	* The attribute 'path' is a node representing the location of the task generator
+	* The tasks created are added to the attribute *tasks*
+	* The attribute 'idx' is a counter of task generators in the same path
+	"""
+
+	mappings = {}
+	prec = Utils.defaultdict(list)
+
+	def __init__(self, *k, **kw):
+		"""
+		The task generator objects predefine various attributes (source, target) for possible
+		processing by process_rule (make-like rules) or process_source (extensions, misc methods)
+
+		The tasks are stored on the attribute 'tasks'. They are created by calling methods
+		listed in self.meths *or* referenced in the attribute features
+		A topological sort is performed to ease the method re-use.
+
+		The extra key/value elements passed in kw are set as attributes
+		"""
+
+		# so we will have to play with directed acyclic graphs
+		# detect cycles, etc
+		self.source = ''
+		self.target = ''
+
+		self.meths = []
+		"""
+		List of method names to execute (it is usually a good idea to avoid touching this)
+		"""
+
+		self.prec = Utils.defaultdict(list)
+		"""
+		Precedence table for sorting the methods in self.meths
+		"""
+
+		self.mappings = {}
+		"""
+		List of mappings {extension -> function} for processing files by extension
+		"""
+
+		self.features = []
+		"""
+		List of feature names for bringing new methods in
+		"""
+
+		self.tasks = []
+		"""
+		List of tasks created.
+		"""
+
+		if not 'bld' in kw:
+			# task generators without a build context :-/
+			self.env = ConfigSet.ConfigSet()
+			self.idx = 0
+			self.path = None
+		else:
+			self.bld = kw['bld']
+			self.env = self.bld.env.derive()
+			self.path = self.bld.path # emulate chdir when reading scripts
+
+			# provide a unique id
+			try:
+				self.idx = self.bld.idx[id(self.path)] = self.bld.idx.get(id(self.path), 0) + 1
+			except AttributeError:
+				self.bld.idx = {}
+				self.idx = self.bld.idx[id(self.path)] = 1
+
+		for key, val in kw.items():
+			setattr(self, key, val)
+
+	def __str__(self):
+		"""for debugging purposes"""
+		return "<task_gen %r declared in %s>" % (self.name, self.path.abspath())
+
+	def __repr__(self):
+		"""for debugging purposes"""
+		lst = []
+		for x in self.__dict__.keys():
+			if x not in ['env', 'bld', 'compiled_tasks', 'tasks']:
+				lst.append("%s=%s" % (x, repr(getattr(self, x))))
+		return "bld(%s) in %s" % (", ".join(lst), self.path.abspath())
+
+	def get_name(self):
+		"""
+		If not set, the name is computed from the target name::
+
+			def build(bld):
+				x = bld(name='foo')
+				x.get_name() # foo
+				y = bld(target='bar')
+				y.get_name() # bar
+
+		:rtype: string
+		:return: name of this task generator
+		"""
+		try:
+			return self._name
+		except AttributeError:
+			if isinstance(self.target, list):
+				lst = [str(x) for x in self.target]
+				name = self._name = ','.join(lst)
+			else:
+				name = self._name = str(self.target)
+			return name
+	def set_name(self, name):
+		self._name = name
+
+	name = property(get_name, set_name)
+
+	def to_list(self, val):
+		"""
+		Ensure that a parameter is a list
+
+		:type val: string or list of string
+		:param val: input to return as a list
+		:rtype: list
+		"""
+		if isinstance(val, str): return val.split()
+		else: return val
+
+	def post(self):
+		"""
+		Create task objects. The following operations are performed:
+
+		#. The body of this method is called only once and sets the attribute ``posted``
+		#. The attribute ``features`` is used to add more methods in ``self.meths``
+		#. The methods are sorted by the precedence table ``self.prec`` or `:waflib:attr:waflib.TaskGen.task_gen.prec`
+		#. The methods are then executed in order
+		#. The tasks created are added to :py:attr:`waflib.TaskGen.task_gen.tasks`
+		"""
+
+		# we could add a decorator to let the task run once, but then python 2.3 will be difficult to support
+		if getattr(self, 'posted', None):
+			#error("OBJECT ALREADY POSTED" + str( self))
+			return False
+		self.posted = True
+
+		keys = set(self.meths)
+
+		# add the methods listed in the features
+		self.features = Utils.to_list(self.features)
+		for x in self.features + ['*']:
+			st = feats[x]
+			if not st:
+				if not x in Task.classes:
+					Logs.warn('feature %r does not exist - bind at least one method to it' % x)
+			keys.update(list(st)) # ironpython 2.7 wants the cast to list
+
+		# copy the precedence table
+		prec = {}
+		prec_tbl = self.prec or task_gen.prec
+		for x in prec_tbl:
+			if x in keys:
+				prec[x] = prec_tbl[x]
+
+		# elements disconnected
+		tmp = []
+		for a in keys:
+			for x in prec.values():
+				if a in x: break
+			else:
+				tmp.append(a)
+
+		# TODO waf 1.7
+		#tmp.sort()
+
+		# topological sort
+		out = []
+		while tmp:
+			e = tmp.pop()
+			if e in keys: out.append(e)
+			try:
+				nlst = prec[e]
+			except KeyError:
+				pass
+			else:
+				del prec[e]
+				for x in nlst:
+					for y in prec:
+						if x in prec[y]:
+							break
+					else:
+						tmp.append(x)
+
+		if prec:
+			raise Errors.WafError('Cycle detected in the method execution %r' % prec)
+		out.reverse()
+		self.meths = out
+
+		# then we run the methods in order
+		Logs.debug('task_gen: posting %s %d' % (self, id(self)))
+		for x in out:
+			try:
+				v = getattr(self, x)
+			except AttributeError:
+				raise Errors.WafError('%r is not a valid task generator method' % x)
+			Logs.debug('task_gen: -> %s (%d)' % (x, id(self)))
+			v()
+
+		Logs.debug('task_gen: posted %s' % self.name)
+		return True
+
+	def get_hook(self, node):
+		"""
+		:param node: Input file to process
+		:type node: :py:class:`waflib.Tools.Node.Node`
+		:return: A method able to process the input node by looking at the extension
+		:rtype: function
+		"""
+		name = node.name
+		for k in self.mappings:
+			if name.endswith(k):
+				return self.mappings[k]
+		for k in task_gen.mappings:
+			if name.endswith(k):
+				return task_gen.mappings[k]
+		raise Errors.WafError("File %r has no mapping in %r (did you forget to load a waf tool?)" % (node, task_gen.mappings.keys()))
+
+	def create_task(self, name, src=None, tgt=None):
+		"""
+		Wrapper for creating task objects easily
+
+		:param name: task class name
+		:type name: string
+		:param src: input nodes
+		:type src: list of :py:class:`waflib.Tools.Node.Node`
+		:param tgt: output nodes
+		:type tgt: list of :py:class:`waflib.Tools.Node.Node`
+		:return: A task object
+		:rtype: :py:class:`waflib.Task.TaskBase`
+		"""
+		task = Task.classes[name](env=self.env.derive(), generator=self)
+		if src:
+			task.set_inputs(src)
+		if tgt:
+			task.set_outputs(tgt)
+		self.tasks.append(task)
+		return task
+
+	def clone(self, env):
+		"""
+		Make a copy of a task generator. Once the copy is made, it is necessary to ensure that the
+		task generator does not create the same output files as the original, or the same files may
+		be compiled twice.
+
+		:param env: A configuration set
+		:type env: :py:class:`waflib.ConfigSet.ConfigSet`
+		:return: A copy
+		:rtype: :py:class:`waflib.TaskGen.task_gen`
+		"""
+		newobj = self.bld()
+		for x in self.__dict__:
+			if x in ['env', 'bld']:
+				continue
+			elif x in ['path', 'features']:
+				setattr(newobj, x, getattr(self, x))
+			else:
+				setattr(newobj, x, copy.copy(getattr(self, x)))
+
+		newobj.posted = False
+		if isinstance(env, str):
+			newobj.env = self.bld.all_envs[env].derive()
+		else:
+			newobj.env = env.derive()
+
+		return newobj
+
+def declare_chain(name='', rule=None, reentrant=None, color='BLUE',
+	ext_in=[], ext_out=[], before=[], after=[], decider=None, scan=None, install_path=None, shell=False):
+	"""
+	Create a new mapping and a task class for processing files by extension.
+	See Tools/flex.py for an example.
+
+	:param name: name for the task class
+	:type name: string
+	:param rule: function to execute or string to be compiled in a function
+	:type rule: string or function
+	:param reentrant: re-inject the output file in the process (done automatically, set to 0 to disable)
+	:type reentrant: int
+	:param color: color for the task output
+	:type color: string
+	:param ext_in: execute the task only after the files of such extensions are created
+	:type ext_in: list of string
+	:param ext_out: execute the task only before files of such extensions are processed
+	:type ext_out: list of string
+	:param before: execute instances of this task before classes of the given names
+	:type before: list of string
+	:param after: execute instances of this task after classes of the given names
+	:type after: list of string
+	:param decider: if present, use it to create the output nodes for the task
+	:type decider: function
+	:param scan: scanner function for the task
+	:type scan: function
+	:param install_path: installation path for the output nodes
+	:type install_path: string
+	"""
+	ext_in = Utils.to_list(ext_in)
+	ext_out = Utils.to_list(ext_out)
+	if not name:
+		name = rule
+	cls = Task.task_factory(name, rule, color=color, ext_in=ext_in, ext_out=ext_out, before=before, after=after, scan=scan, shell=shell)
+
+	def x_file(self, node):
+		ext = decider and decider(self, node) or cls.ext_out
+		if ext_in:
+			_ext_in = ext_in[0]
+
+		tsk = self.create_task(name, node)
+		cnt = 0
+
+		keys = self.mappings.keys() + self.__class__.mappings.keys()
+		for x in ext:
+			k = node.change_ext(x, ext_in=_ext_in)
+			tsk.outputs.append(k)
+
+			if reentrant != None:
+				if cnt < int(reentrant):
+					self.source.append(k)
+			else:
+				for y in keys: # ~ nfile * nextensions :-/
+					if k.name.endswith(y):
+						self.source.append(k)
+						break
+			cnt += 1
+
+		if install_path:
+			self.bld.install_files(install_path, tsk.outputs)
+		return tsk
+
+	for x in cls.ext_in:
+		task_gen.mappings[x] = x_file
+	return x_file
+
+def taskgen_method(func):
+	"""
+	Decorator: register a method as a task generator method.
+	The function must accept a task generator as first parameter::
+
+		from waflib.TaskGen import taskgen_method
+		@taskgen_method
+		def mymethod(self):
+			pass
+
+	:param func: task generator method to add
+	:type func: function
+	:rtype: function
+	"""
+	setattr(task_gen, func.__name__, func)
+	return func
+
+def feature(*k):
+	"""
+	Decorator: register a task generator method that will be executed when the
+	object attribute 'feature' contains the corresponding key(s)::
+
+		from waflib.Task import feature
+		@feature('myfeature')
+		def myfunction(self):
+			print('that is my feature!')
+		def build(bld):
+			bld(features='myfeature')
+
+	:param k: feature names
+	:type k: list of string
+	"""
+	def deco(func):
+		setattr(task_gen, func.__name__, func)
+		for name in k:
+			feats[name].update([func.__name__])
+		return func
+	return deco
+
+def before_method(*k):
+	"""
+	Decorator: register a task generator method which will be executed
+	before the functions of given name(s)::
+
+		from waflib.TaskGen import feature, before
+		@feature('myfeature')
+		@before_method('fun2')
+		def fun1(self):
+			print('feature 1!')
+		@feature('myfeature')
+		def fun2(self):
+			print('feature 2!')
+		def build(bld):
+			bld(features='myfeature')
+
+	:param k: method names
+	:type k: list of string
+	"""
+	def deco(func):
+		setattr(task_gen, func.__name__, func)
+		for fun_name in k:
+			if not func.__name__ in task_gen.prec[fun_name]:
+				task_gen.prec[fun_name].append(func.__name__)
+				#task_gen.prec[fun_name].sort()
+		return func
+	return deco
+before = before_method
+
+def after_method(*k):
+	"""
+	Decorator: register a task generator method which will be executed
+	after the functions of given name(s)::
+
+		from waflib.TaskGen import feature, after
+		@feature('myfeature')
+		@after_method('fun2')
+		def fun1(self):
+			print('feature 1!')
+		@feature('myfeature')
+		def fun2(self):
+			print('feature 2!')
+		def build(bld):
+			bld(features='myfeature')
+
+	:param k: method names
+	:type k: list of string
+	"""
+	def deco(func):
+		setattr(task_gen, func.__name__, func)
+		for fun_name in k:
+			if not fun_name in task_gen.prec[func.__name__]:
+				task_gen.prec[func.__name__].append(fun_name)
+				#task_gen.prec[func.__name__].sort()
+		return func
+	return deco
+after = after_method
+
+def extension(*k):
+	"""
+	Decorator: register a task generator method which will be invoked during
+	the processing of source files for the extension given::
+
+		from waflib import Task
+		class mytask(Task):
+			run_str = 'cp ${SRC} ${TGT}'
+		@extension('.moo')
+		def create_maa_file(self, node):
+			self.create_task('mytask', node, node.change_ext('.maa'))
+		def build(bld):
+			bld(source='foo.moo')
+	"""
+	def deco(func):
+		setattr(task_gen, func.__name__, func)
+		for x in k:
+			task_gen.mappings[x] = func
+		return func
+	return deco
+
+# ---------------------------------------------------------------
+# The following methods are task generator methods commonly used
+# they are almost examples, the rest of waf core does not depend on them
+
+ at taskgen_method
+def to_nodes(self, lst, path=None):
+	"""
+	Convert the input list into a list of nodes.
+	It is used by :py:func:`waflib.TaskGen.process_source` and :py:func:`waflib.TaskGen.process_rule`.
+	It is designed for source files, for folders, see :py:func:`waflib.Tools.ccroot.to_incnodes`:
+
+	:param lst: input list
+	:type lst: list of string and nodes
+	:param path: path from which to search the nodes (by default, :py:attr:`waflib.TaskGen.task_gen.path`)
+	:type path: :py:class:`waflib.Tools.Node.Node`
+	:rtype: list of :py:class:`waflib.Tools.Node.Node`
+	"""
+	tmp = []
+	path = path or self.path
+	find = path.find_resource
+
+	if isinstance(lst, self.path.__class__):
+		lst = [lst]
+
+	# either a list or a string, convert to a list of nodes
+	for x in Utils.to_list(lst):
+		if isinstance(x, str):
+			node = find(x)
+		else:
+			node = x
+		if not node:
+			raise Errors.WafError("source not found: %r in %r" % (x, self))
+		tmp.append(node)
+	return tmp
+
+ at feature('*')
+def process_source(self):
+	"""
+	Process each element in the attribute ``source`` by extension.
+
+	#. The *source* list is converted through :py:meth:`waflib.TaskGen.to_nodes` to a list of :py:class:`waflib.Node.Node` first.
+	#. File extensions are mapped to methods having the signature: ``def meth(self, node)`` by :py:meth:`waflib.TaskGen.extension`
+	#. The method is retrieved through :py:meth:`waflib.TaskGen.task_gen.get_hook`
+	#. When called, the methods may modify self.source to append more source to process
+	#. The mappings can map an extension or a filename (see the code below)
+	"""
+	self.source = self.to_nodes(getattr(self, 'source', []))
+	for node in self.source:
+		self.get_hook(node)(self, node)
+
+ at feature('*')
+ at before_method('process_source')
+def process_rule(self):
+	"""
+	Process the attribute ``rule``. When present, :py:meth:`waflib.TaskGen.process_source` is disabled::
+
+		def build(bld):
+			bld(rule='cp ${SRC} ${TGT}', source='wscript', target='bar.txt')
+	"""
+	if not getattr(self, 'rule', None):
+		return
+
+	# create the task class
+	name = str(getattr(self, 'name', None) or self.target or self.rule)
+	cls = Task.task_factory(name, self.rule,
+		getattr(self, 'vars', []),
+		shell=getattr(self, 'shell', True), color=getattr(self, 'color', 'BLUE'))
+
+	# now create one instance
+	tsk = self.create_task(name)
+
+	if getattr(self, 'target', None):
+		if isinstance(self.target, str):
+			self.target = self.target.split()
+		if not isinstance(self.target, list):
+			self.target = [self.target]
+		for x in self.target:
+			if isinstance(x, str):
+				tsk.outputs.append(self.path.find_or_declare(x))
+			else:
+				x.parent.mkdir() # if a node was given, create the required folders
+				tsk.outputs.append(x)
+		if getattr(self, 'install_path', None):
+			# from waf 1.5
+			# although convenient, it does not 1. allow to name the target file and 2. symlinks
+			# TODO remove in waf 1.7
+			self.bld.install_files(self.install_path, tsk.outputs)
+
+	if getattr(self, 'source', None):
+		tsk.inputs = self.to_nodes(self.source)
+		# bypass the execution of process_source by setting the source to an empty list
+		self.source = []
+
+	if getattr(self, 'scan', None):
+		cls.scan = self.scan
+	elif getattr(self, 'deps', None):
+		def scan(self):
+			nodes = []
+			for x in self.generator.to_list(self.generator.deps):
+				node = self.generator.path.find_resource(x)
+				if not node:
+					self.generator.bld.fatal('Could not find %r (was it declared?)' % x)
+				nodes.append(node)
+			return [nodes, []]
+		cls.scan = scan
+
+	if getattr(self, 'cwd', None):
+		tsk.cwd = self.cwd
+
+	# TODO remove on_results in waf 1.7
+	if getattr(self, 'update_outputs', None) or getattr(self, 'on_results', None):
+		Task.update_outputs(cls)
+
+	if getattr(self, 'always', None):
+		Task.always_run(cls)
+
+	for x in ['after', 'before', 'ext_in', 'ext_out']:
+		setattr(cls, x, getattr(self, x, []))
+
+ at feature('seq')
+def sequence_order(self):
+	"""
+	Add a strict sequential constraint between the tasks generated by task generators.
+	It works because task generators are posted in order.
+	It will not post objects which belong to other folders.
+
+	Example::
+
+		bld(features='javac seq')
+		bld(features='jar seq')
+
+	To start a new sequence, set the attribute seq_start, for example::
+
+		obj = bld(features='seq')
+		obj.seq_start = True
+
+	Note that the method is executed in last position. This is more an
+	example than a widely-used solution.
+	"""
+	if self.meths and self.meths[-1] != 'sequence_order':
+		self.meths.append('sequence_order')
+		return
+
+	if getattr(self, 'seq_start', None):
+		return
+
+	# all the tasks previously declared must be run before these
+	if getattr(self.bld, 'prev', None):
+		self.bld.prev.post()
+		for x in self.bld.prev.tasks:
+			for y in self.tasks:
+				y.set_run_after(x)
+
+	self.bld.prev = self
+
+
+re_m4 = re.compile('@(\w+)@', re.M)
+
+class subst_pc(Task.Task):
+	"""
+	Create *.pc* files from *.pc.in*. The task is executed whenever an input variable used
+	in the substitution changes.
+	"""
+
+	def run(self):
+		"Substitutes variables in a .in file"
+
+		code = self.inputs[0].read()
+
+		# replace all % by %% to prevent errors by % signs
+		code = code.replace('%', '%%')
+
+		# extract the vars foo into lst and replace @foo@ by %(foo)s
+		lst = []
+		def repl(match):
+			g = match.group
+			if g(1):
+				lst.append(g(1))
+				return "%%(%s)s" % g(1)
+			return ''
+		code = re_m4.sub(repl, code)
+
+		try:
+			d = self.generator.dct
+		except AttributeError:
+			d = {}
+			for x in lst:
+				tmp = getattr(self.generator, x, '') or self.env.get_flat(x) or self.env.get_flat(x.upper())
+				d[x] = str(tmp)
+
+		self.outputs[0].write(code % d)
+		self.generator.bld.raw_deps[self.uid()] = self.dep_vars = lst
+
+		# make sure the signature is updated
+		try: delattr(self, 'cache_sig')
+		except AttributeError: pass
+
+	def sig_vars(self):
+		"""
+		Compute a hash (signature) of the variables used in the substitution
+		"""
+		bld = self.generator.bld
+		env = self.env
+		upd = self.m.update
+
+		# raw_deps: persistent custom values returned by the scanner
+		vars = self.generator.bld.raw_deps.get(self.uid(), [])
+
+		# hash both env vars and task generator attributes
+		act_sig = bld.hash_env_vars(env, vars)
+		upd(act_sig)
+
+		lst = [getattr(self.generator, x, '') for x in vars]
+		upd(Utils.h_list(lst))
+
+		return self.m.digest()
+
+ at extension('.pc.in')
+def add_pcfile(self, node):
+	"""
+	Process *.pc.in* files to *.pc*. Install the results to ``${PREFIX}/lib/pkgconfig/``
+
+		def build(bld):
+			bld(source='foo.pc.in', install_path='${LIBDIR}/pkgconfig/')
+	"""
+	tsk = self.create_task('subst_pc', node, node.change_ext('.pc', '.pc.in'))
+	self.bld.install_files(getattr(self, 'install_path', '${LIBDIR}/pkgconfig/'), tsk.outputs)
+
+class subst(subst_pc):
+	pass
+
+ at feature('subst')
+ at before_method('process_source', 'process_rule')
+def process_subst(self):
+	"""
+	Define a transformation that substitutes the contents of *source* files to *target* files::
+
+		def build(bld):
+			bld(
+				features='subst',
+				source='foo.c.in',
+				target='foo.c',
+				install_path='${LIBDIR}/pkgconfig',
+				VAR = 'val'
+			)
+
+	The input files are supposed to contain macros of the form *@VAR@*, where *VAR* is an argument
+	of the task generator object.
+
+	This method overrides the processing by :py:meth:`waflib.TaskGen.process_source`.
+	"""
+	src = self.to_nodes(getattr(self, 'source', []))
+	tgt = getattr(self, 'target', [])
+	if isinstance(tgt, self.path.__class__):
+		tgt = [tgt]
+	tgt = [isinstance(x, self.path.__class__) and x or self.path.find_or_declare(x) for x in Utils.to_list(tgt)]
+
+	if len(src) != len(tgt):
+		raise Errors.WafError('invalid source or target for %r' % self)
+
+	for x, y in zip(src, tgt):
+		if not (x and y):
+			raise Errors.WafError('invalid source or target for %r' % self)
+		tsk = self.create_task('subst', x, y)
+		for a in ('after', 'before', 'ext_in', 'ext_out'):
+			val = getattr(self, a, None)
+			if val:
+				setattr(tsk, a, val)
+
+	inst_to = getattr(self, 'install_path', None)
+	if inst_to:
+		self.bld.install_files(inst_to, tgt, chmod=getattr(self, 'chmod', Utils.O644))
+
+	self.source = []
+
diff --git a/xpdeint/waf/waflib/TaskGen.pyc b/xpdeint/waf/waflib/TaskGen.pyc
new file mode 100644
index 0000000..77ff1f7
Binary files /dev/null and b/xpdeint/waf/waflib/TaskGen.pyc differ
diff --git a/xpdeint/waf/waflib/Tools/__init__.py b/xpdeint/waf/waflib/Tools/__init__.py
new file mode 100644
index 0000000..c8a3c34
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/__init__.py
@@ -0,0 +1,3 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005-2010 (ita)
diff --git a/xpdeint/waf/waflib/Tools/__init__.pyc b/xpdeint/waf/waflib/Tools/__init__.pyc
new file mode 100644
index 0000000..ad8f809
Binary files /dev/null and b/xpdeint/waf/waflib/Tools/__init__.pyc differ
diff --git a/xpdeint/waf/waflib/Tools/ar.py b/xpdeint/waf/waflib/Tools/ar.py
new file mode 100644
index 0000000..bf488e2
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/ar.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+# Ralf Habacker, 2006 (rh)
+
+"""
+The **ar** program creates static libraries. This tool is almost always loaded
+from others (C, C++, D, etc) for static library support.
+"""
+
+from waflib.Configure import conf
+
+ at conf
+def find_ar(conf):
+	"""Configuration helper used by C/C++ tools to enable the support for static libraries"""
+	conf.load('ar')
+
+def configure(conf):
+	"""Find the ar program and set the default flags in ``conf.env.ARFLAGS``"""
+	conf.find_program('ar', var='AR')
+	conf.env.ARFLAGS = 'rcs'
+
diff --git a/xpdeint/waf/waflib/Tools/asm.py b/xpdeint/waf/waflib/Tools/asm.py
new file mode 100644
index 0000000..5b5c43d
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/asm.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2008-2010 (ita)
+
+"""
+Assembly support, used by tools such as gas and nasm
+
+To declare targets using assembly::
+
+	def configure(conf):
+		conf.load('gcc gas')
+
+	def build(bld):
+		bld(
+			features='c cstlib asm',
+			source = 'test.S',
+			target = 'asmtest')
+
+		bld(
+			features='asm asmprogram',
+			source = 'test.S',
+			target = 'asmtest')
+
+Support for pure asm programs and libraries should also work::
+
+	def configure(conf):
+		conf.load('nasm')
+		conf.find_program('ld', 'ASLINK')
+
+	def build(bld):
+		bld(
+			features='asm asmprogram',
+			source = 'test.S',
+			target = 'asmtest')
+"""
+
+import os, sys
+from waflib import Task, Utils
+import waflib.Task
+from waflib.Tools.ccroot import link_task, stlink_task
+from waflib.TaskGen import extension, feature
+
+class asm(Task.Task):
+	"""
+	Compile asm files by gas/nasm/yasm/...
+	"""
+	color = 'BLUE'
+	run_str = '${AS} ${ASFLAGS} ${CPPPATH_ST:INCPATHS} ${AS_SRC_F}${SRC} ${AS_TGT_F}${TGT}'
+
+ at extension('.s', '.S', '.asm', '.ASM', '.spp', '.SPP')
+def asm_hook(self, node):
+	"""
+	Bind the asm extension to the asm task
+
+	:param node: input file
+	:type node: :py:class:`waflib.Node.Node`
+	"""
+	return self.create_compiled_task('asm', node)
+
+class asmprogram(link_task):
+	"Link object files into a c program"
+	run_str = '${ASLINK} ${ASLINKFLAGS} ${ASLNK_TGT_F}${TGT} ${ASLNK_SRC_F}${SRC}'
+	ext_out = ['.bin']
+	inst_to = '${BINDIR}'
+	chmod   = Utils.O755
+
+class asmshlib(asmprogram):
+	"Link object files into a c shared library"
+	inst_to = '${LIBDIR}'
+
+class asmstlib(stlink_task):
+	"Link object files into a c static library"
+	pass # do not remove
+
diff --git a/xpdeint/waf/waflib/Tools/bison.py b/xpdeint/waf/waflib/Tools/bison.py
new file mode 100644
index 0000000..9b90317
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/bison.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# John O'Meara, 2006
+# Thomas Nagy 2009-2010 (ita)
+
+"""
+The **bison** program is a code generator which creates C or C++ files.
+The generated files are compiled into object files.
+"""
+
+from waflib import Task
+from waflib.TaskGen import extension
+
+class bison(Task.Task):
+	"""Compile bison files"""
+	color   = 'BLUE'
+	run_str = '${BISON} ${BISONFLAGS} ${SRC[0].abspath()} -o ${TGT[0].name}'
+	ext_out = ['.h'] # just to make sure
+
+ at extension('.y', '.yc', '.yy')
+def big_bison(self, node):
+	"""
+	Create a bison task, which must be executed from the directory of the output file.
+	"""
+	has_h = '-d' in self.env['BISONFLAGS']
+
+	outs = []
+	if node.name.endswith('.yc'):
+		outs.append(node.change_ext('.tab.cc'))
+		if has_h:
+			outs.append(node.change_ext('.tab.hh'))
+	else:
+		outs.append(node.change_ext('.tab.c'))
+		if has_h:
+			outs.append(node.change_ext('.tab.h'))
+
+	tsk = self.create_task('bison', node, outs)
+	tsk.cwd = node.parent.get_bld().abspath()
+
+	# and the c/cxx file must be compiled too
+	self.source.append(outs[0])
+
+def configure(conf):
+	"""
+	Detect the *bison* program
+	"""
+	conf.find_program('bison', var='BISON')
+	conf.env.BISONFLAGS = ['-d']
+
diff --git a/xpdeint/waf/waflib/Tools/c.py b/xpdeint/waf/waflib/Tools/c.py
new file mode 100644
index 0000000..a475896
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/c.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+
+"Base for c programs/libraries"
+
+from waflib import TaskGen, Task, Utils
+from waflib.Tools import c_preproc
+from waflib.Tools.ccroot import link_task, stlink_task
+
+ at TaskGen.extension('.c')
+def c_hook(self, node):
+	"Bind the c file extension to the creation of a :py:class:`waflib.Tools.c.c` instance"
+	return self.create_compiled_task('c', node)
+
+class c(Task.Task):
+	"Compile C files into object files"
+	run_str = '${CC} ${ARCH_ST:ARCH} ${CFLAGS} ${CPPFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CC_SRC_F}${SRC} ${CC_TGT_F}${TGT}'
+	vars    = ['CCDEPS'] # unused variable to depend on, just in case
+	ext_in  = ['.h'] # set the build order easily by using ext_out=['.h']
+	scan    = c_preproc.scan
+
+Task.classes['cc'] = cc = c # compat, remove in waf 1.7
+
+class cprogram(link_task):
+	"Link object files into a c program"
+	run_str = '${LINK_CC} ${LINKFLAGS} ${CCLNK_SRC_F}${SRC} ${CCLNK_TGT_F}${TGT[0].abspath()} ${RPATH_ST:RPATH} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${FRAMEWORK_ST:FRAMEWORK} ${ARCH_ST:ARCH} ${STLIB_MARKER} ${STLIBPATH_ST:STLIBPATH} ${STLIB_ST:STLIB} ${SHLIB_MARKER} ${LIBPATH_ST:LIBPATH} ${LIB_ST:LIB}'
+	ext_out = ['.bin']
+	vars    = ['LINKDEPS']
+	inst_to = '${BINDIR}'
+	chmod   = Utils.O755
+
+class cshlib(cprogram):
+	"Link object files into a c shared library"
+	inst_to = '${LIBDIR}'
+
+class cstlib(stlink_task):
+	"Link object files into a c static library"
+	pass # do not remove
+
diff --git a/xpdeint/waf/waflib/Tools/c_aliases.py b/xpdeint/waf/waflib/Tools/c_aliases.py
new file mode 100644
index 0000000..0e4059c
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/c_aliases.py
@@ -0,0 +1,128 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005-2010 (ita)
+
+"base for all c/c++ programs and libraries"
+
+import os, sys, re
+from waflib import Utils, Build
+from waflib.Configure import conf
+
+def get_extensions(lst):
+	"""
+	:param lst: files to process
+	:list lst: list of string or :py:class:`waflib.Node.Node`
+	:return: list of file extensions
+	:rtype: list of string
+	"""
+	ret = []
+	for x in Utils.to_list(lst):
+		try:
+			if not isinstance(x, str):
+				x = x.name
+			ret.append(x[x.rfind('.') + 1:])
+		except:
+			pass
+	return ret
+
+def sniff_features(**kw):
+	"""
+	Look at the source files and return the features for a task generator (mainly cc and cxx)::
+
+		snif_features(source=['foo.c', 'foo.cxx'], type='shlib')
+		# returns  ['cxx', 'c', 'cxxshlib', 'cshlib']
+
+	:param source: source files to process
+	:type source: list of string or :py:class:`waflib.Node.Node`
+	:param type: object type in *program*, *shlib* or *stlib*
+	:type type: string
+	:return: the list of features for a task generator processing the source files
+	:rtype: list of string
+	"""
+	exts = get_extensions(kw['source'])
+	type = kw['_type']
+	feats = []
+
+	# watch the order, cxx will have the precedence
+	if 'cxx' in exts or 'cpp' in exts or 'c++' in exts or 'cc' in exts or 'C' in exts:
+		feats.append('cxx')
+
+	if 'c' in exts or 'vala' in exts:
+		feats.append('c')
+
+	if 'd' in exts:
+		feats.append('d')
+
+	if 'java' in exts:
+		feats.append('java')
+
+	if 'java' in exts:
+		return 'java'
+
+	if type in ['program', 'shlib', 'stlib']:
+		for x in feats:
+			if x in ['cxx', 'd', 'c']:
+				feats.append(x + type)
+
+	return feats
+
+def set_features(kw, _type):
+	kw['_type'] = _type
+	kw['features'] = Utils.to_list(kw.get('features', [])) + Utils.to_list(sniff_features(**kw))
+
+ at conf
+def program(bld, *k, **kw):
+	"""
+	Alias for creating programs by looking at the file extensions::
+
+		def build(bld):
+			bld.program(source='foo.c', target='app')
+			# equivalent to:
+			# bld(features='c cprogram', source='foo.c', target='app')
+
+	"""
+	set_features(kw, 'program')
+	return bld(*k, **kw)
+
+ at conf
+def shlib(bld, *k, **kw):
+	"""
+	Alias for creating shared libraries by looking at the file extensions::
+
+		def build(bld):
+			bld.shlib(source='foo.c', target='app')
+			# equivalent to:
+			# bld(features='c cshlib', source='foo.c', target='app')
+
+	"""
+	set_features(kw, 'shlib')
+	return bld(*k, **kw)
+
+ at conf
+def stlib(bld, *k, **kw):
+	"""
+	Alias for creating static libraries by looking at the file extensions::
+
+		def build(bld):
+			bld.stlib(source='foo.cpp', target='app')
+			# equivalent to:
+			# bld(features='cxx cxxstlib', source='foo.cpp', target='app')
+
+	"""
+	set_features(kw, 'stlib')
+	return bld(*k, **kw)
+
+ at conf
+def objects(bld, *k, **kw):
+	"""
+	Alias for creating object files by looking at the file extensions::
+
+		def build(bld):
+			bld.objects(source='foo.c', target='app')
+			# equivalent to:
+			# bld(features='c', source='foo.c', target='app')
+
+	"""
+	set_features(kw, 'objects')
+	return bld(*k, **kw)
+
diff --git a/xpdeint/waf/waflib/Tools/c_config.py b/xpdeint/waf/waflib/Tools/c_config.py
new file mode 100755
index 0000000..982a62f
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/c_config.py
@@ -0,0 +1,1201 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005-2010 (ita)
+
+"""
+C/C++/D configuration helpers
+"""
+
+import os, imp, sys, re, shlex, shutil
+from waflib import Build, Utils, Configure, Task, Options, Logs, TaskGen, Errors, ConfigSet, Runner
+from waflib.TaskGen import before_method, after_method, feature
+from waflib.Configure import conf
+
+WAF_CONFIG_H   = 'config.h'
+"""default name for the config.h file"""
+
+DEFKEYS = 'define_key'
+INCKEYS = 'include_key'
+
+cfg_ver = {
+	'atleast-version': '>=',
+	'exact-version': '==',
+	'max-version': '<=',
+}
+
+SNIP_FUNCTION = '''
+	int main() {
+	void *p;
+	p=(void*)(%s);
+	return 0;
+}
+'''
+"""Code template for checking for functions"""
+
+SNIP_TYPE = '''
+int main() {
+	if ((%(type_name)s *) 0) return 0;
+	if (sizeof (%(type_name)s)) return 0;
+}
+'''
+"""Code template for checking for types"""
+
+SNIP_CLASS = '''
+int main() {
+	if (
+}
+'''
+
+SNIP_EMPTY_PROGRAM = '''
+int main() {
+	return 0;
+}
+'''
+
+SNIP_FIELD = '''
+int main() {
+	char *off;
+	off = (char*) &((%(type_name)s*)0)->%(field_name)s;
+	return (size_t) off < sizeof(%(type_name)s);
+}
+'''
+
+MACRO_TO_DESTOS = {
+'__linux__'                                      : 'linux',
+'__GNU__'                                        : 'gnu',
+'__FreeBSD__'                                    : 'freebsd',
+'__NetBSD__'                                     : 'netbsd',
+'__OpenBSD__'                                    : 'openbsd',
+'__sun'                                          : 'sunos',
+'__hpux'                                         : 'hpux',
+'__sgi'                                          : 'irix',
+'_AIX'                                           : 'aix',
+'__CYGWIN__'                                     : 'cygwin',
+'__MSYS__'                                       : 'msys',
+'_UWIN'                                          : 'uwin',
+'_WIN64'                                         : 'win32',
+'_WIN32'                                         : 'win32',
+'__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__'  : 'darwin',
+'__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' : 'darwin', #iphone
+'__QNX__'                                        : 'qnx'
+}
+
+MACRO_TO_DEST_CPU = {
+'__x86_64__'  : 'x86_64',
+'__i386__'    : 'x86',
+'__ia64__'    : 'ia',
+'__mips__'    : 'mips',
+'__sparc__'   : 'sparc',
+'__alpha__'   : 'alpha',
+'__arm__'     : 'arm',
+'__hppa__'    : 'hppa',
+'__powerpc__' : 'powerpc',
+}
+
+ at conf
+def parse_flags(self, line, uselib, env=None, force_static=False):
+	"""
+	Parse the flags from the input lines, and add them to the relevant use variables::
+
+		def configure(conf):
+			conf.parse_flags('-O3', uselib_store='FOO')
+			# conf.env.CXXFLAGS_FOO = ['-O3']
+			# conf.env.CFLAGS_FOO = ['-O3']
+
+	:param line: flags
+	:type line: string
+	:param uselib: where to add the flags
+	:type uselib: string
+	:param env: config set or conf.env by default
+	:type env: :py:class:`waflib.ConfigSet.ConfigSet`
+	"""
+
+	assert(isinstance(line, str))
+
+	env = env or self.env
+
+	# append_unique is not always possible
+	# for example, apple flags may require both -arch i386 and -arch ppc
+
+	app = env.append_value
+	appu = env.append_unique
+	#lst = shlex.split(line)
+	# issue #811
+	lex = shlex.shlex(line, posix=False)
+	lex.whitespace_split = True
+	lex.commenters = ''
+	lst = list(lex)
+
+	while lst:
+		x = lst.pop(0)
+		st = x[:2]
+		ot = x[2:]
+
+		if st == '-I' or st == '/I':
+			if not ot: ot = lst.pop(0)
+			appu('INCLUDES_' + uselib, [ot])
+		elif st == '-include':
+			tmp = [x, lst.pop(0)]
+			app('CFLAGS', tmp)
+			app('CXXFLAGS', tmp)
+		elif st == '-D' or (self.env.CXX_NAME == 'msvc' and st == '/D'): # not perfect but..
+			if not ot: ot = lst.pop(0)
+			app('DEFINES_' + uselib, [ot])
+		elif st == '-l':
+			if not ot: ot = lst.pop(0)
+			prefix = force_static and 'STLIB_' or 'LIB_'
+			appu(prefix + uselib, [ot])
+		elif st == '-L':
+			if not ot: ot = lst.pop(0)
+			appu('LIBPATH_' + uselib, [ot])
+		elif x == '-pthread' or x.startswith('+') or x.startswith('-std'):
+			app('CFLAGS_' + uselib, [x])
+			app('CXXFLAGS_' + uselib, [x])
+			app('LINKFLAGS_' + uselib, [x])
+		elif x == '-framework':
+			appu('FRAMEWORK_' + uselib, [lst.pop(0)])
+		elif x.startswith('-F'):
+			appu('FRAMEWORKPATH_' + uselib, [x[2:]])
+		elif x.startswith('-Wl'):
+			app('LINKFLAGS_' + uselib, [x])
+		elif x.startswith('-m') or x.startswith('-f') or x.startswith('-dynamic'):
+			app('CFLAGS_' + uselib, [x])
+			app('CXXFLAGS_' + uselib, [x])
+		elif x.startswith('-bundle'):
+			app('LINKFLAGS_' + uselib, [x])
+		elif x.startswith('-undefined'):
+			arg = lst.pop(0)
+			app('LINKFLAGS_' + uselib, [x, arg])
+		elif x.startswith('-arch') or x.startswith('-isysroot'):
+			tmp = [x, lst.pop(0)]
+			app('CFLAGS_' + uselib, tmp)
+			app('CXXFLAGS_' + uselib, tmp)
+			app('LINKFLAGS_' + uselib, tmp)
+		elif x.endswith('.a') or x.endswith('.so') or x.endswith('.dylib'):
+			appu('LINKFLAGS_' + uselib, [x]) # not cool, #762
+
+ at conf
+def ret_msg(self, f, kw):
+	if isinstance(f, str):
+		return f
+	return f(kw)
+
+ at conf
+def validate_cfg(self, kw):
+	"""
+	Search for the program *pkg-config* if missing, and validate the parameters to pass to
+	:py:func:`waflib.Tools.c_config.exec_cfg`.
+
+	:param path: the **-config program to use** (default is *pkg-config*)
+	:type path: list of string
+	:param msg: message to display to describe the test executed
+	:type msg: string
+	:param okmsg: message to display when the test is successful
+	:type okmsg: string
+	:param errmsg: message to display in case of error
+	:type errmsg: string
+	"""
+	if not 'path' in kw:
+		if not self.env.PKGCONFIG:
+			self.find_program('pkg-config', var='PKGCONFIG')
+		kw['path'] = self.env.PKGCONFIG
+
+	# pkg-config version
+	if 'atleast_pkgconfig_version' in kw:
+		if not 'msg' in kw:
+			kw['msg'] = 'Checking for pkg-config version >= %r' % kw['atleast_pkgconfig_version']
+		return
+
+	if not 'okmsg' in kw:
+		kw['okmsg'] = 'yes'
+	if not 'errmsg' in kw:
+		kw['errmsg'] = 'not found'
+
+	if 'modversion' in kw:
+		if not 'msg' in kw:
+			kw['msg'] = 'Checking for %r version' % kw['modversion']
+		return
+
+	# checking for the version of a module, for the moment, one thing at a time
+	for x in cfg_ver.keys():
+		y = x.replace('-', '_')
+		if y in kw:
+			if not 'package' in kw:
+				raise ValueError('%s requires a package' % x)
+
+			if not 'msg' in kw:
+				kw['msg'] = 'Checking for %r %s %s' % (kw['package'], cfg_ver[x], kw[y])
+			return
+
+	if not 'msg' in kw:
+		kw['msg'] = 'Checking for %r' % (kw['package'] or kw['path'])
+
+ at conf
+def exec_cfg(self, kw):
+	"""
+	Execute the program *pkg-config*:
+
+	* if atleast_pkgconfig_version is given, check that pkg-config has the version n and return
+	* if modversion is given, then return the module version
+	* else, execute the *-config* program with the *args* and *variables* given, and set the flags on the *conf.env.FLAGS_name* variable
+
+	:param atleast_pkgconfig_version: minimum pkg-config version to use (disable other tests)
+	:type atleast_pkgconfig_version: string
+	:param package: package name, for example *gtk+-2.0*
+	:type package: string
+	:param uselib_store: if the test is successful, define HAVE\_*name*. It is also used to define *conf.env.FLAGS_name* variables.
+	:type uselib_store: string
+	:param modversion: if provided, return the version of the given module and define *name*\_VERSION
+	:type modversion: string
+	:param args: arguments to give to *package* when retrieving flags
+	:type args: list of string
+	:param variables: return the values of particular variables
+	:type variables: list of string
+	:param define_variable: additional variables to define (also in conf.env.PKG_CONFIG_DEFINES)
+	:type define_variable: dict(string: string)
+	"""
+
+	# pkg-config version
+	if 'atleast_pkgconfig_version' in kw:
+		cmd = [kw['path'], '--atleast-pkgconfig-version=%s' % kw['atleast_pkgconfig_version']]
+		self.cmd_and_log(cmd)
+		if not 'okmsg' in kw:
+			kw['okmsg'] = 'yes'
+		return
+
+	# checking for the version of a module
+	for x in cfg_ver:
+		y = x.replace('-', '_')
+		if y in kw:
+			self.cmd_and_log([kw['path'], '--%s=%s' % (x, kw[y]), kw['package']])
+			if not 'okmsg' in kw:
+				kw['okmsg'] = 'yes'
+			self.define(self.have_define(kw.get('uselib_store', kw['package'])), 1, 0)
+			break
+
+	# retrieving the version of a module
+	if 'modversion' in kw:
+		version = self.cmd_and_log([kw['path'], '--modversion', kw['modversion']]).strip()
+		self.define('%s_VERSION' % Utils.quote_define_name(kw.get('uselib_store', kw['modversion'])), version)
+		return version
+
+	lst = [kw['path']]
+
+	defi = kw.get('define_variable', None)
+	if not defi:
+		defi = self.env.PKG_CONFIG_DEFINES or {}
+	for key, val in defi.items():
+		lst.append('--define-variable=%s=%s' % (key, val))
+
+	if kw['package']:
+		lst.extend(Utils.to_list(kw['package']))
+
+	# retrieving variables of a module
+	if 'variables' in kw:
+		env = kw.get('env', self.env)
+		uselib = kw.get('uselib_store', kw['package'].upper())
+		vars = Utils.to_list(kw['variables'])
+		for v in vars:
+			val = self.cmd_and_log(lst + ['--variable=' + v]).strip()
+			var = '%s_%s' % (uselib, v)
+			env[var] = val
+		if not 'okmsg' in kw:
+			kw['okmsg'] = 'yes'
+		return
+
+	static = False
+	if 'args' in kw:
+		args = Utils.to_list(kw['args'])
+		if '--static' in args or '--static-libs' in args:
+			static = True
+		lst += args
+	# so we assume the command-line will output flags to be parsed afterwards
+	ret = self.cmd_and_log(lst)
+	if not 'okmsg' in kw:
+		kw['okmsg'] = 'yes'
+
+	self.define(self.have_define(kw.get('uselib_store', kw['package'])), 1, 0)
+	self.parse_flags(ret, kw.get('uselib_store', kw['package'].upper()), kw.get('env', self.env), force_static=static)
+	return ret
+
+ at conf
+def check_cfg(self, *k, **kw):
+	"""
+	Check for configuration flags using a **-config**-like program (pkg-config, sdl-config, etc).
+	Encapsulate the calls to :py:func:`waflib.Tools.c_config.validate_cfg` and :py:func:`waflib.Tools.c_config.exec_cfg`
+
+	A few examples::
+
+		def configure(conf):
+			conf.load('compiler_c')
+			conf.check_cfg(package='glib-2.0', args='--libs --cflags')
+			conf.check_cfg(package='glib-2.0', uselib_store='GLIB', atleast_version='2.10.0',
+				args='--cflags --libs')
+			conf.check_cfg(package='pango')
+			conf.check_cfg(package='pango', uselib_store='MYPANGO', args=['--cflags', '--libs'])
+			conf.check_cfg(package='pango',
+				args=['pango >= 0.1.0', 'pango < 9.9.9', '--cflags', '--libs'],
+				msg="Checking for 'pango 0.1.0'")
+			conf.check_cfg(path='sdl-config', args='--cflags --libs', package='', uselib_store='SDL')
+			conf.check_cfg(path='mpicc', args='--showme:compile --showme:link',
+				package='', uselib_store='OPEN_MPI', mandatory=False)
+
+	"""
+	if k:
+		lst = k[0].split()
+		kw['package'] = lst[0]
+		kw['args'] = ' '.join(lst[1:])
+
+	self.validate_cfg(kw)
+	if 'msg' in kw:
+		self.start_msg(kw['msg'])
+	ret = None
+	try:
+		ret = self.exec_cfg(kw)
+	except self.errors.WafError as e:
+		if 'errmsg' in kw:
+			self.end_msg(kw['errmsg'], 'YELLOW')
+		if Logs.verbose > 1:
+			raise
+		else:
+			self.fatal('The configuration failed')
+	else:
+		kw['success'] = ret
+		if 'okmsg' in kw:
+			self.end_msg(self.ret_msg(kw['okmsg'], kw))
+
+	return ret
+
+ at conf
+def validate_c(self, kw):
+	"""
+	pre-check the parameters that will be given to run_c_code
+
+	:param env: an optional environment (modified -> provide a copy)
+	:type env: :py:class:`waflib.ConfigSet.ConfigSet`
+	:param compiler: c or cxx (tries to guess what is best)
+	:type compiler: string
+	:param type: cprogram, cshlib, cstlib - not required if *features are given directly*
+	:type type: binary to create
+	:param feature: desired features for the task generator that will execute the test, for example ``cxx cxxstlib``
+	:type feature: list of string
+	:param fragment: provide a piece of code for the test (default is to let the system create one)
+	:type fragment: string
+	:param uselib_store: define variables after the test is executed (IMPORTANT!)
+	:type uselib_store: string
+	:param use: parameters to use for building (just like the normal *use* keyword)
+	:type use: list of string
+	:param define_name: define to set when the check is over
+	:type define_name: string
+	:param execute: execute the resulting binary
+	:type execute: bool
+	:param define_ret: if execute is set to True, use the execution output in both the define and the return value
+	:type define_ret: bool
+	:param header_name: check for a particular header
+	:type header_name: string
+	:param auto_add_header_name: if header_name was set, add the headers in env.INCKEYS so the next tests will include these headers
+	:type auto_add_header_name: bool
+	"""
+
+	if not 'env' in kw:
+		kw['env'] = self.env.derive()
+	env = kw['env']
+
+	if not 'compiler' in kw and not 'features' in kw:
+		kw['compiler'] = 'c'
+		if env['CXX_NAME'] and Task.classes.get('cxx', None):
+			kw['compiler'] = 'cxx'
+			if not self.env['CXX']:
+				self.fatal('a c++ compiler is required')
+		else:
+			if not self.env['CC']:
+				self.fatal('a c compiler is required')
+
+	if not 'compile_mode' in kw:
+		kw['compile_mode'] = 'c'
+		if 'cxx' in Utils.to_list(kw.get('features',[])) or kw.get('compiler', '') == 'cxx':
+			kw['compile_mode'] = 'cxx'
+
+	if not 'type' in kw:
+		kw['type'] = 'cprogram'
+
+	if not 'features' in kw:
+		kw['features'] = [kw['compile_mode'], kw['type']] # "cprogram c"
+	else:
+		kw['features'] = Utils.to_list(kw['features'])
+
+	if not 'compile_filename' in kw:
+		kw['compile_filename'] = 'test.c' + ((kw['compile_mode'] == 'cxx') and 'pp' or '')
+
+
+	def to_header(dct):
+		if 'header_name' in dct:
+			dct = Utils.to_list(dct['header_name'])
+			return ''.join(['#include <%s>\n' % x for x in dct])
+		return ''
+
+	#OSX
+	if 'framework_name' in kw:
+		fwkname = kw['framework_name']
+		if not 'uselib_store' in kw:
+			kw['uselib_store'] = fwkname.upper()
+
+		if not kw.get('no_header', False):
+			if not 'header_name' in kw:
+				kw['header_name'] = []
+			fwk = '%s/%s.h' % (fwkname, fwkname)
+			if kw.get('remove_dot_h', None):
+				fwk = fwk[:-2]
+			kw['header_name'] = Utils.to_list(kw['header_name']) + [fwk]
+
+		kw['msg'] = 'Checking for framework %s' % fwkname
+		kw['framework'] = fwkname
+		#kw['frameworkpath'] = set it yourself
+
+	if 'function_name' in kw:
+		fu = kw['function_name']
+		if not 'msg' in kw:
+			kw['msg'] = 'Checking for function %s' % fu
+		kw['code'] = to_header(kw) + SNIP_FUNCTION % fu
+		if not 'uselib_store' in kw:
+			kw['uselib_store'] = fu.upper()
+		if not 'define_name' in kw:
+			kw['define_name'] = self.have_define(fu)
+
+	elif 'type_name' in kw:
+		tu = kw['type_name']
+		if not 'header_name' in kw:
+			kw['header_name'] = 'stdint.h'
+		if 'field_name' in kw:
+			field = kw['field_name']
+			kw['code'] = to_header(kw) + SNIP_FIELD % {'type_name' : tu, 'field_name' : field}
+			if not 'msg' in kw:
+				kw['msg'] = 'Checking for field %s in %s' % (field, tu)
+			if not 'define_name' in kw:
+				kw['define_name'] = self.have_define((tu + '_' + field).upper())
+		else:
+			kw['code'] = to_header(kw) + SNIP_TYPE % {'type_name' : tu}
+			if not 'msg' in kw:
+				kw['msg'] = 'Checking for type %s' % tu
+			if not 'define_name' in kw:
+				kw['define_name'] = self.have_define(tu.upper())
+
+	elif 'header_name' in kw:
+		if not 'msg' in kw:
+			kw['msg'] = 'Checking for header %s' % kw['header_name']
+
+		l = Utils.to_list(kw['header_name'])
+		assert len(l)>0, 'list of headers in header_name is empty'
+
+		kw['code'] = to_header(kw) + SNIP_EMPTY_PROGRAM
+
+		if not 'uselib_store' in kw:
+			kw['uselib_store'] = l[0].upper()
+
+		if not 'define_name' in kw:
+			kw['define_name'] = self.have_define(l[0])
+
+	if 'lib' in kw:
+		if not 'msg' in kw:
+			kw['msg'] = 'Checking for library %s' % kw['lib']
+		if not 'uselib_store' in kw:
+			kw['uselib_store'] = kw['lib'].upper()
+
+	if 'stlib' in kw:
+		if not 'msg' in kw:
+			kw['msg'] = 'Checking for static library %s' % kw['stlib']
+		if not 'uselib_store' in kw:
+			kw['uselib_store'] = kw['stlib'].upper()
+
+	if 'fragment' in kw:
+		# an additional code fragment may be provided to replace the predefined code
+		# in custom headers
+		kw['code'] = kw['fragment']
+		if not 'msg' in kw:
+			kw['msg'] = 'Checking for code snippet'
+		if not 'errmsg' in kw:
+			kw['errmsg'] = 'no'
+
+	for (flagsname,flagstype) in [('cxxflags','compiler'), ('cflags','compiler'), ('linkflags','linker')]:
+		if flagsname in kw:
+			if not 'msg' in kw:
+				kw['msg'] = 'Checking for %s flags %s' % (flagstype, kw[flagsname])
+			if not 'errmsg' in kw:
+				kw['errmsg'] = 'no'
+
+	if not 'execute' in kw:
+		kw['execute'] = False
+	if kw['execute']:
+		kw['features'].append('test_exec')
+
+	if not 'errmsg' in kw:
+		kw['errmsg'] = 'not found'
+
+	if not 'okmsg' in kw:
+		kw['okmsg'] = 'yes'
+
+	if not 'code' in kw:
+		kw['code'] = SNIP_EMPTY_PROGRAM
+
+	# if there are headers to append automatically to the next tests
+	if self.env[INCKEYS]:
+		kw['code'] = '\n'.join(['#include <%s>' % x for x in self.env[INCKEYS]]) + '\n' + kw['code']
+
+	if not kw.get('success'): kw['success'] = None
+
+	if 'define_name' in kw:
+		self.undefine(kw['define_name'])
+
+	assert 'msg' in kw, 'invalid parameters, read http://freehackers.org/~tnagy/wafbook/single.html#config_helpers_c'
+
+ at conf
+def post_check(self, *k, **kw):
+	"Set the variables after a test executed in :py:func:`waflib.Tools.c_config.check` was run successfully"
+
+	is_success = 0
+	if kw['execute']:
+		if kw['success'] is not None:
+			if kw.get('define_ret', False):
+				is_success = kw['success']
+			else:
+				is_success = (kw['success'] == 0)
+	else:
+		is_success = (kw['success'] == 0)
+
+	if 'define_name' in kw:
+		# TODO simplify?
+		if 'header_name' in kw or 'function_name' in kw or 'type_name' in kw or 'fragment' in kw:
+			nm = kw['define_name']
+			if kw['execute'] and kw.get('define_ret', None) and isinstance(is_success, str):
+				self.define(kw['define_name'], is_success, quote=kw.get('quote', 1))
+			else:
+				self.define_cond(kw['define_name'], is_success)
+		else:
+			self.define_cond(kw['define_name'], is_success)
+
+	if 'header_name' in kw:
+		if kw.get('auto_add_header_name', False):
+			self.env.append_value(INCKEYS, Utils.to_list(kw['header_name']))
+
+	if is_success and 'uselib_store' in kw:
+		from waflib.Tools import ccroot
+
+		# TODO see get_uselib_vars from ccroot.py
+		_vars = set([])
+		for x in kw['features']:
+			if x in ccroot.USELIB_VARS:
+				_vars |= ccroot.USELIB_VARS[x]
+
+		for k in _vars:
+			lk = k.lower()
+			if k == 'INCLUDES': lk = 'includes'
+			if k == 'DEFINES': lk = 'defines'
+			if lk in kw:
+				val = kw[lk]
+				# remove trailing slash
+				if isinstance(val, str):
+					val = val.rstrip(os.path.sep)
+				self.env.append_unique(k + '_' + kw['uselib_store'], val)
+	return is_success
+
+ at conf
+def check(self, *k, **kw):
+	"""
+	Perform a configuration test by calling :py:func:`waflib.Tools.c_config.run_c_code`.
+	For the complete list of parameters, see :py:func:`waflib.Tools.c_config.validate_c`.
+	To force a specific compiler, prefer the methods :py:func:`waflib.Tools.c_config.check_cxx` or :py:func:`waflib.Tools.c_config.check_cc`
+	"""
+	self.validate_c(kw)
+	self.start_msg(kw['msg'])
+	ret = None
+	try:
+		ret = self.run_c_code(*k, **kw)
+	except self.errors.ConfigurationError as e:
+		self.end_msg(kw['errmsg'], 'YELLOW')
+		if Logs.verbose > 1:
+			raise
+		else:
+			self.fatal('The configuration failed')
+	else:
+		kw['success'] = ret
+
+	ret = self.post_check(*k, **kw)
+	if not ret:
+		self.end_msg(kw['errmsg'], 'YELLOW')
+		self.fatal('The configuration failed %r kws: %r' % (ret, kw))
+	else:
+		self.end_msg(self.ret_msg(kw['okmsg'], kw))
+	return ret
+
+class test_exec(Task.Task):
+	"""
+	A task for executing a programs after they are built. See :py:func:`waflib.Tools.c_config.test_exec_fun`.
+	"""
+	color = 'PINK'
+	def run(self):
+		if getattr(self.generator, 'rpath', None):
+			if getattr(self.generator, 'define_ret', False):
+				self.generator.bld.retval = self.generator.bld.cmd_and_log([self.inputs[0].abspath()])
+			else:
+				self.generator.bld.retval = self.generator.bld.exec_command([self.inputs[0].abspath()])
+		else:
+			env = self.env.env or {}
+			env.update(dict(os.environ))
+			for var in ('LD_LIBRARY_PATH', 'DYLD_LIBRARY_PATH', 'PATH'):
+				env[var] = self.inputs[0].parent.abspath() + os.path.pathsep + env.get(var, '')
+			if getattr(self.generator, 'define_ret', False):
+				self.generator.bld.retval = self.generator.bld.cmd_and_log([self.inputs[0].abspath()], env=env)
+			else:
+				self.generator.bld.retval = self.generator.bld.exec_command([self.inputs[0].abspath()], env=env)
+		if self.generator.bld.logger:
+			self.generator.bld.logger.debug('test_exec: retval = %r' % self.generator.bld.retval)
+
+ at feature('test_exec')
+ at after_method('apply_link')
+def test_exec_fun(self):
+	"""
+	The feature **test_exec** is used to create a task that will to execute the binary
+	created (link task output) during the build. The exit status will be set
+	on the build context, so only one program may have the feature *test_exec*.
+	This is used by configuration tests::
+
+		def configure(conf):
+			conf.check(execute=True)
+	"""
+	self.create_task('test_exec', self.link_task.outputs[0])
+
+CACHE_RESULTS = 1
+COMPILE_ERRORS = 2
+
+ at conf
+def run_c_code(self, *k, **kw):
+	"""
+	Create a temporary build context to execute a build. A reference to that build
+	context is kept on self.test_bld for debugging purposes, and you should not rely
+	on it too much (read the note on the cache below).
+	The parameters given in the arguments to this function are passed as arguments for
+	a single task generator created in the build. Only three parameters are obligatory:
+
+	:param features: features to pass to a task generator created in the build
+	:type features: list of string
+	:param compile_filename: file to create for the compilation (default: *test.c*)
+	:type compile_filename: string
+	:param code: code to write in the filename to compile
+	:type code: string
+
+	Though this function returns *0* by default, the build may set an attribute named *retval* on the
+	build context object to return a particular value. See :py:func:`waflib.Tools.c_config.test_exec_fun` for example.
+
+	This function also provides a limited cache. To use it, provide the following option::
+
+		def options(opt):
+			opt.add_option('--confcache', dest='confcache', default=0,
+				action='count', help='Use a configuration cache')
+
+	And execute the configuration with the following command-line::
+
+		$ waf configure --confcache
+
+	"""
+
+	lst = [str(v) for (p, v) in kw.items() if p != 'env']
+	h = Utils.h_list(lst)
+	dir = self.bldnode.abspath() + os.sep + (not Utils.is_win32 and '.' or '') + 'conf_check_' + Utils.to_hex(h)
+
+	try:
+		os.makedirs(dir)
+	except:
+		pass
+
+	try:
+		os.stat(dir)
+	except:
+		self.fatal('cannot use the configuration test folder %r' % dir)
+
+	cachemode = getattr(Options.options, 'confcache', None)
+	if cachemode == CACHE_RESULTS:
+		try:
+			proj = ConfigSet.ConfigSet(os.path.join(dir, 'cache_run_c_code'))
+			ret = proj['cache_run_c_code']
+		except:
+			pass
+		else:
+			if isinstance(ret, str) and ret.startswith('Test does not build'):
+				self.fatal(ret)
+			return ret
+
+	bdir = os.path.join(dir, 'testbuild')
+
+	if not os.path.exists(bdir):
+		os.makedirs(bdir)
+
+	self.test_bld = bld = Build.BuildContext(top_dir=dir, out_dir=bdir)
+	bld.init_dirs()
+	bld.progress_bar = 0
+	bld.targets = '*'
+
+	if kw['compile_filename']:
+		node = bld.srcnode.make_node(kw['compile_filename'])
+		node.write(kw['code'])
+
+	bld.logger = self.logger
+	bld.all_envs.update(self.all_envs) # not really necessary
+	bld.env = kw['env']
+
+	o = bld(features=kw['features'], source=kw['compile_filename'], target='testprog')
+
+	for k, v in kw.items():
+		setattr(o, k, v)
+
+	self.to_log("==>\n%s\n<==" % kw['code'])
+
+	# compile the program
+	bld.targets = '*'
+
+	ret = -1
+	try:
+		try:
+			bld.compile()
+		except Errors.WafError:
+			ret = 'Test does not build: %s' % Utils.ex_stack()
+			self.fatal(ret)
+		else:
+			ret = getattr(bld, 'retval', 0)
+	finally:
+		# cache the results each time
+		proj = ConfigSet.ConfigSet()
+		proj['cache_run_c_code'] = ret
+		proj.store(os.path.join(dir, 'cache_run_c_code'))
+
+	return ret
+
+ at conf
+def check_cxx(self, *k, **kw):
+	"""
+	Same as :py:func:`waflib.Tools.c_config.check` but default to the *c++* programming language
+	"""
+	kw['compiler'] = 'cxx'
+	return self.check(*k, **kw)
+
+ at conf
+def check_cc(self, *k, **kw):
+	"""
+	Same as :py:func:`waflib.Tools.c_config.check` but default to the *c* programming language
+	"""
+	kw['compiler'] = 'c'
+	return self.check(*k, **kw)
+
+ at conf
+def define(self, key, val, quote=True):
+	"""
+	Store a single define and its state into conf.env.DEFINES
+
+	:param key: define name
+	:type key: string
+	:param val: value
+	:type val: int or string
+	:param quote: enclose strings in quotes (yes by default)
+	:type quote: bool
+	"""
+	assert key and isinstance(key, str)
+
+	if isinstance(val, int) or isinstance(val, float):
+		s = '%s=%s'
+	else:
+		s = quote and '%s="%s"' or '%s=%s'
+	app = s % (key, str(val))
+
+	ban = key + '='
+	lst = self.env['DEFINES']
+	for x in lst:
+		if x.startswith(ban):
+			lst[lst.index(x)] = app
+			break
+	else:
+		self.env.append_value('DEFINES', app)
+
+	self.env.append_unique(DEFKEYS, key)
+
+ at conf
+def undefine(self, key):
+	"""
+	Remove a define from conf.env.DEFINES
+
+	:param key: define name
+	:type key: string
+	"""
+	assert key and isinstance(key, str)
+
+	ban = key + '='
+	lst = [x for x in self.env['DEFINES'] if not x.startswith(ban)]
+	self.env['DEFINES'] = lst
+	self.env.append_unique(DEFKEYS, key)
+
+ at conf
+def define_cond(self, key, val):
+	"""
+	Conditionally define a name::
+
+		def configure(conf):
+			conf.define_cond('A', True)
+			# equivalent to:
+			# if val: conf.define('A', 1)
+			# else: conf.undefine('A')
+
+	:param key: define name
+	:type key: string
+	:param val: value
+	:type val: int or string
+	"""
+	assert key and isinstance(key, str)
+
+	if val:
+		self.define(key, 1)
+	else:
+		self.undefine(key)
+
+ at conf
+def is_defined(self, key):
+	"""
+	:param key: define name
+	:type key: string
+	:return: True if the define is set
+	:rtype: bool
+	"""
+	assert key and isinstance(key, str)
+
+	ban = key + '='
+	for x in self.env['DEFINES']:
+		if x.startswith(ban):
+			return True
+	return False
+
+ at conf
+def get_define(self, key):
+	"""
+	:param key: define name
+	:type key: string
+	:return: the value of a previously stored define or None if it is not set
+	"""
+	assert key and isinstance(key, str)
+
+	ban = key + '='
+	for x in self.env['DEFINES']:
+		if x.startswith(ban):
+			return x[len(ban):]
+	return None
+
+ at conf
+def have_define(self, key):
+	"""
+	:param key: define name
+	:type key: string
+	:return: the input key prefixed by *HAVE_* and substitute any invalid characters.
+	:rtype: string
+	"""
+	return self.__dict__.get('HAVE_PAT', 'HAVE_%s') % Utils.quote_define_name(key)
+
+ at conf
+def write_config_header(self, configfile='', guard='', top=False, env=None, defines=True, headers=False, remove=True):
+	"""
+	Write a configuration header containing defines and includes::
+
+		def configure(cnf):
+			cnf.define('A', 1)
+			cnf.write_config_header('config.h')
+
+	:param configfile: relative path to the file to create
+	:type configfile: string
+	:param env: config set to read the definitions from (default is conf.env)
+	:type env: :py:class:`waflib.ConfigSet.ConfigSet`
+	:param top: write the configuration header from the build directory (default is from the current path)
+	:type top: bool
+	:param defines: add the defines (yes by default)
+	:type defines: bool
+	:param headers: add #include in the file
+	:type headers: bool
+	:param remove: remove the defines after they are added (yes by default)
+	:type remove: bool
+	"""
+	if not configfile: configfile = WAF_CONFIG_H
+	waf_guard = guard or '_%s_WAF' % Utils.quote_define_name(configfile)
+
+	node = top and self.bldnode or self.path.get_bld()
+	node = node.make_node(configfile)
+	node.parent.mkdir()
+
+	lst = ['/* WARNING! All changes made to this file will be lost! */\n']
+	lst.append('#ifndef %s\n#define %s\n' % (waf_guard, waf_guard))
+	lst.append(self.get_config_header(defines, headers))
+	lst.append('\n#endif /* %s */\n' % waf_guard)
+
+	node.write('\n'.join(lst))
+
+	env = env or self.env
+
+	# config files are not removed on "waf clean"
+	env.append_unique(Build.CFG_FILES, [node.abspath()])
+
+	if remove:
+		for key in self.env[DEFKEYS]:
+			self.undefine(key)
+		self.env[DEFKEYS] = []
+
+ at conf
+def get_config_header(self, defines=True, headers=False):
+	"""
+	Create the contents of a ``config.h`` file from the defines and includes
+	set in conf.env.define_key / conf.env.include_key. No include guards are added.
+
+	:param defines: write the defines values
+	:type defines: bool
+	:param headers: write the headers
+	:type headers: bool
+	:return: the contents of a ``config.h`` file
+	:rtype: string
+	"""
+	lst = []
+	if headers:
+		for x in self.env[INCKEYS]:
+			lst.append('#include <%s>' % x)
+
+	if defines:
+		for x in self.env[DEFKEYS]:
+			if self.is_defined(x):
+				val = self.get_define(x)
+				lst.append('#define %s %s' % (x, val))
+			else:
+				lst.append('/* #undef %s */' % x)
+	return "\n".join(lst)
+
+ at conf
+def cc_add_flags(conf):
+	"""
+	Read the CFLAGS/CPPFLAGS from os.environ and add to conf.env.CFLAGS
+	"""
+	conf.add_os_flags('CPPFLAGS', 'CFLAGS')
+	conf.add_os_flags('CFLAGS')
+
+ at conf
+def cxx_add_flags(conf):
+	"""
+	Read the CXXFLAGS/CPPFLAGS and add to conf.env.CXXFLAGS
+	"""
+	conf.add_os_flags('CPPFLAGS', 'CXXFLAGS')
+	conf.add_os_flags('CXXFLAGS')
+
+ at conf
+def link_add_flags(conf):
+	"""
+	Read the LINKFLAGS/LDFLAGS and add to conf.env.LDFLAGS
+	"""
+	conf.add_os_flags('LINKFLAGS')
+	conf.add_os_flags('LDFLAGS', 'LINKFLAGS')
+
+ at conf
+def cc_load_tools(conf):
+	"""
+	Load the c tool
+	"""
+	if not conf.env.DEST_OS:
+		conf.env.DEST_OS = Utils.unversioned_sys_platform()
+	conf.load('c')
+
+ at conf
+def cxx_load_tools(conf):
+	"""
+	Load the cxx tool
+	"""
+	if not conf.env.DEST_OS:
+		conf.env.DEST_OS = Utils.unversioned_sys_platform()
+	conf.load('cxx')
+
+ at conf
+def get_cc_version(conf, cc, gcc=False, icc=False):
+	"""
+	Run the preprocessor to determine the compiler version
+
+	The variables CC_VERSION, DEST_OS, DEST_BINFMT and DEST_CPU will be set in *conf.env*
+	"""
+	cmd = cc + ['-dM', '-E', '-']
+	try:
+		p = Utils.subprocess.Popen(cmd, stdin=Utils.subprocess.PIPE, stdout=Utils.subprocess.PIPE, stderr=Utils.subprocess.PIPE)
+		p.stdin.write('\n'.encode())
+		out = p.communicate()[0]
+	except:
+		conf.fatal('could not determine the compiler version %r' % cmd)
+
+	if not isinstance(out, str):
+		out = out.decode(sys.stdout.encoding)
+
+	if gcc:
+		if out.find('__INTEL_COMPILER') >= 0:
+			conf.fatal('The intel compiler pretends to be gcc')
+		if out.find('__GNUC__') < 0:
+			conf.fatal('Could not determine the compiler type')
+
+	if icc and out.find('__INTEL_COMPILER') < 0:
+		conf.fatal('Not icc/icpc')
+
+	k = {}
+	if icc or gcc:
+		out = out.split('\n')
+		import shlex
+
+		for line in out:
+			lst = shlex.split(line)
+			if len(lst)>2:
+				key = lst[1]
+				val = lst[2]
+				k[key] = val
+
+		def isD(var):
+			return var in k
+
+		def isT(var):
+			return var in k and k[var] != '0'
+
+		# Some documentation is available at http://predef.sourceforge.net
+		# The names given to DEST_OS must match what Utils.unversioned_sys_platform() returns.
+		if not conf.env.DEST_OS:
+			conf.env.DEST_OS = ''
+		for i in MACRO_TO_DESTOS:
+			if isD(i):
+				conf.env.DEST_OS = MACRO_TO_DESTOS[i]
+				break
+		else:
+			if isD('__APPLE__') and isD('__MACH__'):
+				conf.env.DEST_OS = 'darwin'
+			elif isD('__unix__'): # unix must be tested last as it's a generic fallback
+				conf.env.DEST_OS = 'generic'
+
+		if isD('__ELF__'):
+			conf.env.DEST_BINFMT = 'elf'
+		elif isD('__WINNT__') or isD('__CYGWIN__'):
+			conf.env.DEST_BINFMT = 'pe'
+			conf.env.LIBDIR = conf.env['PREFIX'] + '/bin'
+		elif isD('__APPLE__'):
+			conf.env.DEST_BINFMT = 'mac-o'
+
+		if not conf.env.DEST_BINFMT:
+			# Infer the binary format from the os name.
+			conf.env.DEST_BINFMT = Utils.destos_to_binfmt(conf.env.DEST_OS)
+
+		for i in MACRO_TO_DEST_CPU:
+			if isD(i):
+				conf.env.DEST_CPU = MACRO_TO_DEST_CPU[i]
+				break
+
+		Logs.debug('ccroot: dest platform: ' + ' '.join([conf.env[x] or '?' for x in ('DEST_OS', 'DEST_BINFMT', 'DEST_CPU')]))
+		if icc:
+			ver = k['__INTEL_COMPILER']
+			conf.env['CC_VERSION'] = (ver[:-2], ver[-2], ver[-1])
+		else:
+			conf.env['CC_VERSION'] = (k['__GNUC__'], k['__GNUC_MINOR__'], k['__GNUC_PATCHLEVEL__'])
+	return k
+
+ at conf
+def get_xlc_version(conf, cc):
+	"""Get the compiler version"""
+
+	version_re = re.compile(r"IBM XL C/C\+\+.*, V(?P<major>\d*)\.(?P<minor>\d*)", re.I).search
+	cmd = cc + ['-qversion']
+
+	try:
+		out, err = conf.cmd_and_log(cmd, output=0)
+	except Errors.WafError:
+		conf.fatal('Could not find xlc %r' % cmd)
+	if out: match = version_re(out)
+	else: match = version_re(err)
+	if not match:
+		conf.fatal('Could not determine the XLC version.')
+	k = match.groupdict()
+	conf.env['CC_VERSION'] = (k['major'], k['minor'])
+
+# ============ the --as-needed flag should added during the configuration, not at runtime =========
+
+ at conf
+def add_as_needed(self):
+	"""
+	Add ``--as-needed`` to the *LINKFLAGS*
+	"""
+	if self.env.DEST_BINFMT == 'elf' and 'gcc' in (self.env.CXX_NAME, self.env.CC_NAME):
+		self.env.append_unique('LINKFLAGS', '--as-needed')
+
+# ============ parallel configuration
+
+class cfgtask(Task.TaskBase):
+	"""
+	A task that executes configuration tests
+	make sure that the checks write to conf.env in a thread-safe manner
+
+	for the moment it only executes conf.check
+	"""
+	def display(self):
+		return ''
+
+	def runnable_status(self):
+		return Task.RUN_ME
+
+	def run(self):
+		conf = self.conf
+		bld = Build.BuildContext(top_dir=conf.srcnode.abspath(), out_dir=conf.bldnode.abspath())
+		bld.env = conf.env
+		bld.init_dirs()
+		bld.in_msg = 1 # suppress top-level start_msg
+		bld.logger = self.logger
+		try:
+			bld.check(**self.args)
+		except:
+			return 1
+
+ at conf
+def multicheck(self, *k, **kw):
+	"""
+	Use tuples to perform parallel configuration tests
+	"""
+	self.start_msg(kw.get('msg', 'Executing %d configuration tests' % len(k)))
+
+	class par(object):
+		def __init__(self):
+			self.keep = False
+			self.cache_global = Options.cache_global
+			self.nocache = Options.options.nocache
+			self.returned_tasks = []
+		def total(self):
+			return len(tasks)
+		def to_log(self, *k, **kw):
+			return
+
+	bld = par()
+	tasks = []
+	for dct in k:
+		x = cfgtask(bld=bld)
+		tasks.append(x)
+		x.args = dct
+		x.bld = bld
+		x.conf = self
+		x.args = dct
+
+		# bind a logger that will keep the info in memory
+		x.logger = Logs.make_mem_logger(str(id(x)), self.logger)
+
+	def it():
+		yield tasks
+		while 1:
+			yield []
+	p = Runner.Parallel(bld, Options.options.jobs)
+	p.biter = it()
+	p.start()
+
+	# flush the logs in order into the config.log
+	for x in tasks:
+		x.logger.memhandler.flush()
+
+	for x in tasks:
+		if x.hasrun != Task.SUCCESS:
+			self.end_msg(kw.get('errmsg', 'no'), color='YELLOW')
+			self.fatal(kw.get('fatalmsg', None) or 'One of the tests has failed, see the config.log for more information')
+
+	self.end_msg('ok')
+
diff --git a/xpdeint/waf/waflib/Tools/c_config.pyc b/xpdeint/waf/waflib/Tools/c_config.pyc
new file mode 100644
index 0000000..e44053b
Binary files /dev/null and b/xpdeint/waf/waflib/Tools/c_config.pyc differ
diff --git a/xpdeint/waf/waflib/Tools/c_osx.py b/xpdeint/waf/waflib/Tools/c_osx.py
new file mode 100644
index 0000000..a2f6241
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/c_osx.py
@@ -0,0 +1,188 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy 2008-2010
+
+"""
+MacOSX related tools
+"""
+
+import os, shutil, sys, platform
+from waflib import TaskGen, Task, Build, Options, Utils, Errors
+from waflib.TaskGen import taskgen_method, feature, after_method, before_method
+
+app_info = '''
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleGetInfoString</key>
+	<string>Created by Waf</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>NOTE</key>
+	<string>THIS IS A GENERATED FILE, DO NOT MODIFY</string>
+	<key>CFBundleExecutable</key>
+	<string>%s</string>
+</dict>
+</plist>
+'''
+"""
+plist template
+"""
+
+ at feature('c', 'cxx')
+def set_macosx_deployment_target(self):
+	"""
+	see WAF issue 285 and also and also http://trac.macports.org/ticket/17059
+	"""
+	if self.env['MACOSX_DEPLOYMENT_TARGET']:
+		os.environ['MACOSX_DEPLOYMENT_TARGET'] = self.env['MACOSX_DEPLOYMENT_TARGET']
+	elif 'MACOSX_DEPLOYMENT_TARGET' not in os.environ:
+		if Utils.unversioned_sys_platform() == 'darwin':
+			os.environ['MACOSX_DEPLOYMENT_TARGET'] = '.'.join(platform.mac_ver()[0].split('.')[:2])
+
+ at taskgen_method
+def create_bundle_dirs(self, name, out):
+	"""
+	Create bundle folders, used by :py:func:`create_task_macplist` and :py:func:`create_task_macapp`
+	"""
+	bld = self.bld
+	dir = out.parent.find_or_declare(name)
+	dir.mkdir()
+	macos = dir.find_or_declare(['Contents', 'MacOS'])
+	macos.mkdir()
+	return dir
+
+def bundle_name_for_output(out):
+	name = out.name
+	k = name.rfind('.')
+	if k >= 0:
+		name = name[:k] + '.app'
+	else:
+		name = name + '.app'
+	return name
+
+ at feature('cprogram', 'cxxprogram')
+ at after_method('apply_link')
+def create_task_macapp(self):
+	"""
+	To compile an executable into a Mac application (a .app), set its *mac_app* attribute::
+
+		def build(bld):
+			bld.shlib(source='a.c', target='foo', mac_app = True)
+
+	To force *all* executables to be transformed into Mac applications::
+
+		def build(bld):
+			bld.env.MACAPP = True
+			bld.shlib(source='a.c', target='foo')
+	"""
+	if self.env['MACAPP'] or getattr(self, 'mac_app', False):
+		out = self.link_task.outputs[0]
+
+		name = bundle_name_for_output(out)
+		dir = self.create_bundle_dirs(name, out)
+
+		n1 = dir.find_or_declare(['Contents', 'MacOS', out.name])
+
+		self.apptask = self.create_task('macapp', self.link_task.outputs, n1)
+		inst_to = getattr(self, 'install_path', '/Applications') + '/%s/Contents/MacOS/' % name
+		self.bld.install_files(inst_to, n1, chmod=Utils.O755)
+
+		if getattr(self, 'mac_resources', None):
+			res_dir = n1.parent.parent.make_node('Resources')
+			inst_to = getattr(self, 'install_path', '/Applications') + '/%s/Resources' % name
+			for x in self.to_list(self.mac_resources):
+				node = self.path.find_node(x)
+				if not node:
+					raise Errors.WafError('Missing mac_resource %r in %r' % (x, self))
+
+				parent = node.parent
+				if os.path.isdir(node.abspath()):
+					nodes = node.ant_glob('**')
+				else:
+					nodes = [node]
+				for node in nodes:
+					rel = node.path_from(parent)
+					tsk = self.create_task('macapp', node, res_dir.make_node(rel))
+					self.bld.install_as(inst_to + '/%s' % rel, node)
+
+		if getattr(self.bld, 'is_install', None):
+			# disable the normal binary installation
+			self.install_task.hasrun = Task.SKIP_ME
+
+ at feature('cprogram', 'cxxprogram')
+ at after_method('apply_link')
+def create_task_macplist(self):
+	"""
+	Create a :py:class:`waflib.Tools.c_osx.macplist` instance.
+	"""
+	if  self.env['MACAPP'] or getattr(self, 'mac_app', False):
+		out = self.link_task.outputs[0]
+
+		name = bundle_name_for_output(out)
+
+		dir = self.create_bundle_dirs(name, out)
+		n1 = dir.find_or_declare(['Contents', 'Info.plist'])
+		self.plisttask = plisttask = self.create_task('macplist', [], n1)
+
+		if getattr(self, 'mac_plist', False):
+			node = self.path.find_resource(self.mac_plist)
+			if node:
+				plisttask.inputs.append(node)
+			else:
+				plisttask.code = self.mac_plist
+		else:
+			plisttask.code = app_info % self.link_task.outputs[0].name
+
+		inst_to = getattr(self, 'install_path', '/Applications') + '/%s/Contents/' % name
+		self.bld.install_files(inst_to, n1)
+
+ at feature('cshlib', 'cxxshlib')
+ at before_method('apply_link', 'propagate_uselib_vars')
+def apply_bundle(self):
+	"""
+	To make a bundled shared library (a ``.bundle``), set the *mac_bundle* attribute::
+
+		def build(bld):
+			bld.shlib(source='a.c', target='foo', mac_bundle = True)
+
+	To force *all* executables to be transformed into bundles::
+
+		def build(bld):
+			bld.env.MACBUNDLE = True
+			bld.shlib(source='a.c', target='foo')
+	"""
+	if self.env['MACBUNDLE'] or getattr(self, 'mac_bundle', False):
+		self.env['LINKFLAGS_cshlib'] = self.env['LINKFLAGS_cxxshlib'] = [] # disable the '-dynamiclib' flag
+		self.env['cshlib_PATTERN'] = self.env['cxxshlib_PATTERN'] = self.env['macbundle_PATTERN']
+		use = self.use = self.to_list(getattr(self, 'use', []))
+		if not 'MACBUNDLE' in use:
+			use.append('MACBUNDLE')
+
+app_dirs = ['Contents', 'Contents/MacOS', 'Contents/Resources']
+
+class macapp(Task.Task):
+	"""
+	Create mac applications
+	"""
+	color = 'PINK'
+	def run(self):
+		self.outputs[0].parent.mkdir()
+		shutil.copy2(self.inputs[0].srcpath(), self.outputs[0].abspath())
+
+class macplist(Task.Task):
+	"""
+	Create plist files
+	"""
+	color = 'PINK'
+	ext_in = ['.bin']
+	def run(self):
+		if getattr(self, 'code', None):
+			txt = self.code
+		else:
+			txt = self.inputs[0].read()
+		self.outputs[0].write(txt)
+
diff --git a/xpdeint/waf/waflib/Tools/c_preproc.py b/xpdeint/waf/waflib/Tools/c_preproc.py
new file mode 100644
index 0000000..79eef46
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/c_preproc.py
@@ -0,0 +1,1030 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+
+"""
+C/C++ preprocessor for finding dependencies
+
+Reasons for using the Waf preprocessor by default
+
+#. Some c/c++ extensions (Qt) require a custom preprocessor for obtaining the dependencies (.moc files)
+#. Not all compilers provide .d files for obtaining the dependencies (portability)
+#. A naive file scanner will not catch the constructs such as "#include foo()"
+#. A naive file scanner will catch unnecessary dependencies (change an unused header -> recompile everything)
+
+Regarding the speed concerns:
+
+* the preprocessing is performed only when files must be compiled
+* the macros are evaluated only for #if/#elif/#include
+* system headers are not scanned by default
+
+Now if you do not want the Waf preprocessor, the tool +gccdeps* uses the .d files produced
+during the compilation to track the dependencies (useful when used with the boost libraries).
+It only works with gcc >= 4.4 though.
+
+A dumb preprocessor is also available in the tool *c_dumbpreproc*
+"""
+# TODO: more varargs, pragma once
+
+import re, sys, os, string, traceback
+from waflib import Logs, Build, Utils, Errors
+from waflib.Logs import debug, error
+
+class PreprocError(Errors.WafError):
+	pass
+
+POPFILE = '-'
+"Constant representing a special token used in :py:meth:`waflib.Tools.c_preproc.c_parser.start` iteration to switch to a header read previously"
+
+recursion_limit = 150
+"Limit on the amount of files to read in the dependency scanner"
+
+go_absolute = False
+"Set to True to track headers on files in /usr/include, else absolute paths are ignored (but it becomes very slow)"
+
+standard_includes = ['/usr/include']
+if Utils.is_win32:
+	standard_includes = []
+
+use_trigraphs = 0
+"""Apply trigraph rules (False by default)"""
+
+strict_quotes = 0
+"""Reserve the "#include <>" quotes for system includes (do not search for those includes). False by default."""
+
+g_optrans = {
+'not':'!',
+'and':'&&',
+'bitand':'&',
+'and_eq':'&=',
+'or':'||',
+'bitor':'|',
+'or_eq':'|=',
+'xor':'^',
+'xor_eq':'^=',
+'compl':'~',
+}
+"""Operators such as and/or/xor for c++. Set an empty dict to disable."""
+
+# ignore #warning and #error
+re_lines = re.compile(
+	'^[ \t]*(#|%:)[ \t]*(ifdef|ifndef|if|else|elif|endif|include|import|define|undef|pragma)[ \t]*(.*)\r*$',
+	re.IGNORECASE | re.MULTILINE)
+"""Match #include lines"""
+
+re_mac = re.compile("^[a-zA-Z_]\w*")
+"""Match macro definitions"""
+
+re_fun = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*[(]')
+"""Match macro functions"""
+
+re_pragma_once = re.compile('^\s*once\s*', re.IGNORECASE)
+"""Match #pragma once statements"""
+
+re_nl = re.compile('\\\\\r*\n', re.MULTILINE)
+"""Match newlines"""
+
+re_cpp = re.compile(
+	r"""(/\*[^*]*\*+([^/*][^*]*\*+)*/)|//[^\n]*|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^/"'\\]*)""",
+	re.MULTILINE)
+"""Filter C/C++ comments"""
+
+trig_def = [('??'+a, b) for a, b in zip("=-/!'()<>", r'#~\|^[]{}')]
+"""Trigraph definitions"""
+
+chr_esc = {'0':0, 'a':7, 'b':8, 't':9, 'n':10, 'f':11, 'v':12, 'r':13, '\\':92, "'":39}
+"""Escape characters"""
+
+NUM   = 'i'
+"""Number token"""
+
+OP    = 'O'
+"""Operator token"""
+
+IDENT = 'T'
+"""Identifier token"""
+
+STR   = 's'
+"""String token"""
+
+CHAR  = 'c'
+"""Character token"""
+
+tok_types = [NUM, STR, IDENT, OP]
+"""Token types"""
+
+exp_types = [
+	r"""0[xX](?P<hex>[a-fA-F0-9]+)(?P<qual1>[uUlL]*)|L*?'(?P<char>(\\.|[^\\'])+)'|(?P<n1>\d+)[Ee](?P<exp0>[+-]*?\d+)(?P<float0>[fFlL]*)|(?P<n2>\d*\.\d+)([Ee](?P<exp1>[+-]*?\d+))?(?P<float1>[fFlL]*)|(?P<n4>\d+\.\d*)([Ee](?P<exp2>[+-]*?\d+))?(?P<float2>[fFlL]*)|(?P<oct>0*)(?P<n0>\d+)(?P<qual2>[uUlL]*)""",
+	r'L?"([^"\\]|\\.)*"',
+	r'[a-zA-Z_]\w*',
+	r'%:%:|<<=|>>=|\.\.\.|<<|<%|<:|<=|>>|>=|\+\+|\+=|--|->|-=|\*=|/=|%:|%=|%>|==|&&|&=|\|\||\|=|\^=|:>|!=|##|[\(\)\{\}\[\]<>\?\|\^\*\+&=:!#;,%/\-\?\~\.]',
+]
+"""Expression types"""
+
+re_clexer = re.compile('|'.join(["(?P<%s>%s)" % (name, part) for name, part in zip(tok_types, exp_types)]), re.M)
+"""Match expressions into tokens"""
+
+accepted  = 'a'
+"""Parser state is *accepted*"""
+
+ignored   = 'i'
+"""Parser state is *ignored*, for example preprocessor lines in an #if 0 block"""
+
+undefined = 'u'
+"""Parser state is *undefined* at the moment"""
+
+skipped   = 's'
+"""Parser state is *skipped*, for example preprocessor lines in a #elif 0 block"""
+
+def repl(m):
+	"""Replace function used with :py:attr:`waflib.Tools.c_preproc.re_cpp`"""
+	s = m.group(1)
+	if s:
+		return ' '
+	return m.group(3) or ''
+
+def filter_comments(filename):
+	"""
+	Filter the comments from a c/h file, and return the preprocessor lines.
+	The regexps :py:attr:`waflib.Tools.c_preproc.re_cpp`, :py:attr:`waflib.Tools.c_preproc.re_nl` and :py:attr:`waflib.Tools.c_preproc.re_lines` are used internally.
+
+	:return: the preprocessor directives as a list of (keyword, line)
+	:rtype: a list of string pairs
+	"""
+	# return a list of tuples : keyword, line
+	code = Utils.readf(filename)
+	if use_trigraphs:
+		for (a, b) in trig_def: code = code.split(a).join(b)
+	code = re_nl.sub('', code)
+	code = re_cpp.sub(repl, code)
+	return [(m.group(2), m.group(3)) for m in re.finditer(re_lines, code)]
+
+prec = {}
+"""
+Operator precendence rules required for parsing expressions of the form::
+
+	#if 1 && 2 != 0
+"""
+ops = ['* / %', '+ -', '<< >>', '< <= >= >', '== !=', '& | ^', '&& ||', ',']
+for x in range(len(ops)):
+	syms = ops[x]
+	for u in syms.split():
+		prec[u] = x
+
+def trimquotes(s):
+	"""
+	Remove the single quotes around an expression::
+
+		trimquotes("'test'") == "test"
+
+	:param s: expression to transform
+	:type s: string
+	:rtype: string
+	"""
+	if not s: return ''
+	s = s.rstrip()
+	if s[0] == "'" and s[-1] == "'": return s[1:-1]
+	return s
+
+def reduce_nums(val_1, val_2, val_op):
+	"""
+	Apply arithmetic rules to compute a result
+
+	:param val1: input parameter
+	:type val1: int or string
+	:param val2: input parameter
+	:type val2: int or string
+	:param val_op: C operator in *+*, */*, *-*, etc
+	:type val_op: string
+	:rtype: int
+	"""
+	#print val_1, val_2, val_op
+
+	# now perform the operation, make certain a and b are numeric
+	try:    a = 0 + val_1
+	except TypeError: a = int(val_1)
+	try:    b = 0 + val_2
+	except TypeError: b = int(val_2)
+
+	d = val_op
+	if d == '%':  c = a%b
+	elif d=='+':  c = a+b
+	elif d=='-':  c = a-b
+	elif d=='*':  c = a*b
+	elif d=='/':  c = a/b
+	elif d=='^':  c = a^b
+	elif d=='|':  c = a|b
+	elif d=='||': c = int(a or b)
+	elif d=='&':  c = a&b
+	elif d=='&&': c = int(a and b)
+	elif d=='==': c = int(a == b)
+	elif d=='!=': c = int(a != b)
+	elif d=='<=': c = int(a <= b)
+	elif d=='<':  c = int(a < b)
+	elif d=='>':  c = int(a > b)
+	elif d=='>=': c = int(a >= b)
+	elif d=='^':  c = int(a^b)
+	elif d=='<<': c = a<<b
+	elif d=='>>': c = a>>b
+	else: c = 0
+	return c
+
+def get_num(lst):
+	"""
+	Try to obtain a number from a list of tokens. The token types are defined in :py:attr:`waflib.Tools.ccroot.tok_types`.
+
+	:param lst: list of preprocessor tokens
+	:type lst: list of tuple (tokentype, value)
+	:return: a pair containing the number and the rest of the list
+	:rtype: tuple(value, list)
+	"""
+	if not lst: raise PreprocError("empty list for get_num")
+	(p, v) = lst[0]
+	if p == OP:
+		if v == '(':
+			count_par = 1
+			i = 1
+			while i < len(lst):
+				(p, v) = lst[i]
+
+				if p == OP:
+					if v == ')':
+						count_par -= 1
+						if count_par == 0:
+							break
+					elif v == '(':
+						count_par += 1
+				i += 1
+			else:
+				raise PreprocError("rparen expected %r" % lst)
+
+			(num, _) = get_term(lst[1:i])
+			return (num, lst[i+1:])
+
+		elif v == '+':
+			return get_num(lst[1:])
+		elif v == '-':
+			num, lst = get_num(lst[1:])
+			return (reduce_nums('-1', num, '*'), lst)
+		elif v == '!':
+			num, lst = get_num(lst[1:])
+			return (int(not int(num)), lst)
+		elif v == '~':
+			return (~ int(num), lst)
+		else:
+			raise PreprocError("Invalid op token %r for get_num" % lst)
+	elif p == NUM:
+		return v, lst[1:]
+	elif p == IDENT:
+		# all macros should have been replaced, remaining identifiers eval to 0
+		return 0, lst[1:]
+	else:
+		raise PreprocError("Invalid token %r for get_num" % lst)
+
+def get_term(lst):
+	"""
+	Evaluate an expression recursively, for example::
+
+		1+1+1 -> 2+1 -> 3
+
+	:param lst: list of tokens
+	:type lst: list of tuple(token, value)
+	:return: the value and the remaining tokens
+	:rtype: value, list
+	"""
+
+	if not lst: raise PreprocError("empty list for get_term")
+	num, lst = get_num(lst)
+	if not lst:
+		return (num, [])
+	(p, v) = lst[0]
+	if p == OP:
+		if v == '&&' and not num:
+			return (num, [])
+		elif v == '||' and num:
+			return (num, [])
+		elif v == ',':
+			# skip
+			return get_term(lst[1:])
+		elif v == '?':
+			count_par = 0
+			i = 1
+			while i < len(lst):
+				(p, v) = lst[i]
+
+				if p == OP:
+					if v == ')':
+						count_par -= 1
+					elif v == '(':
+						count_par += 1
+					elif v == ':':
+						if count_par == 0:
+							break
+				i += 1
+			else:
+				raise PreprocError("rparen expected %r" % lst)
+
+			if int(num):
+				return get_term(lst[1:i])
+			else:
+				return get_term(lst[i+1:])
+
+		else:
+			num2, lst = get_num(lst[1:])
+
+			if not lst:
+				# no more tokens to process
+				num2 = reduce_nums(num, num2, v)
+				return get_term([(NUM, num2)] + lst)
+
+			# operator precedence
+			p2, v2 = lst[0]
+			if p2 != OP:
+				raise PreprocError("op expected %r" % lst)
+
+			if prec[v2] >= prec[v]:
+				num2 = reduce_nums(num, num2, v)
+				return get_term([(NUM, num2)] + lst)
+			else:
+				num3, lst = get_num(lst[1:])
+				num3 = reduce_nums(num2, num3, v2)
+				return get_term([(NUM, num), (p, v), (NUM, num3)] + lst)
+
+
+	raise PreprocError("cannot reduce %r" % lst)
+
+def reduce_eval(lst):
+	"""
+	Take a list of tokens and output true or false for #if/#elif conditions.
+
+	:param lst: a list of tokens
+	:type lst: list of tuple(token, value)
+	:return: a token
+	:rtype: tuple(NUM, int)
+	"""
+	num, lst = get_term(lst)
+	return (NUM, num)
+
+def stringize(lst):
+	"""
+	Merge a list of tokens into a string
+
+	:param lst: a list of tokens
+	:type lst: list of tuple(token, value)
+	:rtype: string
+	"""
+	lst = [str(v2) for (p2, v2) in lst]
+	return "".join(lst)
+
+def paste_tokens(t1, t2):
+	"""
+	Token pasting works between identifiers, particular operators, and identifiers and numbers::
+
+		a ## b  ->  ab
+		> ## =  ->  >=
+		a ## 2  ->  a2
+
+	:param t1: token
+	:type t1: tuple(type, value)
+	:param t2: token
+	:type t2: tuple(type, value)
+	"""
+	p1 = None
+	if t1[0] == OP and t2[0] == OP:
+		p1 = OP
+	elif t1[0] == IDENT and (t2[0] == IDENT or t2[0] == NUM):
+		p1 = IDENT
+	elif t1[0] == NUM and t2[0] == NUM:
+		p1 = NUM
+	if not p1:
+		raise PreprocError('tokens do not make a valid paste %r and %r' % (t1, t2))
+	return (p1, t1[1] + t2[1])
+
+def reduce_tokens(lst, defs, ban=[]):
+	"""
+	Replace the tokens in lst, using the macros provided in defs, and a list of macros that cannot be re-applied
+
+	:param lst: list of tokens
+	:type lst: list of tuple(token, value)
+	:param defs: macro definitions
+	:type defs: dict
+	:param ban: macros that cannot be substituted (recursion is not allowed)
+	:type ban: list of string
+	:return: the new list of tokens
+	:rtype: value, list
+	"""
+	i = 0
+
+	while i < len(lst):
+		(p, v) = lst[i]
+
+		if p == IDENT and v == "defined":
+			del lst[i]
+			if i < len(lst):
+				(p2, v2) = lst[i]
+				if p2 == IDENT:
+					if v2 in defs:
+						lst[i] = (NUM, 1)
+					else:
+						lst[i] = (NUM, 0)
+				elif p2 == OP and v2 == '(':
+					del lst[i]
+					(p2, v2) = lst[i]
+					del lst[i] # remove the ident, and change the ) for the value
+					if v2 in defs:
+						lst[i] = (NUM, 1)
+					else:
+						lst[i] = (NUM, 0)
+				else:
+					raise PreprocError("Invalid define expression %r" % lst)
+
+		elif p == IDENT and v in defs:
+
+			if isinstance(defs[v], str):
+				a, b = extract_macro(defs[v])
+				defs[v] = b
+			macro_def = defs[v]
+			to_add = macro_def[1]
+
+			if isinstance(macro_def[0], list):
+				# macro without arguments
+				del lst[i]
+				for x in range(len(to_add)):
+					lst.insert(i, to_add[x])
+					i += 1
+			else:
+				# collect the arguments for the funcall
+
+				args = []
+				del lst[i]
+
+				if i >= len(lst):
+					raise PreprocError("expected '(' after %r (got nothing)" % v)
+
+				(p2, v2) = lst[i]
+				if p2 != OP or v2 != '(':
+					raise PreprocError("expected '(' after %r" % v)
+
+				del lst[i]
+
+				one_param = []
+				count_paren = 0
+				while i < len(lst):
+					p2, v2 = lst[i]
+
+					del lst[i]
+					if p2 == OP and count_paren == 0:
+						if v2 == '(':
+							one_param.append((p2, v2))
+							count_paren += 1
+						elif v2 == ')':
+							if one_param: args.append(one_param)
+							break
+						elif v2 == ',':
+							if not one_param: raise PreprocError("empty param in funcall %s" % p)
+							args.append(one_param)
+							one_param = []
+						else:
+							one_param.append((p2, v2))
+					else:
+						one_param.append((p2, v2))
+						if   v2 == '(': count_paren += 1
+						elif v2 == ')': count_paren -= 1
+				else:
+					raise PreprocError('malformed macro')
+
+				# substitute the arguments within the define expression
+				accu = []
+				arg_table = macro_def[0]
+				j = 0
+				while j < len(to_add):
+					(p2, v2) = to_add[j]
+
+					if p2 == OP and v2 == '#':
+						# stringize is for arguments only
+						if j+1 < len(to_add) and to_add[j+1][0] == IDENT and to_add[j+1][1] in arg_table:
+							toks = args[arg_table[to_add[j+1][1]]]
+							accu.append((STR, stringize(toks)))
+							j += 1
+						else:
+							accu.append((p2, v2))
+					elif p2 == OP and v2 == '##':
+						# token pasting, how can man invent such a complicated system?
+						if accu and j+1 < len(to_add):
+							# we have at least two tokens
+
+							t1 = accu[-1]
+
+							if to_add[j+1][0] == IDENT and to_add[j+1][1] in arg_table:
+								toks = args[arg_table[to_add[j+1][1]]]
+
+								if toks:
+									accu[-1] = paste_tokens(t1, toks[0]) #(IDENT, accu[-1][1] + toks[0][1])
+									accu.extend(toks[1:])
+								else:
+									# error, case "a##"
+									accu.append((p2, v2))
+									accu.extend(toks)
+							elif to_add[j+1][0] == IDENT and to_add[j+1][1] == '__VA_ARGS__':
+								# TODO not sure
+								# first collect the tokens
+								va_toks = []
+								st = len(macro_def[0])
+								pt = len(args)
+								for x in args[pt-st+1:]:
+									va_toks.extend(x)
+									va_toks.append((OP, ','))
+								if va_toks: va_toks.pop() # extra comma
+								if len(accu)>1:
+									(p3, v3) = accu[-1]
+									(p4, v4) = accu[-2]
+									if v3 == '##':
+										# remove the token paste
+										accu.pop()
+										if v4 == ',' and pt < st:
+											# remove the comma
+											accu.pop()
+								accu += va_toks
+							else:
+								accu[-1] = paste_tokens(t1, to_add[j+1])
+
+							j += 1
+						else:
+							# Invalid paste, case    "##a" or "b##"
+							accu.append((p2, v2))
+
+					elif p2 == IDENT and v2 in arg_table:
+						toks = args[arg_table[v2]]
+						reduce_tokens(toks, defs, ban+[v])
+						accu.extend(toks)
+					else:
+						accu.append((p2, v2))
+
+					j += 1
+
+
+				reduce_tokens(accu, defs, ban+[v])
+
+				for x in range(len(accu)-1, -1, -1):
+					lst.insert(i, accu[x])
+
+		i += 1
+
+
+def eval_macro(lst, defs):
+	"""
+	Reduce the tokens by :py:func:`waflib.Tools.c_preproc.reduce_tokens` and try to return a 0/1 result by :py:func:`waflib.Tools.c_preproc.reduce_eval`.
+
+	:param lst: list of tokens
+	:type lst: list of tuple(token, value)
+	:param defs: macro definitions
+	:type defs: dict
+	:rtype: int
+	"""
+	reduce_tokens(lst, defs, [])
+	if not lst: raise PreprocError("missing tokens to evaluate")
+	(p, v) = reduce_eval(lst)
+	return int(v) != 0
+
+def extract_macro(txt):
+	"""
+	Process a macro definition of the form::
+		 #define f(x, y) x * y
+
+	into a function or a simple macro without arguments
+
+	:param txt: expression to exact a macro definition from
+	:type txt: string
+	:return: a tuple containing the name, the list of arguments and the replacement
+	:rtype: tuple(string, [list, list])
+	"""
+	t = tokenize(txt)
+	if re_fun.search(txt):
+		p, name = t[0]
+
+		p, v = t[1]
+		if p != OP: raise PreprocError("expected open parenthesis")
+
+		i = 1
+		pindex = 0
+		params = {}
+		prev = '('
+
+		while 1:
+			i += 1
+			p, v = t[i]
+
+			if prev == '(':
+				if p == IDENT:
+					params[v] = pindex
+					pindex += 1
+					prev = p
+				elif p == OP and v == ')':
+					break
+				else:
+					raise PreprocError("unexpected token (3)")
+			elif prev == IDENT:
+				if p == OP and v == ',':
+					prev = v
+				elif p == OP and v == ')':
+					break
+				else:
+					raise PreprocError("comma or ... expected")
+			elif prev == ',':
+				if p == IDENT:
+					params[v] = pindex
+					pindex += 1
+					prev = p
+				elif p == OP and v == '...':
+					raise PreprocError("not implemented (1)")
+				else:
+					raise PreprocError("comma or ... expected (2)")
+			elif prev == '...':
+				raise PreprocError("not implemented (2)")
+			else:
+				raise PreprocError("unexpected else")
+
+		#~ print (name, [params, t[i+1:]])
+		return (name, [params, t[i+1:]])
+	else:
+		(p, v) = t[0]
+		return (v, [[], t[1:]])
+
+re_include = re.compile('^\s*(<(?P<a>.*)>|"(?P<b>.*)")')
+def extract_include(txt, defs):
+	"""
+	Process a line in the form::
+
+		#include foo
+
+	:param txt: include line to process
+	:type txt: string
+	:param defs: macro definitions
+	:type defs: dict
+	:return: the file name
+	:rtype: string
+	"""
+	m = re_include.search(txt)
+	if m:
+		if m.group('a'): return '<', m.group('a')
+		if m.group('b'): return '"', m.group('b')
+
+	# perform preprocessing and look at the result, it must match an include
+	toks = tokenize(txt)
+	reduce_tokens(toks, defs, ['waf_include'])
+
+	if not toks:
+		raise PreprocError("could not parse include %s" % txt)
+
+	if len(toks) == 1:
+		if toks[0][0] == STR:
+			return '"', toks[0][1]
+	else:
+		if toks[0][1] == '<' and toks[-1][1] == '>':
+			return stringize(toks).lstrip('<').rstrip('>')
+
+	raise PreprocError("could not parse include %s." % txt)
+
+def parse_char(txt):
+	"""
+	Parse a c character
+
+	:param txt: character to parse
+	:type txt: string
+	:return: a character literal
+	:rtype: string
+	"""
+
+	if not txt: raise PreprocError("attempted to parse a null char")
+	if txt[0] != '\\':
+		return ord(txt)
+	c = txt[1]
+	if c == 'x':
+		if len(txt) == 4 and txt[3] in string.hexdigits: return int(txt[2:], 16)
+		return int(txt[2:], 16)
+	elif c.isdigit():
+		if c == '0' and len(txt)==2: return 0
+		for i in 3, 2, 1:
+			if len(txt) > i and txt[1:1+i].isdigit():
+				return (1+i, int(txt[1:1+i], 8))
+	else:
+		try: return chr_esc[c]
+		except KeyError: raise PreprocError("could not parse char literal '%s'" % txt)
+
+ at Utils.run_once
+def tokenize(s):
+	"""
+	Convert a string into a list of tokens (shlex.split does not apply to c/c++/d)
+
+	:param s: input to tokenize
+	:type s: string
+	:return: a list of tokens
+	:rtype: list of tuple(token, value)
+	"""
+	# the same headers are read again and again - 10% improvement on preprocessing the samba headers
+	ret = []
+	for match in re_clexer.finditer(s):
+		m = match.group
+		for name in tok_types:
+			v = m(name)
+			if v:
+				if name == IDENT:
+					try: v = g_optrans[v]; name = OP
+					except KeyError:
+						# c++ specific
+						if v.lower() == "true":
+							v = 1
+							name = NUM
+						elif v.lower() == "false":
+							v = 0
+							name = NUM
+				elif name == NUM:
+					if m('oct'): v = int(v, 8)
+					elif m('hex'): v = int(m('hex'), 16)
+					elif m('n0'): v = m('n0')
+					else:
+						v = m('char')
+						if v: v = parse_char(v)
+						else: v = m('n2') or m('n4')
+				elif name == OP:
+					if v == '%:': v = '#'
+					elif v == '%:%:': v = '##'
+				elif name == STR:
+					# remove the quotes around the string
+					v = v[1:-1]
+				ret.append((name, v))
+				break
+	return ret
+
+ at Utils.run_once
+def define_name(line):
+	"""
+	:param line: define line
+	:type line: string
+	:rtype: string
+	:return: the define name
+	"""
+	return re_mac.match(line).group(0)
+
+class c_parser(object):
+	"""
+	Used by :py:func:`waflib.Tools.c_preproc.scan` to parse c/h files. Note that by default,
+	only project headers are parsed.
+	"""
+	def __init__(self, nodepaths=None, defines=None):
+		self.lines = []
+		"""list of lines read"""
+
+		if defines is None:
+			self.defs  = {}
+		else:
+			self.defs  = dict(defines) # make a copy
+		self.state = []
+
+		self.count_files = 0
+		self.currentnode_stack = []
+
+		self.nodepaths = nodepaths or []
+		"""Include paths"""
+
+		self.nodes = []
+		"""List of :py:class:`waflib.Node.Node` found so far"""
+
+		self.names = []
+		"""List of file names that could not be matched by any file"""
+
+		self.curfile = ''
+		"""Current file"""
+
+		self.ban_includes = set([])
+		"""Includes that must not be read (#pragma once)"""
+
+	def cached_find_resource(self, node, filename):
+		"""
+		Find a file from the input directory
+
+		:param node: directory
+		:type node: :py:class:`waflib.Node.Node`
+		:param filename: header to find
+		:type filename: string
+		:return: the node if found, or None
+		:rtype: :py:class:`waflib.Node.Node`
+		"""
+		try:
+			nd = node.ctx.cache_nd
+		except:
+			nd = node.ctx.cache_nd = {}
+
+		tup = (node, filename)
+		try:
+			return nd[tup]
+		except KeyError:
+			ret = node.find_resource(filename)
+			if ret:
+				if getattr(ret, 'children', None):
+					ret = None
+				elif ret.is_child_of(node.ctx.bldnode):
+					tmp = node.ctx.srcnode.search(ret.path_from(node.ctx.bldnode))
+					if tmp and getattr(tmp, 'children', None):
+						ret = None
+			nd[tup] = ret
+			return ret
+
+	def tryfind(self, filename):
+		"""
+		Try to obtain a node from the filename based from the include paths. Will add
+		the node found to :py:attr:`waflib.Tools.c_preproc.c_parser.nodes` or the file name to
+		:py:attr:`waflib.Tools.c_preproc.c_parser.names` if no corresponding file is found. Called by
+		:py:attr:`waflib.Tools.c_preproc.c_parser.start`.
+
+		:param filename: header to find
+		:type filename: string
+		:return: the node if found
+		:rtype: :py:class:`waflib.Node.Node`
+		"""
+		self.curfile = filename
+
+		# for msvc it should be a for loop on the whole stack
+		found = self.cached_find_resource(self.currentnode_stack[-1], filename)
+
+		for n in self.nodepaths:
+			if found:
+				break
+			found = self.cached_find_resource(n, filename)
+
+		if found:
+			# TODO the duplicates do not increase the no-op build times too much, but they may be worth removing
+			self.nodes.append(found)
+			if filename[-4:] != '.moc':
+				self.addlines(found)
+		else:
+			if not filename in self.names:
+				self.names.append(filename)
+		return found
+
+	def addlines(self, node):
+		"""
+		Add the lines from a header in the list of preprocessor lines to parse
+
+		:param node: header
+		:type node: :py:class:`waflib.Node.Node`
+		"""
+
+		self.currentnode_stack.append(node.parent)
+		filepath = node.abspath()
+
+		self.count_files += 1
+		if self.count_files > recursion_limit:
+			# issue #812
+			raise PreprocError("recursion limit exceeded")
+		pc = self.parse_cache
+		debug('preproc: reading file %r', filepath)
+		try:
+			lns = pc[filepath]
+		except KeyError:
+			pass
+		else:
+			self.lines.extend(lns)
+			return
+
+		try:
+			lines = filter_comments(filepath)
+			lines.append((POPFILE, ''))
+			lines.reverse()
+			pc[filepath] = lines # cache the lines filtered
+			self.lines.extend(lines)
+		except IOError:
+			raise PreprocError("could not read the file %s" % filepath)
+		except Exception:
+			if Logs.verbose > 0:
+				error("parsing %s failed" % filepath)
+				traceback.print_exc()
+
+	def start(self, node, env):
+		"""
+		Preprocess a source file to obtain the dependencies, which are accumulated to :py:attr:`waflib.Tools.c_preproc.c_parser.nodes`
+		and :py:attr:`waflib.Tools.c_preproc.c_parser.names`.
+
+		:param node: source file
+		:type node: :py:class:`waflib.Node.Node`
+		:param env: config set containing additional defines to take into account
+		:type env: :py:class:`waflib.ConfigSet.ConfigSet`
+		"""
+
+		debug('preproc: scanning %s (in %s)', node.name, node.parent.name)
+
+		bld = node.ctx
+		try:
+			self.parse_cache = bld.parse_cache
+		except AttributeError:
+			bld.parse_cache = {}
+			self.parse_cache = bld.parse_cache
+
+		self.addlines(node)
+
+		# macros may be defined on the command-line, so they must be parsed as if they were part of the file
+		if env['DEFINES']:
+			try:
+				lst = ['%s %s' % (x[0], trimquotes('='.join(x[1:]))) for x in [y.split('=') for y in env['DEFINES']]]
+				lst.reverse()
+				self.lines.extend([('define', x) for x in lst])
+			except AttributeError:
+				# if the defines are invalid the compiler will tell the user
+				pass
+
+		while self.lines:
+			(token, line) = self.lines.pop()
+			if token == POPFILE:
+				self.count_files -= 1
+				self.currentnode_stack.pop()
+				continue
+
+			try:
+				ve = Logs.verbose
+				if ve: debug('preproc: line is %s - %s state is %s', token, line, self.state)
+				state = self.state
+
+				# make certain we define the state if we are about to enter in an if block
+				if token[:2] == 'if':
+					state.append(undefined)
+				elif token == 'endif':
+					state.pop()
+
+				# skip lines when in a dead 'if' branch, wait for the endif
+				if token[0] != 'e':
+					if skipped in self.state or ignored in self.state:
+						continue
+
+				if token == 'if':
+					ret = eval_macro(tokenize(line), self.defs)
+					if ret: state[-1] = accepted
+					else: state[-1] = ignored
+				elif token == 'ifdef':
+					m = re_mac.match(line)
+					if m and m.group(0) in self.defs: state[-1] = accepted
+					else: state[-1] = ignored
+				elif token == 'ifndef':
+					m = re_mac.match(line)
+					if m and m.group(0) in self.defs: state[-1] = ignored
+					else: state[-1] = accepted
+				elif token == 'include' or token == 'import':
+					(kind, inc) = extract_include(line, self.defs)
+					if inc in self.ban_includes:
+						continue
+					if token == 'import': self.ban_includes.add(inc)
+					if ve: debug('preproc: include found %s    (%s) ', inc, kind)
+					if kind == '"' or not strict_quotes:
+						self.tryfind(inc)
+				elif token == 'elif':
+					if state[-1] == accepted:
+						state[-1] = skipped
+					elif state[-1] == ignored:
+						if eval_macro(tokenize(line), self.defs):
+							state[-1] = accepted
+				elif token == 'else':
+					if state[-1] == accepted: state[-1] = skipped
+					elif state[-1] == ignored: state[-1] = accepted
+				elif token == 'define':
+					try:
+						self.defs[define_name(line)] = line
+					except:
+						raise PreprocError("Invalid define line %s" % line)
+				elif token == 'undef':
+					m = re_mac.match(line)
+					if m and m.group(0) in self.defs:
+						self.defs.__delitem__(m.group(0))
+						#print "undef %s" % name
+				elif token == 'pragma':
+					if re_pragma_once.match(line.lower()):
+						self.ban_includes.add(self.curfile)
+			except Exception as e:
+				if Logs.verbose:
+					debug('preproc: line parsing failed (%s): %s %s', e, line, Utils.ex_stack())
+
+def scan(task):
+	"""
+	Get the dependencies using a c/c++ preprocessor, this is required for finding dependencies of the kind::
+
+		#include some_macro()
+
+	This function is bound as a task method on :py:class:`waflib.Tools.c.c` and :py:class:`waflib.Tools.cxx.cxx` for example
+	"""
+
+	global go_absolute
+
+	try:
+		incn = task.generator.includes_nodes
+	except AttributeError:
+		raise Errors.WafError('%r is missing a feature such as "c", "cxx" or "includes": ' % task.generator)
+
+	if go_absolute:
+		nodepaths = incn + standard_includes
+	else:
+		nodepaths = [x for x in incn if x.is_child_of(x.ctx.srcnode) or x.is_child_of(x.ctx.bldnode)]
+
+	tmp = c_parser(nodepaths)
+	tmp.start(task.inputs[0], task.env)
+	if Logs.verbose:
+		debug('deps: deps for %r: %r; unresolved %r' % (task.inputs, tmp.nodes, tmp.names))
+	return (tmp.nodes, tmp.names)
+
diff --git a/xpdeint/waf/waflib/Tools/c_preproc.pyc b/xpdeint/waf/waflib/Tools/c_preproc.pyc
new file mode 100644
index 0000000..0df35e0
Binary files /dev/null and b/xpdeint/waf/waflib/Tools/c_preproc.pyc differ
diff --git a/xpdeint/waf/waflib/Tools/c_tests.py b/xpdeint/waf/waflib/Tools/c_tests.py
new file mode 100644
index 0000000..a2a1d08
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/c_tests.py
@@ -0,0 +1,218 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2010 (ita)
+
+"""
+Various configuration tests.
+"""
+
+from waflib import Task
+from waflib.Configure import conf
+from waflib.TaskGen import feature, before_method, after_method
+import sys
+
+LIB_CODE = '''
+#ifdef _MSC_VER
+#define testEXPORT __declspec(dllexport)
+#else
+#define testEXPORT
+#endif
+testEXPORT int lib_func(void) { return 9; }
+'''
+
+MAIN_CODE = '''
+#ifdef _MSC_VER
+#define testEXPORT __declspec(dllimport)
+#else
+#define testEXPORT
+#endif
+testEXPORT int lib_func(void);
+int main(void) {return !(lib_func() == 9);}
+'''
+
+ at feature('link_lib_test')
+ at before_method('process_source')
+def link_lib_test_fun(self):
+	"""
+	The configuration test :py:func:`waflib.Tools.ccroot.run_c_code` declares a unique task generator,
+	so we need to create other task generators from here to check if the linker is able to link libraries.
+	"""
+	def write_test_file(task):
+		task.outputs[0].write(task.generator.code)
+
+	rpath = []
+	if getattr(self, 'add_rpath', False):
+		rpath = [self.bld.path.get_bld().abspath()]
+
+	mode = self.mode
+	m = '%s %s' % (mode, mode)
+	ex = self.test_exec and 'test_exec' or ''
+	bld = self.bld
+	bld(rule=write_test_file, target='test.' + mode, code=LIB_CODE)
+	bld(rule=write_test_file, target='main.' + mode, code=MAIN_CODE)
+	bld(features='%sshlib' % m, source='test.' + mode, target='test')
+	bld(features='%sprogram %s' % (m, ex), source='main.' + mode, target='app', use='test', rpath=rpath)
+
+ at conf
+def check_library(self, mode=None, test_exec=True):
+	"""
+	Check if libraries can be linked with the current linker. Uses :py:func:`waflib.Tools.c_tests.link_lib_test_fun`.
+
+	:param mode: c or cxx or d
+	:type mode: string
+	"""
+	if not mode:
+		mode = 'c'
+		if self.env.CXX:
+			mode = 'cxx'
+	self.check(
+		compile_filename = [],
+		features = 'link_lib_test',
+		msg = 'Checking for libraries',
+		mode = mode,
+		test_exec = test_exec,
+		)
+
+########################################################################################
+
+INLINE_CODE = '''
+typedef int foo_t;
+static %s foo_t static_foo () {return 0; }
+%s foo_t foo () {
+	return 0;
+}
+'''
+INLINE_VALUES = ['inline', '__inline__', '__inline']
+
+ at conf
+def check_inline(self, **kw):
+	"""
+	Check for the right value for inline macro.
+	Define INLINE_MACRO to 1 if the define is found.
+	If the inline macro is not 'inline', add a define to the ``config.h`` (#define inline __inline__)
+
+	:param define_name: define INLINE_MACRO by default to 1 if the macro is defined
+	:type define_name: string
+	:param features: by default *c* or *cxx* depending on the compiler present
+	:type features: list of string
+	"""
+
+	self.start_msg('Checking for inline')
+
+	if not 'define_name' in kw:
+		kw['define_name'] = 'INLINE_MACRO'
+	if not 'features' in kw:
+		if self.env.CXX:
+			kw['features'] = ['cxx']
+		else:
+			kw['features'] = ['c']
+
+	for x in INLINE_VALUES:
+		kw['fragment'] = INLINE_CODE % (x, x)
+
+		try:
+			self.check(**kw)
+		except self.errors.ConfigurationError:
+			continue
+		else:
+			self.end_msg(x)
+			if x != 'inline':
+				self.define('inline', x, quote=False)
+			return x
+	self.fatal('could not use inline functions')
+
+########################################################################################
+
+LARGE_FRAGMENT = '#include <unistd.h>\nint main() { return !(sizeof(off_t) >= 8); }\n'
+
+ at conf
+def check_large_file(self, **kw):
+	"""
+	Check for large file support and define the macro HAVE_LARGEFILE
+	The test is skipped on win32 systems (DEST_BINFMT == pe).
+
+	:param define_name: define to set, by default *HAVE_LARGEFILE*
+	:type define_name: string
+	:param execute: execute the test (yes by default)
+	:type execute: bool
+	"""
+
+	if not 'define_name' in kw:
+		kw['define_name'] = 'HAVE_LARGEFILE'
+	if not 'execute' in kw:
+		kw['execute'] = True
+
+	if not 'features' in kw:
+		if self.env.CXX:
+			kw['features'] = ['cxx', 'cxxprogram']
+		else:
+			kw['features'] = ['c', 'cprogram']
+
+	kw['fragment'] = LARGE_FRAGMENT
+
+	kw['msg'] = 'Checking for large file support'
+	ret = True
+	try:
+		if self.env.DEST_BINFMT != 'pe':
+			ret = self.check(**kw)
+	except self.errors.ConfigurationError:
+		pass
+	else:
+		if ret:
+			return True
+
+	kw['msg'] = 'Checking for -D_FILE_OFFSET_BITS=64'
+	kw['defines'] = ['_FILE_OFFSET_BITS=64']
+	try:
+		ret = self.check(**kw)
+	except self.errors.ConfigurationError:
+		pass
+	else:
+		self.define('_FILE_OFFSET_BITS', 64)
+		return ret
+
+	self.fatal('There is no support for large files')
+
+########################################################################################
+
+ENDIAN_FRAGMENT = '''
+short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+int use_ascii (int i) {
+	return ascii_mm[i] + ascii_ii[i];
+}
+short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+int use_ebcdic (int i) {
+	return ebcdic_mm[i] + ebcdic_ii[i];
+}
+extern int foo;
+'''
+
+class grep_for_endianness(Task.Task):
+	color = 'PINK'
+	def run(self):
+		txt = self.inputs[0].read(flags='rb').decode('iso8859-1')
+		if txt.find('LiTTleEnDian') > -1:
+			self.generator.tmp.append('little')
+		elif txt.find('BIGenDianSyS') > -1:
+			self.generator.tmp.append('big')
+		else:
+			return -1
+
+ at feature('grep_for_endianness')
+ at after_method('process_source')
+def grep_for_endianness_fun(self):
+	self.create_task('grep_for_endianness', self.compiled_tasks[0].outputs[0])
+
+ at conf
+def check_endianness(self):
+	"""
+	Execute a configuration test to determine the endianness
+	"""
+	tmp = []
+	def check_msg(self):
+		return tmp[0]
+	self.check(fragment=ENDIAN_FRAGMENT, features='c grep_for_endianness', msg="Checking for endianness", define='ENDIANNESS', tmp=tmp, okmsg=check_msg)
+	return tmp[0]
+
diff --git a/xpdeint/waf/waflib/Tools/ccroot.py b/xpdeint/waf/waflib/Tools/ccroot.py
new file mode 100644
index 0000000..cfcca03
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/ccroot.py
@@ -0,0 +1,608 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005-2010 (ita)
+
+"""
+Classes and methods shared by tools providing support for C-like language such
+as C/C++/D/Assembly/Go (this support module is almost never used alone).
+"""
+
+import os, sys, re
+from waflib import TaskGen, Task, Utils, Logs, Build, Options, Node, Errors
+from waflib.Logs import error, debug, warn
+from waflib.TaskGen import after_method, before_method, feature, taskgen_method, extension
+from waflib.Tools import c_aliases, c_preproc, c_config, c_osx, c_tests
+from waflib.Configure import conf
+
+USELIB_VARS = Utils.defaultdict(set)
+"""
+Mapping for features to :py:class:`waflib.ConfigSet.ConfigSet` variables. See :py:func:`waflib.Tools.ccroot.propagate_uselib_vars`.
+"""
+
+USELIB_VARS['c']   = set(['INCLUDES', 'FRAMEWORKPATH', 'DEFINES', 'CPPFLAGS', 'CCDEPS', 'CFLAGS', 'ARCH'])
+USELIB_VARS['cxx'] = set(['INCLUDES', 'FRAMEWORKPATH', 'DEFINES', 'CPPFLAGS', 'CXXDEPS', 'CXXFLAGS', 'ARCH'])
+USELIB_VARS['d']   = set(['INCLUDES', 'DFLAGS'])
+
+USELIB_VARS['cprogram'] = USELIB_VARS['cxxprogram'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS', 'FRAMEWORK', 'FRAMEWORKPATH', 'ARCH'])
+USELIB_VARS['cshlib']   = USELIB_VARS['cxxshlib']   = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS', 'FRAMEWORK', 'FRAMEWORKPATH', 'ARCH'])
+USELIB_VARS['cstlib']   = USELIB_VARS['cxxstlib']   = set(['ARFLAGS', 'LINKDEPS'])
+
+USELIB_VARS['dprogram'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS'])
+USELIB_VARS['dshlib']   = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS'])
+USELIB_VARS['dstlib']   = set(['ARFLAGS', 'LINKDEPS'])
+
+USELIB_VARS['go'] = set(['GOCFLAGS'])
+USELIB_VARS['goprogram'] = set(['GOLFLAGS'])
+
+USELIB_VARS['asm'] = set(['ASFLAGS'])
+
+# =================================================================================================
+
+ at taskgen_method
+def create_compiled_task(self, name, node):
+	"""
+	Create the compilation task: c, cxx, asm, etc. The output node is created automatically (object file with a typical **.o** extension).
+	The task is appended to the list *compiled_tasks* which is then used by :py:func:`waflib.Tools.ccroot.apply_link`
+
+	:param name: name of the task class
+	:type name: string
+	:param node: the file to compile
+	:type node: :py:class:`waflib.Node.Node`
+	:return: The task created
+	:rtype: :py:class:`waflib.Task.Task`
+	"""
+	out = '%s.%d.o' % (node.name, self.idx)
+	task = self.create_task(name, node, node.parent.find_or_declare(out))
+	try:
+		self.compiled_tasks.append(task)
+	except AttributeError:
+		self.compiled_tasks = [task]
+	return task
+
+ at taskgen_method
+def to_incnodes(self, inlst):
+	"""
+	Task generator method provided to convert a list of string/nodes into a list of includes folders.
+
+	The paths are assumed to be relative to the task generator path, except if they begin by **#**
+	in which case they are searched from the top-level directory (``bld.srcnode``).
+	The folders are simply assumed to be existing.
+
+	The node objects in the list are returned in the output list. The strings are converted
+	into node objects if possible. The node is searched from the source directory, and if a match is found,
+	the equivalent build directory is created and added to the returned list too. When a folder cannot be found, it is ignored.
+
+	:param inlst: list of folders
+	:type inlst: space-delimited string or a list of string/nodes
+	:rtype: list of :py:class:`waflib.Node.Node`
+	:return: list of include folders as nodes
+	"""
+	lst = []
+	seen = set([])
+	for x in self.to_list(inlst):
+		if x in seen or not x:
+			continue
+		seen.add(x)
+
+		if isinstance(x, Node.Node):
+			lst.append(x)
+		else:
+			if os.path.isabs(x):
+				lst.append(self.bld.root.make_node(x) or x)
+			else:
+				if x[0] == '#':
+					p = self.bld.bldnode.make_node(x[1:])
+					v = self.bld.srcnode.make_node(x[1:])
+				else:
+					p = self.path.get_bld().make_node(x)
+					v = self.path.make_node(x)
+				if p.is_child_of(self.bld.bldnode):
+					p.mkdir()
+				lst.append(p)
+				lst.append(v)
+	return lst
+
+ at feature('c', 'cxx', 'd', 'go', 'asm', 'fc', 'includes')
+ at after_method('propagate_uselib_vars', 'process_source')
+def apply_incpaths(self):
+	"""
+	Task generator method that processes the attribute *includes*::
+
+		tg = bld(features='includes', includes='.')
+
+	The folders only need to be relative to the current directory, the equivalent build directory is
+	added automatically (for headers created in the build directory). This enable using a build directory
+	or not (``top == out``).
+
+	This method will add a list of nodes read by :py:func:`waflib.Tools.ccroot.to_incnodes` in ``tg.env.INCPATHS``,
+	and the list of include paths in ``tg.env.INCLUDES``.
+	"""
+
+	lst = self.to_incnodes(self.to_list(getattr(self, 'includes', [])) + self.env['INCLUDES'])
+	self.includes_nodes = lst
+	self.env['INCPATHS'] = [x.abspath() for x in lst]
+
+class link_task(Task.Task):
+	"""
+	Base class for all link tasks. A task generator is supposed to have at most one link task bound in the attribute *link_task*. See :py:func:`waflib.Tools.ccroot.apply_link`.
+
+	.. inheritance-diagram:: waflib.Tools.ccroot.stlink_task waflib.Tools.c.cprogram waflib.Tools.c.cshlib waflib.Tools.cxx.cxxstlib  waflib.Tools.cxx.cxxprogram waflib.Tools.cxx.cxxshlib waflib.Tools.d.dprogram waflib.Tools.d.dshlib waflib.Tools.d.dstlib waflib.Tools.ccroot.fake_shlib waflib.Tools.ccroot.fake_stlib waflib.Tools.asm.asmprogram waflib.Tools.asm.asmshlib waflib.Tools.asm.asmstlib
+	"""
+	color   = 'YELLOW'
+
+	inst_to = None
+	"""Default installation path for the link task outputs, or None to disable"""
+
+	chmod   = Utils.O644
+	"""Default installation mode for the link task outputs"""
+
+	def add_target(self, target):
+		"""
+		Process the *target* attribute to add the platform-specific prefix/suffix such as *.so* or *.exe*.
+		The settings are retrieved from ``env.clsname_PATTERN``
+		"""
+		if isinstance(target, str):
+			pattern = self.env[self.__class__.__name__ + '_PATTERN']
+			if not pattern:
+				pattern = '%s'
+			folder, name = os.path.split(target)
+
+			if self.__class__.__name__.find('shlib') > 0:
+				if self.env.DEST_BINFMT == 'pe' and getattr(self.generator, 'vnum', None):
+					# include the version in the dll file name,
+					# the import lib file name stays unversionned.
+					name = name + '-' + self.generator.vnum.split('.')[0]
+
+			tmp = folder + os.sep + pattern % name
+			target = self.generator.path.find_or_declare(tmp)
+		self.set_outputs(target)
+
+class stlink_task(link_task):
+	"""
+	Base for static link tasks, which use *ar* most of the time.
+	The target is always removed before being written.
+	"""
+	run_str = '${AR} ${ARFLAGS} ${AR_TGT_F}${TGT} ${AR_SRC_F}${SRC}'
+
+def rm_tgt(cls):
+	old = cls.run
+	def wrap(self):
+		try: os.remove(self.outputs[0].abspath())
+		except OSError: pass
+		return old(self)
+	setattr(cls, 'run', wrap)
+rm_tgt(stlink_task)
+
+ at feature('c', 'cxx', 'd', 'go', 'fc', 'asm')
+ at after_method('process_source')
+def apply_link(self):
+	"""
+	Collect the tasks stored in ``compiled_tasks`` (created by :py:func:`waflib.Tools.ccroot.create_compiled_task`), and
+	use the outputs for a new instance of :py:class:`waflib.Tools.ccroot.link_task`. The class to use is the first link task
+	matching a name from the attribute *features*, for example::
+
+			def build(bld):
+				tg = bld(features='cxx cxxprogram cprogram', source='main.c', target='app')
+
+	will create the task ``tg.link_task`` as a new instance of :py:class:`waflib.Tools.cxx.cxxprogram`
+	"""
+
+	for x in self.features:
+		if x == 'cprogram' and 'cxx' in self.features: # limited compat
+			x = 'cxxprogram'
+		elif x == 'cshlib' and 'cxx' in self.features:
+			x = 'cxxshlib'
+
+		if x in Task.classes:
+			if issubclass(Task.classes[x], link_task):
+				link = x
+				break
+	else:
+		return
+
+	objs = [t.outputs[0] for t in getattr(self, 'compiled_tasks', [])]
+	self.link_task = self.create_task(link, objs)
+	self.link_task.add_target(self.target)
+
+	# remember that the install paths are given by the task generators
+	# we need to define install_task even during the build phase because others might need the installation path
+	try:
+		inst_to = self.install_path
+	except AttributeError:
+		inst_to = self.link_task.__class__.inst_to
+	if inst_to:
+		# install a copy of the node list we have at this moment (implib not added)
+		self.install_task = self.bld.install_files(inst_to, self.link_task.outputs[:], env=self.env, chmod=self.link_task.chmod)
+
+ at taskgen_method
+def use_rec(self, name, **kw):
+	"""
+	Processes the ``use`` keyword recursively. This method is kind of private and only meant to be used from ``process_use``
+	"""
+
+	if name in self.tmp_use_not or name in self.tmp_use_seen:
+		return
+
+	try:
+		y = self.bld.get_tgen_by_name(name)
+	except Errors.WafError:
+		self.uselib.append(name)
+		self.tmp_use_not.add(name)
+		return
+
+	self.tmp_use_seen.append(name)
+	y.post()
+
+	# bind temporary attributes on the task generator
+	y.tmp_use_objects = objects = kw.get('objects', True)
+	y.tmp_use_stlib   = stlib   = kw.get('stlib', True)
+	try:
+		link_task = y.link_task
+	except AttributeError:
+		y.tmp_use_var = ''
+	else:
+		objects = False
+		if not isinstance(y.link_task, stlink_task):
+			stlib = False
+			y.tmp_use_var = 'LIB'
+		else:
+			y.tmp_use_var = 'STLIB'
+
+	p = self.tmp_use_prec
+	for x in self.to_list(getattr(y, 'use', [])):
+		try:
+			p[x].append(name)
+		except:
+			p[x] = [name]
+		self.use_rec(x, objects=objects, stlib=stlib)
+
+ at feature('c', 'cxx', 'd', 'use', 'fc')
+ at before_method('apply_incpaths', 'propagate_uselib_vars')
+ at after_method('apply_link', 'process_source')
+def process_use(self):
+	"""
+	Process the ``use`` attribute which contains a list of task generator names::
+
+		def build(bld):
+			bld.shlib(source='a.c', target='lib1')
+			bld.program(source='main.c', target='app', use='lib1')
+
+	See :py:func:`waflib.Tools.ccroot.use_rec`.
+	"""
+
+	use_not = self.tmp_use_not = set([])
+	use_seen = self.tmp_use_seen = [] # we would like an ordered set
+	use_prec = self.tmp_use_prec = {}
+	self.uselib = self.to_list(getattr(self, 'uselib', []))
+	self.includes = self.to_list(getattr(self, 'includes', []))
+	names = self.to_list(getattr(self, 'use', []))
+
+	for x in names:
+		self.use_rec(x)
+
+	for x in use_not:
+		if x in use_prec:
+			del use_prec[x]
+
+	# topological sort
+	out = []
+	tmp = []
+	for x in self.tmp_use_seen:
+		for k in use_prec.values():
+			if x in k:
+				break
+		else:
+			tmp.append(x)
+
+	while tmp:
+		e = tmp.pop()
+		out.append(e)
+		try:
+			nlst = use_prec[e]
+		except KeyError:
+			pass
+		else:
+			del use_prec[e]
+			for x in nlst:
+				for y in use_prec:
+					if x in use_prec[y]:
+						break
+				else:
+					tmp.append(x)
+	if use_prec:
+		raise Errors.WafError('Cycle detected in the use processing %r' % use_prec)
+	out.reverse()
+
+	link_task = getattr(self, 'link_task', None)
+	for x in out:
+		y = self.bld.get_tgen_by_name(x)
+		var = y.tmp_use_var
+		if var and link_task:
+			if var == 'LIB' or y.tmp_use_stlib:
+				self.env.append_value(var, [y.target[y.target.rfind(os.sep) + 1:]])
+				self.link_task.dep_nodes.extend(y.link_task.outputs)
+				tmp_path = y.link_task.outputs[0].parent.path_from(self.bld.bldnode)
+				self.env.append_value(var + 'PATH', [tmp_path])
+		else:
+			if y.tmp_use_objects:
+				self.add_objects_from_tgen(y)
+
+		if getattr(y, 'export_includes', None):
+			self.includes.extend(y.to_incnodes(y.export_includes))
+
+	# and finally, add the uselib variables (no recursion needed)
+	for x in names:
+		try:
+			y = self.bld.get_tgen_by_name(x)
+		except:
+			if not self.env['STLIB_' + x] and not x in self.uselib:
+				self.uselib.append(x)
+		else:
+			for k in self.to_list(getattr(y, 'uselib', [])):
+				if not self.env['STLIB_' + k] and not k in self.uselib:
+					self.uselib.append(k)
+
+ at taskgen_method
+def add_objects_from_tgen(self, tg):
+	# Not public yet, wait for waf 1.6.7 at least - the purpose of this is to add pdb files to the compiled
+	# tasks but not to the link tasks (to avoid errors)
+	try:
+		link_task = self.link_task
+	except AttributeError:
+		pass
+	else:
+		for tsk in getattr(tg, 'compiled_tasks', []):
+			for x in tsk.outputs:
+				if x.name.endswith('.o') or x.name.endswith('.obj'):
+					link_task.inputs.append(x)
+
+ at taskgen_method
+def get_uselib_vars(self):
+	"""
+	:return: the *uselib* variables associated to the *features* attribute (see :py:attr:`waflib.Tools.ccroot.USELIB_VARS`)
+	:rtype: list of string
+	"""
+	_vars = set([])
+	for x in self.features:
+		if x in USELIB_VARS:
+			_vars |= USELIB_VARS[x]
+	return _vars
+
+ at feature('c', 'cxx', 'd', 'fc', 'javac', 'cs', 'uselib')
+ at after_method('process_use')
+def propagate_uselib_vars(self):
+	"""
+	Process uselib variables for adding flags. For example, the following target::
+
+		def build(bld):
+			bld.env.AFLAGS_aaa = ['bar']
+			from waflib.Tools.ccroot import USELIB_VARS
+			USELIB_VARS['aaa'] = set('AFLAGS')
+
+			tg = bld(features='aaa', aflags='test')
+
+	The *aflags* attribute will be processed and this method will set::
+
+			tg.env.AFLAGS = ['bar', 'test']
+	"""
+	_vars = self.get_uselib_vars()
+	env = self.env
+
+	for x in _vars:
+		y = x.lower()
+		env.append_unique(x, self.to_list(getattr(self, y, [])))
+
+	for x in self.features:
+		for var in _vars:
+			compvar = '%s_%s' % (var, x)
+			env.append_value(var, env[compvar])
+
+	for x in self.to_list(getattr(self, 'uselib', [])):
+		for v in _vars:
+			env.append_value(v, env[v + '_' + x])
+
+# ============ the code above must not know anything about import libs ==========
+
+ at feature('cshlib', 'cxxshlib', 'fcshlib')
+ at after_method('apply_link')
+def apply_implib(self):
+	"""
+	Handle dlls and their import libs on Windows-like systems.
+
+	A ``.dll.a`` file called *import library* is generated.
+	It must be installed as it is required for linking the library.
+	"""
+	if not self.env.DEST_BINFMT == 'pe':
+		return
+
+	dll = self.link_task.outputs[0]
+	if isinstance(self.target, Node.Node):
+		name = self.target.name
+	else:
+		name = os.path.split(self.target)[1]
+	implib = self.env['implib_PATTERN'] % name
+	implib = dll.parent.find_or_declare(implib)
+	self.env.append_value('LINKFLAGS', self.env['IMPLIB_ST'] % implib.bldpath())
+	self.link_task.outputs.append(implib)
+
+	if getattr(self, 'defs', None) and self.env.DEST_BINFMT == 'pe':
+		node = self.path.find_resource(self.defs)
+		if not node:
+			raise Errors.WafError('invalid def file %r' % self.defs)
+		if 'msvc' in (self.env.CC_NAME, self.env.CXX_NAME):
+			self.env.append_value('LINKFLAGS', '/def:%s' % node.path_from(self.bld.bldnode))
+			self.link_task.dep_nodes.append(node)
+		else:
+			#gcc for windows takes *.def file a an input without any special flag
+			self.link_task.inputs.append(node)
+
+	try:
+		inst_to = self.install_path
+	except AttributeError:
+		inst_to = self.link_task.__class__.inst_to
+	if not inst_to:
+		return
+
+	self.implib_install_task = self.bld.install_as('${PREFIX}/lib/%s' % implib.name, implib, self.env)
+
+# ============ the code above must not know anything about vnum processing on unix platforms =========
+
+ at feature('cshlib', 'cxxshlib', 'dshlib', 'fcshlib', 'vnum')
+ at after_method('apply_link')
+def apply_vnum(self):
+	"""
+	Enforce version numbering on shared libraries. The valid version numbers must have at most two dots::
+
+		def build(bld):
+			bld.shlib(source='a.c', target='foo', vnum='14.15.16')
+
+	In this example, ``libfoo.so`` is installed as ``libfoo.so.1.2.3``, and the following symbolic links are created:
+
+	* ``libfoo.so   → libfoo.so.1.2.3``
+	* ``libfoo.so.1 → libfoo.so.1.2.3``
+	"""
+	if not getattr(self, 'vnum', '') or os.name != 'posix' or self.env.DEST_BINFMT not in ('elf', 'mac-o'):
+		return
+
+	link = self.link_task
+	nums = self.vnum.split('.')
+	node = link.outputs[0]
+
+	libname = node.name
+	if libname.endswith('.dylib'):
+		name3 = libname.replace('.dylib', '.%s.dylib' % self.vnum)
+		name2 = libname.replace('.dylib', '.%s.dylib' % nums[0])
+	else:
+		name3 = libname + '.' + self.vnum
+		name2 = libname + '.' + nums[0]
+
+	# add the so name for the ld linker - to disable, just unset env.SONAME_ST
+	if self.env.SONAME_ST:
+		v = self.env.SONAME_ST % name2
+		self.env.append_value('LINKFLAGS', v.split())
+
+	# the following task is just to enable execution from the build dir :-/
+	tsk = self.create_task('vnum', node, [node.parent.find_or_declare(name2), node.parent.find_or_declare(name3)])
+
+	if getattr(self.bld, 'is_install', None):
+		self.install_task.hasrun = Task.SKIP_ME
+		bld = self.bld
+		path = self.install_task.dest
+		t1 = bld.install_as(path + os.sep + name3, node, env=self.env)
+		t2 = bld.symlink_as(path + os.sep + name2, name3)
+		t3 = bld.symlink_as(path + os.sep + libname, name3)
+		self.vnum_install_task = (t1, t2, t3)
+
+	if '-dynamiclib' in self.env['LINKFLAGS'] and getattr(self, 'install_task', None):
+		path = os.path.join(self.install_task.get_install_path(), self.link_task.outputs[0].name)
+		self.env.append_value('LINKFLAGS', ['-install_name', path])
+
+class vnum(Task.Task):
+	"""
+	Create the symbolic links for a versioned shared library. Instances are created by :py:func:`waflib.Tools.ccroot.apply_vnum`
+	"""
+	color = 'CYAN'
+	quient = True
+	ext_in = ['.bin']
+	def run(self):
+		for x in self.outputs:
+			path = x.abspath()
+			try:
+				os.remove(path)
+			except OSError:
+				pass
+
+			try:
+				os.symlink(self.inputs[0].name, path)
+			except OSError:
+				return 1
+
+class fake_shlib(link_task):
+	"""
+	Task used for reading a system library and adding the dependency on it
+	"""
+	def runnable_status(self):
+		for t in self.run_after:
+			if not t.hasrun:
+				return Task.ASK_LATER
+
+		for x in self.outputs:
+			x.sig = Utils.h_file(x.abspath())
+		return Task.SKIP_ME
+
+class fake_stlib(stlink_task):
+	"""
+	Task used for reading a system library and adding the dependency on it
+	"""
+	def runnable_status(self):
+		for t in self.run_after:
+			if not t.hasrun:
+				return Task.ASK_LATER
+
+		for x in self.outputs:
+			x.sig = Utils.h_file(x.abspath())
+		return Task.SKIP_ME
+
+ at conf
+def read_shlib(self, name, paths=[]):
+	"""
+	Read a system shared library, enabling its use as a local library. Will trigger a rebuild if the file changes::
+
+		def build(bld):
+			bld.read_shlib('m')
+			bld.program(source='main.c', use='m')
+	"""
+	return self(name=name, features='fake_lib', lib_paths=paths, lib_type='shlib')
+
+ at conf
+def read_stlib(self, name, paths=[]):
+	"""
+	Read a system static library, enabling a use as a local library. Will trigger a rebuild if the file changes.
+	"""
+	return self(name=name, features='fake_lib', lib_paths=paths, lib_type='stlib')
+
+lib_patterns = {
+	'shlib' : ['lib%s.so', '%s.so', 'lib%s.dll', '%s.dll'],
+	'stlib' : ['lib%s.a', '%s.a', 'lib%s.dll', '%s.dll', 'lib%s.lib', '%s.lib'],
+}
+
+ at feature('fake_lib')
+def process_lib(self):
+	"""
+	Find the location of a foreign library. Used by :py:class:`waflib.Tools.ccroot.read_shlib` and :py:class:`waflib.Tools.ccroot.read_stlib`.
+	"""
+	node = None
+
+	names = [x % self.name for x in lib_patterns[self.lib_type]]
+	for x in self.lib_paths + [self.path, '/usr/lib64', '/usr/lib', '/usr/local/lib64', '/usr/local/lib']:
+		if not isinstance(x, Node.Node):
+			x = self.bld.root.find_node(x) or self.path.find_node(x)
+			if not x:
+				continue
+
+		for y in names:
+			node = x.find_node(y)
+			if node:
+				node.sig = Utils.h_file(node.abspath())
+				break
+		else:
+			continue
+		break
+	else:
+		raise Errors.WafError('could not find library %r' % self.name)
+	self.link_task = self.create_task('fake_%s' % self.lib_type, [], [node])
+	self.target = self.name
+
+
+class fake_o(Task.Task):
+	def runnable_status(self):
+		return Task.SKIP_ME
+
+ at extension('.o', '.obj')
+def add_those_o_files(self, node):
+	tsk = self.create_task('fake_o', [], node)
+	try:
+		self.compiled_tasks.append(tsk)
+	except AttributeError:
+		self.compiled_tasks = [tsk]
+
diff --git a/xpdeint/waf/waflib/Tools/compiler_c.py b/xpdeint/waf/waflib/Tools/compiler_c.py
new file mode 100644
index 0000000..7e9ed82
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/compiler_c.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Matthias Jahn jahn dôt matthias ât freenet dôt de, 2007 (pmarat)
+
+"""
+Try to detect a C compiler from the list of supported compilers (gcc, msvc, etc)::
+
+	def options(opt):
+		opt.load('compiler_c')
+	def configure(cnf):
+		cnf.load('compiler_c')
+	def build(bld):
+		bld.program(source='main.c', target='app')
+
+The compilers are associated to platforms in :py:attr:`waflib.Tools.compiler_c.c_compiler`. To register
+a new C compiler named *cfoo* (assuming the tool ``waflib/extras/cfoo.py`` exists), use::
+
+	def options(opt):
+		opt.load('compiler_c')
+	def configure(cnf):
+		from waflib.Tools.compiler_c import c_compiler
+		c_compiler['win32'] = ['cfoo', 'msvc', 'gcc']
+		cnf.load('compiler_c')
+	def build(bld):
+		bld.program(source='main.c', target='app')
+
+Not all compilers need to have a specific tool. For example, the clang compilers can be detected by the gcc tools when using::
+
+	$ CC=clang waf configure
+"""
+
+import os, sys, imp, types
+from waflib.Tools import ccroot
+from waflib import Utils, Configure
+from waflib.Logs import debug
+
+c_compiler = {
+'win32':  ['msvc', 'gcc'],
+'cygwin': ['gcc'],
+'darwin': ['gcc'],
+'aix':    ['xlc', 'gcc'],
+'linux':  ['gcc', 'icc'],
+'sunos':  ['suncc', 'gcc'],
+'irix':   ['gcc', 'irixcc'],
+'hpux':   ['gcc'],
+'gnu':    ['gcc'],
+'java':   ['gcc', 'msvc', 'icc'],
+'default':['gcc'],
+}
+"""
+Dict mapping the platform names to waf tools finding specific compilers::
+
+	from waflib.Tools.compiler_c import c_compiler
+	c_compiler['linux'] = ['gcc', 'icc', 'suncc']
+"""
+
+def configure(conf):
+	"""
+	Try to find a suitable C compiler or raise a :py:class:`waflib.Errors.ConfigurationError`.
+	"""
+	try: test_for_compiler = conf.options.check_c_compiler
+	except AttributeError: conf.fatal("Add options(opt): opt.load('compiler_c')")
+	for compiler in test_for_compiler.split():
+		conf.env.stash()
+		conf.start_msg('Checking for %r (c compiler)' % compiler)
+		try:
+			conf.load(compiler)
+		except conf.errors.ConfigurationError as e:
+			conf.env.revert()
+			conf.end_msg(False)
+			debug('compiler_c: %r' % e)
+		else:
+			if conf.env['CC']:
+				conf.end_msg(conf.env.get_flat('CC'))
+				conf.env['COMPILER_CC'] = compiler
+				break
+			conf.end_msg(False)
+	else:
+		conf.fatal('could not configure a c compiler!')
+
+def options(opt):
+	"""
+	Restrict the compiler detection from the command-line::
+
+		$ waf configure --check-c-compiler=gcc
+	"""
+	opt.load_special_tools('c_*.py', ban=['c_dumbpreproc.py'])
+	global c_compiler
+	build_platform = Utils.unversioned_sys_platform()
+	possible_compiler_list = c_compiler[build_platform in c_compiler and build_platform or 'default']
+	test_for_compiler = ' '.join(possible_compiler_list)
+	cc_compiler_opts = opt.add_option_group("C Compiler Options")
+	cc_compiler_opts.add_option('--check-c-compiler', default="%s" % test_for_compiler,
+		help='On this platform (%s) the following C-Compiler will be checked by default: "%s"' % (build_platform, test_for_compiler),
+		dest="check_c_compiler")
+	for x in test_for_compiler.split():
+		opt.load('%s' % x)
+
diff --git a/xpdeint/waf/waflib/Tools/compiler_cxx.py b/xpdeint/waf/waflib/Tools/compiler_cxx.py
new file mode 100644
index 0000000..3f3173f
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/compiler_cxx.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Matthias Jahn jahn dôt matthias ât freenet dôt de 2007 (pmarat)
+
+"""
+Try to detect a C++ compiler from the list of supported compilers (g++, msvc, etc)::
+
+	def options(opt):
+		opt.load('compiler_cxx')
+	def configure(cnf):
+		cnf.load('compiler_cxx')
+	def build(bld):
+		bld.program(source='main.cpp', target='app')
+
+The compilers are associated to platforms in :py:attr:`waflib.Tools.compiler_cxx.cxx_compiler`. To register
+a new C++ compiler named *cfoo* (assuming the tool ``waflib/extras/cfoo.py`` exists), use::
+
+	def options(opt):
+		opt.load('compiler_cxx')
+	def configure(cnf):
+		from waflib.Tools.compiler_cxx import cxx_compiler
+		cxx_compiler['win32'] = ['cfoo', 'msvc', 'gcc']
+		cnf.load('compiler_cxx')
+	def build(bld):
+		bld.program(source='main.c', target='app')
+
+Not all compilers need to have a specific tool. For example, the clang compilers can be detected by the gcc tools when using::
+
+	$ CXX=clang waf configure
+"""
+
+
+import os, sys, imp, types
+from waflib.Tools import ccroot
+from waflib import Utils, Configure
+from waflib.Logs import debug
+
+cxx_compiler = {
+'win32':  ['msvc', 'g++'],
+'cygwin': ['g++'],
+'darwin': ['g++'],
+'aix':    ['xlc++', 'g++'],
+'linux':  ['g++', 'icpc'],
+'sunos':  ['sunc++', 'g++'],
+'irix':   ['g++'],
+'hpux':   ['g++'],
+'gnu':    ['g++'],
+'java':   ['g++', 'msvc', 'icpc'],
+'default': ['g++']
+}
+"""
+Dict mapping the platform names to waf tools finding specific compilers::
+
+	from waflib.Tools.compiler_cxx import cxx_compiler
+	cxx_compiler['linux'] = ['gxx', 'icpc', 'suncxx']
+"""
+
+
+def configure(conf):
+	"""
+	Try to find a suitable C++ compiler or raise a :py:class:`waflib.Errors.ConfigurationError`.
+	"""
+	try: test_for_compiler = conf.options.check_cxx_compiler
+	except AttributeError: conf.fatal("Add options(opt): opt.load('compiler_cxx')")
+
+	for compiler in test_for_compiler.split():
+		conf.env.stash()
+		conf.start_msg('Checking for %r (c++ compiler)' % compiler)
+		try:
+			conf.load(compiler)
+		except conf.errors.ConfigurationError as e:
+			conf.env.revert()
+			conf.end_msg(False)
+			debug('compiler_cxx: %r' % e)
+		else:
+			if conf.env['CXX']:
+				conf.end_msg(conf.env.get_flat('CXX'))
+				conf.env['COMPILER_CXX'] = compiler
+				break
+			conf.end_msg(False)
+	else:
+		conf.fatal('could not configure a c++ compiler!')
+
+def options(opt):
+	"""
+	Restrict the compiler detection from the command-line::
+
+		$ waf configure --check-cxx-compiler=gxx
+	"""
+	opt.load_special_tools('cxx_*.py')
+	global cxx_compiler
+	build_platform = Utils.unversioned_sys_platform()
+	possible_compiler_list = cxx_compiler[build_platform in cxx_compiler and build_platform or 'default']
+	test_for_compiler = ' '.join(possible_compiler_list)
+	cxx_compiler_opts = opt.add_option_group('C++ Compiler Options')
+	cxx_compiler_opts.add_option('--check-cxx-compiler', default="%s" % test_for_compiler,
+		help='On this platform (%s) the following C++ Compiler will be checked by default: "%s"' % (build_platform, test_for_compiler),
+		dest="check_cxx_compiler")
+
+	for x in test_for_compiler.split():
+		opt.load('%s' % x)
+
diff --git a/xpdeint/waf/waflib/Tools/compiler_d.py b/xpdeint/waf/waflib/Tools/compiler_d.py
new file mode 100644
index 0000000..e7d4f2a
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/compiler_d.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Carlos Rafael Giani, 2007 (dv)
+# Thomas Nagy, 2010 (ita)
+
+"""
+Try to detect a D compiler from the list of supported compilers::
+
+	def options(opt):
+		opt.load('compiler_d')
+	def configure(cnf):
+		cnf.load('compiler_d')
+	def build(bld):
+		bld.program(source='main.d', target='app')
+
+Only two D compilers are really present at the moment:
+
+* gdc, the ldc compiler having a very similar command-line interface
+* dmd
+"""
+
+import os, sys, imp, types
+from waflib import Utils, Configure, Options, Logs
+
+def configure(conf):
+	"""
+	Try to find a suitable D compiler or raise a :py:class:`waflib.Errors.ConfigurationError`.
+	"""
+	for compiler in conf.options.dcheck.split(','):
+		conf.env.stash()
+		conf.start_msg('Checking for %r (d compiler)' % compiler)
+		try:
+			conf.load(compiler)
+		except conf.errors.ConfigurationError as e:
+			conf.env.revert()
+			conf.end_msg(False)
+			Logs.debug('compiler_cxx: %r' % e)
+		else:
+			if conf.env.D:
+				conf.end_msg(conf.env.get_flat('D'))
+				conf.env['COMPILER_D'] = compiler
+				conf.env.D_COMPILER = conf.env.D # TODO remove this, left for compatibility
+				break
+			conf.end_msg(False)
+	else:
+		conf.fatal('no suitable d compiler was found')
+
+def options(opt):
+	"""
+	Restrict the compiler detection from the command-line::
+
+		$ waf configure --check-d-compiler=dmd
+	"""
+	d_compiler_opts = opt.add_option_group('D Compiler Options')
+	d_compiler_opts.add_option('--check-d-compiler', default='gdc,dmd', action='store',
+		help='check for the compiler [Default:gdc,dmd]', dest='dcheck')
+	for d_compiler in ['gdc', 'dmd']:
+		opt.load('%s' % d_compiler)
+
diff --git a/xpdeint/waf/waflib/Tools/compiler_fc.py b/xpdeint/waf/waflib/Tools/compiler_fc.py
new file mode 100644
index 0000000..f2730f8
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/compiler_fc.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+import os, sys, imp, types
+from waflib import Utils, Configure, Options, Logs, Errors
+from waflib.Tools import fc
+
+fc_compiler = {
+	'win32'  : ['gfortran','ifort'],
+	'darwin' : ['gfortran', 'g95', 'ifort'],
+	'linux'  : ['gfortran', 'g95', 'ifort'],
+	'java'   : ['gfortran', 'g95', 'ifort'],
+	'default': ['gfortran'],
+	'aix'    : ['gfortran']
+}
+
+def __list_possible_compiler(platform):
+	try:
+		return fc_compiler[platform]
+	except KeyError:
+		return fc_compiler["default"]
+
+def configure(conf):
+	"""
+	Try to find a suitable Fortran compiler or raise a :py:class:`waflib.Errors.ConfigurationError`.
+	"""
+	try: test_for_compiler = conf.options.check_fc
+	except AttributeError: conf.fatal("Add options(opt): opt.load('compiler_fc')")
+	orig = conf.env
+	for compiler in test_for_compiler.split():
+		try:
+			conf.start_msg('Checking for %r (fortran compiler)' % compiler)
+			conf.env = orig.derive()
+			conf.load(compiler)
+		except conf.errors.ConfigurationError as e:
+			conf.end_msg(False)
+			Logs.debug('compiler_fortran: %r' % e)
+		else:
+			if conf.env['FC']:
+				orig.table = conf.env.get_merged_dict()
+				conf.env = orig
+				conf.end_msg(conf.env.get_flat('FC'))
+				conf.env.COMPILER_FORTRAN = compiler
+				break
+			conf.end_msg(False)
+	else:
+		conf.fatal('could not configure a fortran compiler!')
+
+def options(opt):
+	"""
+	Restrict the compiler detection from the command-line::
+
+		$ waf configure --check-fortran-compiler=ifort
+	"""
+	opt.load_special_tools('fc_*.py')
+	build_platform = Utils.unversioned_sys_platform()
+	detected_platform = Options.platform
+	possible_compiler_list = __list_possible_compiler(detected_platform)
+	test_for_compiler = ' '.join(possible_compiler_list)
+	fortran_compiler_opts = opt.add_option_group("Fortran Compiler Options")
+	fortran_compiler_opts.add_option('--check-fortran-compiler',
+			default="%s" % test_for_compiler,
+			help='On this platform (%s) the following Fortran Compiler will be checked by default: "%s"' % (detected_platform, test_for_compiler),
+		dest="check_fc")
+
+	for compiler in test_for_compiler.split():
+		opt.load('%s' % compiler)
+
diff --git a/xpdeint/waf/waflib/Tools/cs.py b/xpdeint/waf/waflib/Tools/cs.py
new file mode 100644
index 0000000..4a615d8
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/cs.py
@@ -0,0 +1,178 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+
+"""
+C# support. A simple example::
+
+	def configure(conf):
+		conf.load('cs')
+	def build(bld):
+		bld(features='cs', source='main.cs', gen='foo')
+
+Note that the configuration may compile C# snippets::
+
+	FRAG = '''
+	namespace Moo {
+		public class Test { public static int Main(string[] args) { return 0; } }
+	}'''
+	def configure(conf):
+		conf.check(features='cs', fragment=FRAG, compile_filename='test.cs', gen='test.exe',
+			type='exe', csflags=['-pkg:gtk-sharp-2.0'], msg='Checking for Gtksharp support')
+"""
+
+from waflib import Utils, Task, Options, Logs, Errors
+from waflib.TaskGen import before_method, after_method, feature
+from waflib.Tools import ccroot
+from waflib.Configure import conf
+
+ccroot.USELIB_VARS['cs'] = set(['CSFLAGS', 'ASSEMBLIES', 'RESOURCES'])
+ccroot.lib_patterns['csshlib'] = ['%s']
+
+ at feature('cs')
+ at before_method('process_source')
+def apply_cs(self):
+	"""
+	Create a C# task bound to the attribute *cs_task*. There can be only one C# task by task generator.
+	"""
+	cs_nodes = []
+	no_nodes = []
+	for x in self.to_nodes(self.source):
+		if x.name.endswith('.cs'):
+			cs_nodes.append(x)
+		else:
+			no_nodes.append(x)
+	self.source = no_nodes
+
+	bintype = getattr(self, 'type', self.gen.endswith('.dll') and 'library' or 'exe')
+	self.cs_task = tsk = self.create_task('mcs', cs_nodes, self.path.find_or_declare(self.gen))
+	tsk.env.CSTYPE = '/target:%s' % bintype
+	tsk.env.OUT    = '/out:%s' % tsk.outputs[0].abspath()
+
+	inst_to = getattr(self, 'install_path', bintype=='exe' and '${BINDIR}' or '${LIBDIR}')
+	if inst_to:
+		# note: we are making a copy, so the files added to cs_task.outputs won't be installed automatically
+		mod = getattr(self, 'chmod', bintype=='exe' and Utils.O755 or Utils.O644)
+		self.install_task = self.bld.install_files(inst_to, self.cs_task.outputs[:], env=self.env, chmod=mod)
+
+ at feature('cs')
+ at after_method('apply_cs')
+def use_cs(self):
+	"""
+	C# applications honor the **use** keyword::
+
+		def build(bld):
+			bld(features='cs', source='My.cs', type='library', gen='my.dll', name='mylib')
+			bld(features='cs', source='Hi.cs', includes='.', type='exe', gen='hi.exe', use='mylib', name='hi')
+	"""
+	names = self.to_list(getattr(self, 'use', []))
+	get = self.bld.get_tgen_by_name
+	for x in names:
+		try:
+			y = get(x)
+		except Errors.WafError:
+			self.cs_task.env.append_value('CSFLAGS', '/reference:%s' % x)
+			continue
+		y.post()
+
+		tsk = getattr(y, 'cs_task', None) or getattr(y, 'link_task', None)
+		if not tsk:
+			self.bld.fatal('cs task has no link task for use %r' % self)
+		self.cs_task.dep_nodes.extend(tsk.outputs) # dependency
+		self.cs_task.set_run_after(tsk) # order (redundant, the order is infered from the nodes inputs/outputs)
+		self.cs_task.env.append_value('CSFLAGS', '/reference:%s' % tsk.outputs[0].abspath())
+
+ at feature('cs')
+ at after_method('apply_cs', 'use_cs')
+def debug_cs(self):
+	"""
+	The C# targets may create .mdb or .pdb files::
+
+		def build(bld):
+			bld(features='cs', source='My.cs', type='library', gen='my.dll', csdebug='full')
+			# csdebug is a value in [True, 'full', 'pdbonly']
+	"""
+	csdebug = getattr(self, 'csdebug', self.env.CSDEBUG)
+	if not csdebug:
+		return
+
+	node = self.cs_task.outputs[0]
+	if self.env.CS_NAME == 'mono':
+		out = node.parent.find_or_declare(node.name + '.mdb')
+	else:
+		out = node.change_ext('.pdb')
+	self.cs_task.outputs.append(out)
+	try:
+		self.install_task.source.append(out)
+	except AttributeError:
+		pass
+
+	if csdebug == 'pdbonly':
+		val = ['/debug+', '/debug:pdbonly']
+	elif csdebug == 'full':
+		val = ['/debug+', '/debug:full']
+	else:
+		val = ['/debug-']
+	self.cs_task.env.append_value('CSFLAGS', val)
+
+
+class mcs(Task.Task):
+	"""
+	Compile C# files
+	"""
+	color   = 'YELLOW'
+	run_str = '${MCS} ${CSTYPE} ${CSFLAGS} ${ASS_ST:ASSEMBLIES} ${RES_ST:RESOURCES} ${OUT} ${SRC}'
+
+def configure(conf):
+	"""
+	Find a C# compiler, set the variable MCS for the compiler and CS_NAME (mono or csc)
+	"""
+	csc = getattr(Options.options, 'cscbinary', None)
+	if csc:
+		conf.env.MCS = csc
+	conf.find_program(['csc', 'mcs', 'gmcs'], var='MCS')
+	conf.env.ASS_ST = '/r:%s'
+	conf.env.RES_ST = '/resource:%s'
+
+	conf.env.CS_NAME = 'csc'
+	if str(conf.env.MCS).lower().find('mcs') > -1:
+		conf.env.CS_NAME = 'mono'
+
+def options(opt):
+	"""
+	Add a command-line option for the configuration::
+
+		$ waf configure --with-csc-binary=/foo/bar/mcs
+	"""
+	opt.add_option('--with-csc-binary', type='string', dest='cscbinary')
+
+class fake_csshlib(Task.Task):
+	"""
+	Task used for reading a foreign .net assembly and adding the dependency on it
+	"""
+	color   = 'YELLOW'
+	inst_to = None
+
+	def runnable_status(self):
+		for x in self.outputs:
+			x.sig = Utils.h_file(x.abspath())
+		return Task.SKIP_ME
+
+ at conf
+def read_csshlib(self, name, paths=[]):
+	"""
+	Read a foreign .net assembly for the *use* system::
+
+		def build(bld):
+			bld.read_csshlib('ManagedLibrary.dll', paths=[bld.env.mylibrarypath])
+			bld(features='cs', source='Hi.cs', type='exe', gen='hi.exe', use='ManagedLibrary.dll')
+
+	:param name: Name of the library
+	:type name: string
+	:param paths: Folders in which the library may be found
+	:type paths: list of string
+	:return: A task generator having the feature *fake_lib* which will call :py:func:`waflib.Tools.ccroot.process_lib`
+	:rtype: :py:class:`waflib.TaskGen.task_gen`
+	"""
+	return self(name=name, features='fake_lib', lib_paths=paths, lib_type='csshlib')
+
diff --git a/xpdeint/waf/waflib/Tools/cxx.py b/xpdeint/waf/waflib/Tools/cxx.py
new file mode 100644
index 0000000..f4960e4
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/cxx.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005-2010 (ita)
+
+"Base for c++ programs and libraries"
+
+from waflib import TaskGen, Task, Utils
+from waflib.Tools import c_preproc
+from waflib.Tools.ccroot import link_task, stlink_task
+
+def cxx_hook(self, node):
+	"Bind the c++ file extensions to the creation of a :py:class:`waflib.Tools.cxx.cxx` instance"
+	return self.create_compiled_task('cxx', node)
+TaskGen.extension('.cpp','.cc','.cxx','.C','.c++')(cxx_hook) # leave like this for python 2.3
+
+if not '.c' in TaskGen.task_gen.mappings:
+	TaskGen.task_gen.mappings['.c'] = TaskGen.task_gen.mappings['.cpp']
+
+class cxx(Task.Task):
+	"Compile C++ files into object files"
+	run_str = '${CXX} ${ARCH_ST:ARCH} ${CXXFLAGS} ${CPPFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CXX_SRC_F} ${SRC} ${CXX_TGT_F} ${TGT}'
+	vars    = ['CXXDEPS'] # unused variable to depend on, just in case
+	ext_in  = ['.h'] # set the build order easily by using ext_out=['.h']
+	scan    = c_preproc.scan
+	shell   = True
+
+class cxxprogram(link_task):
+	"Link object files into a c++ program"
+	run_str = '${LINK_CXX} ${LINKFLAGS} ${CXXLNK_SRC_F} ${SRC} ${CXXLNK_TGT_F} ${TGT[0].abspath()} ${RPATH_ST:RPATH} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${FRAMEWORK_ST:FRAMEWORK} ${ARCH_ST:ARCH} ${STLIB_MARKER} ${STLIBPATH_ST:STLIBPATH} ${STLIB_ST:STLIB} ${SHLIB_MARKER} ${LIBPATH_ST:LIBPATH} ${LIB_ST:LIB} ${FINAL_LINK_VAR}'
+	vars    = ['LINKDEPS']
+	ext_out = ['.bin']
+	inst_to = '${BINDIR}'
+	chmod   = Utils.O755
+	shell   = True
+
+class cxxshlib(cxxprogram):
+	"Link object files into a c++ shared library"
+	inst_to = '${LIBDIR}'
+
+class cxxstlib(stlink_task):
+	"Link object files into a c++ static library"
+	pass # do not remove
+
diff --git a/xpdeint/waf/waflib/Tools/d.py b/xpdeint/waf/waflib/Tools/d.py
new file mode 100644
index 0000000..0b006c7
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/d.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Carlos Rafael Giani, 2007 (dv)
+# Thomas Nagy, 2007-2010 (ita)
+
+from waflib import Utils, Task, Errors
+from waflib.TaskGen import taskgen_method, feature, extension
+from waflib.Tools import d_scan, d_config
+from waflib.Tools.ccroot import link_task, stlink_task
+
+class d(Task.Task):
+	"Compile a d file into an object file"
+	color   = 'GREEN'
+	run_str = '${D} ${DFLAGS} ${DINC_ST:INCPATHS} ${D_SRC_F:SRC} ${D_TGT_F:TGT}'
+	scan    = d_scan.scan
+
+class d_with_header(d):
+	"Compile a d file and generate a header"
+	run_str = '${D} ${DFLAGS} ${DINC_ST:INCPATHS} ${D_HDR_F:tgt.outputs[1].bldpath()} ${D_SRC_F:SRC} ${D_TGT_F:tgt.outputs[0].bldpath()}'
+
+class d_header(Task.Task):
+	"Compile d headers"
+	color   = 'BLUE'
+	run_str = '${D} ${D_HEADER} ${SRC}'
+
+class dprogram(link_task):
+	"Link object files into a d program"
+	run_str = '${D_LINKER} ${LINKFLAGS} ${DLNK_SRC_F}${SRC} ${DLNK_TGT_F:TGT} ${RPATH_ST:RPATH} ${DSTLIB_MARKER} ${DSTLIBPATH_ST:STLIBPATH} ${DSTLIB_ST:STLIB} ${DSHLIB_MARKER} ${DLIBPATH_ST:LIBPATH} ${DSHLIB_ST:LIB}'
+	inst_to = '${BINDIR}'
+	chmod   = Utils.O755
+
+class dshlib(dprogram):
+	"Link object files into a d shared library"
+	inst_to = '${LIBDIR}'
+
+class dstlib(stlink_task):
+	"Link object files into a d static library"
+	pass # do not remove
+
+ at extension('.d', '.di', '.D')
+def d_hook(self, node):
+	"""
+	Compile *D* files. To get .di files as well as .o files, set the following::
+
+		def build(bld):
+			bld.program(source='foo.d', target='app', generate_headers=True)
+
+	"""
+	if getattr(self, 'generate_headers', None):
+		task = self.create_compiled_task('d_with_header', node)
+		header_node = node.change_ext(self.env['DHEADER_ext'])
+		task.outputs.append(header_node)
+	else:
+		task = self.create_compiled_task('d', node)
+	return task
+
+ at taskgen_method
+def generate_header(self, filename, install_path=None):
+	"""
+	See feature request #104::
+
+		def build(bld):
+			tg = bld.program(source='foo.d', target='app')
+			tg.generate_header('blah.d')
+			# is equivalent to:
+			#tg = bld.program(source='foo.d', target='app', header_lst='blah.d')
+
+	:param filename: header to create
+	:type filename: string
+	:param install_path: unused (TODO)
+	"""
+	try:
+		self.header_lst.append([filename, install_path])
+	except AttributeError:
+		self.header_lst = [[filename, install_path]]
+
+ at feature('d')
+def process_header(self):
+	"""
+	Process the attribute 'header_lst' to create the d header compilation tasks::
+
+		def build(bld):
+			bld.program(source='foo.d', target='app', header_lst='blah.d')
+	"""
+	for i in getattr(self, 'header_lst', []):
+		node = self.path.find_resource(i[0])
+		if not node:
+			raise Errors.WafError('file %r not found on d obj' % i[0])
+		self.create_task('d_header', node, node.change_ext('.di'))
+
diff --git a/xpdeint/waf/waflib/Tools/d_config.py b/xpdeint/waf/waflib/Tools/d_config.py
new file mode 100644
index 0000000..a2f8e4e
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/d_config.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2010 (ita)
+
+from waflib import Utils
+from waflib.Configure import conf
+
+ at conf
+def d_platform_flags(self):
+	"""
+	Set the extensions dll/so for d programs and libraries
+	"""
+	v = self.env
+	if not v.DEST_OS:
+		v.DEST_OS = Utils.unversioned_sys_platform()
+	if Utils.destos_to_binfmt(self.env.DEST_OS) == 'pe':
+		v['dprogram_PATTERN'] = '%s.exe'
+		v['dshlib_PATTERN']   = 'lib%s.dll'
+		v['dstlib_PATTERN']   = 'lib%s.a'
+	else:
+		v['dprogram_PATTERN'] = '%s'
+		v['dshlib_PATTERN']   = 'lib%s.so'
+		v['dstlib_PATTERN']   = 'lib%s.a'
+
+DLIB = '''
+version(D_Version2) {
+	import std.stdio;
+	int main() {
+		writefln("phobos2");
+		return 0;
+	}
+} else {
+	version(Tango) {
+		import tango.stdc.stdio;
+		int main() {
+			printf("tango");
+			return 0;
+		}
+	} else {
+		import std.stdio;
+		int main() {
+			writefln("phobos1");
+			return 0;
+		}
+	}
+}
+'''
+"""Detection string for the D standard library"""
+
+ at conf
+def check_dlibrary(self):
+	"""
+	Detect the kind of standard library that comes with the compiler, will set conf.env.DLIBRARY to tango, phobos1 or phobos2.
+	"""
+	ret = self.check_cc(features='d dprogram', fragment=DLIB, compile_filename='test.d', execute=True, define_ret=True)
+	self.env.DLIBRARY = ret.strip()
+
diff --git a/xpdeint/waf/waflib/Tools/d_scan.py b/xpdeint/waf/waflib/Tools/d_scan.py
new file mode 100644
index 0000000..dc4049e
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/d_scan.py
@@ -0,0 +1,209 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2010 (ita)
+
+"""
+Provide a scanner for finding dependencies on d files
+"""
+
+import re
+from waflib import Utils, Logs
+
+def filter_comments(filename):
+	"""
+	:param filename: d file name
+	:type filename: string
+	:rtype: list
+	:return: a list of characters
+	"""
+	txt = Utils.readf(filename)
+	i = 0
+	buf = []
+	max = len(txt)
+	begin = 0
+	while i < max:
+		c = txt[i]
+		if c == '"' or c == "'":  # skip a string or character literal
+			buf.append(txt[begin:i])
+			delim = c
+			i += 1
+			while i < max:
+				c = txt[i]
+				if c == delim: break
+				elif c == '\\':  # skip the character following backslash
+					i += 1
+				i += 1
+			i += 1
+			begin = i
+		elif c == '/':  # try to replace a comment with whitespace
+			buf.append(txt[begin:i])
+			i += 1
+			if i == max: break
+			c = txt[i]
+			if c == '+':  # eat nesting /+ +/ comment
+				i += 1
+				nesting = 1
+				c = None
+				while i < max:
+					prev = c
+					c = txt[i]
+					if prev == '/' and c == '+':
+						nesting += 1
+						c = None
+					elif prev == '+' and c == '/':
+						nesting -= 1
+						if nesting == 0: break
+						c = None
+					i += 1
+			elif c == '*':  # eat /* */ comment
+				i += 1
+				c = None
+				while i < max:
+					prev = c
+					c = txt[i]
+					if prev == '*' and c == '/': break
+					i += 1
+			elif c == '/':  # eat // comment
+				i += 1
+				while i < max and txt[i] != '\n':
+					i += 1
+			else:  # no comment
+				begin = i - 1
+				continue
+			i += 1
+			begin = i
+			buf.append(' ')
+		else:
+			i += 1
+	buf.append(txt[begin:])
+	return buf
+
+class d_parser(object):
+	"""
+	Parser for d files
+	"""
+	def __init__(self, env, incpaths):
+		#self.code = ''
+		#self.module = ''
+		#self.imports = []
+
+		self.allnames = []
+
+		self.re_module = re.compile("module\s+([^;]+)")
+		self.re_import = re.compile("import\s+([^;]+)")
+		self.re_import_bindings = re.compile("([^:]+):(.*)")
+		self.re_import_alias = re.compile("[^=]+=(.+)")
+
+		self.env = env
+
+		self.nodes = []
+		self.names = []
+
+		self.incpaths = incpaths
+
+	def tryfind(self, filename):
+		"""
+		Search file a file matching an module/import directive
+
+		:param filename: file to read
+		:type filename: string
+		"""
+		found = 0
+		for n in self.incpaths:
+			found = n.find_resource(filename.replace('.', '/') + '.d')
+			if found:
+				self.nodes.append(found)
+				self.waiting.append(found)
+				break
+		if not found:
+			if not filename in self.names:
+				self.names.append(filename)
+
+	def get_strings(self, code):
+		"""
+		:param code: d code to parse
+		:type code: string
+		:return: the modules that the code uses
+		:rtype: a list of match objects
+		"""
+		#self.imports = []
+		self.module = ''
+		lst = []
+
+		# get the module name (if present)
+
+		mod_name = self.re_module.search(code)
+		if mod_name:
+			self.module = re.sub('\s+', '', mod_name.group(1)) # strip all whitespaces
+
+		# go through the code, have a look at all import occurrences
+
+		# first, lets look at anything beginning with "import" and ending with ";"
+		import_iterator = self.re_import.finditer(code)
+		if import_iterator:
+			for import_match in import_iterator:
+				import_match_str = re.sub('\s+', '', import_match.group(1)) # strip all whitespaces
+
+				# does this end with an import bindings declaration?
+				# (import bindings always terminate the list of imports)
+				bindings_match = self.re_import_bindings.match(import_match_str)
+				if bindings_match:
+					import_match_str = bindings_match.group(1)
+					# if so, extract the part before the ":" (since the module declaration(s) is/are located there)
+
+				# split the matching string into a bunch of strings, separated by a comma
+				matches = import_match_str.split(',')
+
+				for match in matches:
+					alias_match = self.re_import_alias.match(match)
+					if alias_match:
+						# is this an alias declaration? (alias = module name) if so, extract the module name
+						match = alias_match.group(1)
+
+					lst.append(match)
+		return lst
+
+	def start(self, node):
+		"""
+		The parsing starts here
+
+		:param node: input file
+		:type node: :py:class:`waflib.Node.Node`
+		"""
+		self.waiting = [node]
+		# while the stack is not empty, add the dependencies
+		while self.waiting:
+			nd = self.waiting.pop(0)
+			self.iter(nd)
+
+	def iter(self, node):
+		"""
+		Find all the modules that a file depends on, uses :py:meth:`waflib.Tools.d_scan.d_parser.tryfind` to process dependent files
+
+		:param node: input file
+		:type node: :py:class:`waflib.Node.Node`
+		"""
+		path = node.abspath() # obtain the absolute path
+		code = "".join(filter_comments(path)) # read the file and filter the comments
+		names = self.get_strings(code) # obtain the import strings
+		for x in names:
+			# optimization
+			if x in self.allnames: continue
+			self.allnames.append(x)
+
+			# for each name, see if it is like a node or not
+			self.tryfind(x)
+
+def scan(self):
+	"look for .d/.di used by a d file"
+	env = self.env
+	gruik = d_parser(env, self.generator.includes_nodes)
+	node = self.inputs[0]
+	gruik.start(node)
+	nodes = gruik.nodes
+	names = gruik.names
+
+	if Logs.verbose:
+		Logs.debug('deps: deps for %s: %r; unresolved %r' % (str(node), nodes, names))
+	return (nodes, names)
+
diff --git a/xpdeint/waf/waflib/Tools/dbus.py b/xpdeint/waf/waflib/Tools/dbus.py
new file mode 100644
index 0000000..b460633
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/dbus.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Ali Sabil, 2007
+
+"""
+Compile dbus files with **dbus-binding-tool**
+
+Typical usage::
+
+	def options(opt):
+		opt.load('compiler_c dbus')
+	def configure(conf):
+		conf.load('compiler_c dbus')
+	def build(bld):
+		tg = bld.program(
+			includes = '.',
+			source = bld.path.ant_glob('*.c'),
+			target = 'gnome-hello')
+		tg.add_dbus_file('test.xml', 'test_prefix', 'glib-server')
+"""
+
+from waflib import Task, Errors
+from waflib.TaskGen import taskgen_method, before_method
+
+ at taskgen_method
+def add_dbus_file(self, filename, prefix, mode):
+	"""
+	Add a dbus file to the list of dbus files to process. Store them in the attribute *dbus_lst*.
+
+	:param filename: xml file to compile
+	:type filename: string
+	:param prefix: dbus binding tool prefix (--prefix=prefix)
+	:type prefix: string
+	:param mode: dbus binding tool mode (--mode=mode)
+	:type mode: string
+	"""
+	if not hasattr(self, 'dbus_lst'):
+		self.dbus_lst = []
+	if not 'process_dbus' in self.meths:
+		self.meths.append('process_dbus')
+	self.dbus_lst.append([filename, prefix, mode])
+
+ at before_method('apply_core')
+def process_dbus(self):
+	"""
+	Process the dbus files stored in the attribute *dbus_lst* to create :py:class:`waflib.Tools.dbus.dbus_binding_tool` instances.
+	"""
+	for filename, prefix, mode in getattr(self, 'dbus_lst', []):
+		node = self.path.find_resource(filename)
+		if not node:
+			raise Errors.WafError('file not found ' + filename)
+		tsk = self.create_task('dbus_binding_tool', node, node.change_ext('.h'))
+		tsk.env.DBUS_BINDING_TOOL_PREFIX = prefix
+		tsk.env.DBUS_BINDING_TOOL_MODE   = mode
+
+class dbus_binding_tool(Task.Task):
+	"""
+	Compile a dbus file
+	"""
+	color   = 'BLUE'
+	ext_out = ['.h']
+	run_str = '${DBUS_BINDING_TOOL} --prefix=${DBUS_BINDING_TOOL_PREFIX} --mode=${DBUS_BINDING_TOOL_MODE} --output=${TGT} ${SRC}'
+	shell   = True # temporary workaround for #795
+
+def configure(conf):
+	"""
+	Detect the program dbus-binding-tool and set the *conf.env.DBUS_BINDING_TOOL*
+	"""
+	dbus_binding_tool = conf.find_program('dbus-binding-tool', var='DBUS_BINDING_TOOL')
+
diff --git a/xpdeint/waf/waflib/Tools/dmd.py b/xpdeint/waf/waflib/Tools/dmd.py
new file mode 100644
index 0000000..c2f3896
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/dmd.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Carlos Rafael Giani, 2007 (dv)
+# Thomas Nagy, 2008-2010 (ita)
+
+import sys
+from waflib.Tools import ar, d
+from waflib.Configure import conf
+
+ at conf
+def find_dmd(conf):
+	"""
+	Find the program *dmd* or *ldc* and set the variable *D*
+	"""
+	conf.find_program(['dmd', 'ldc'], var='D')
+
+ at conf
+def common_flags_ldc(conf):
+	"""
+	Set the D flags required by *ldc*
+	"""
+	v = conf.env
+	v['DFLAGS']        = ['-d-version=Posix']
+	v['LINKFLAGS']     = []
+	v['DFLAGS_dshlib'] = ['-relocation-model=pic']
+
+ at conf
+def common_flags_dmd(conf):
+	"""
+	Set the flags required by *dmd*
+	"""
+
+	v = conf.env
+
+	# _DFLAGS _DIMPORTFLAGS
+
+	# Compiler is dmd so 'gdc' part will be ignored, just
+	# ensure key is there, so wscript can append flags to it
+	#v['DFLAGS']            = ['-version=Posix']
+
+	v['D_SRC_F']           = ['-c']
+	v['D_TGT_F']           = '-of%s'
+
+	# linker
+	v['D_LINKER']          = v['D']
+	v['DLNK_SRC_F']        = ''
+	v['DLNK_TGT_F']        = '-of%s'
+	v['DINC_ST']           = '-I%s'
+
+	v['DSHLIB_MARKER'] = v['DSTLIB_MARKER'] = ''
+	v['DSTLIB_ST'] = v['DSHLIB_ST']         = '-L-l%s'
+	v['DSTLIBPATH_ST'] = v['DLIBPATH_ST']   = '-L-L%s'
+
+	v['LINKFLAGS_dprogram']= ['-quiet']
+
+	v['DFLAGS_dshlib']     = ['-fPIC']
+	v['LINKFLAGS_dshlib']  = ['-L-shared']
+
+	v['DHEADER_ext']       = '.di'
+	v.DFLAGS_d_with_header = ['-H', '-Hf']
+	v['D_HDR_F']           = '%s'
+
+def configure(conf):
+	"""
+	Configuration for dmd/ldc
+	"""
+	conf.find_dmd()
+
+	if sys.platform == 'win32':
+		out = conf.cmd_and_log([conf.env.D, '--help'])
+		if out.find("D Compiler v2.") > -1:
+			conf.fatal('dmd2 on Windows is not supported, use gdc or ldc instead')
+
+	conf.load('ar')
+	conf.load('d')
+	conf.common_flags_dmd()
+	conf.d_platform_flags()
+
+	if str(conf.env.D).find('ldc') > -1:
+		conf.common_flags_ldc()
+
diff --git a/xpdeint/waf/waflib/Tools/errcheck.py b/xpdeint/waf/waflib/Tools/errcheck.py
new file mode 100644
index 0000000..6b7c960
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/errcheck.py
@@ -0,0 +1,211 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2011 (ita)
+
+"""
+errheck: Search for common mistakes
+
+There is a performance hit, so this tool is only loaded when running "waf -v"
+"""
+
+typos = {
+'feature':'features',
+'sources':'source',
+'targets':'target',
+'include':'includes',
+'export_include':'export_includes',
+'define':'defines',
+'importpath':'includes',
+'installpath':'install_path',
+}
+
+meths_typos = ['__call__', 'program', 'shlib', 'stlib', 'objects']
+
+from waflib import Logs, Build, Node, Task, TaskGen, ConfigSet, Errors, Utils
+import waflib.Tools.ccroot
+
+def check_same_targets(self):
+	mp = Utils.defaultdict(list)
+	uids = {}
+
+	def check_task(tsk):
+		if not isinstance(tsk, Task.Task):
+			return
+
+		for node in tsk.outputs:
+			mp[node].append(tsk)
+		try:
+			uids[tsk.uid()].append(tsk)
+		except:
+			uids[tsk.uid()] = [tsk]
+
+	for g in self.groups:
+		for tg in g:
+			try:
+				for tsk in tg.tasks:
+					check_task(tsk)
+			except AttributeError:
+				# raised if not a task generator, which should be uncommon
+				check_task(tg)
+
+	dupe = False
+	for (k, v) in mp.items():
+		if len(v) > 1:
+			dupe = True
+			msg = '* Node %r is created by more than once%s. The task generators are:' % (k, Logs.verbose == 1 and " (full message on 'waf -v -v')" or "")
+			Logs.error(msg)
+			for x in v:
+				if Logs.verbose > 1:
+					Logs.error('  %d. %r' % (1 + v.index(x), x.generator))
+				else:
+					Logs.error('  %d. %r in %r' % (1 + v.index(x), x.generator.name, getattr(x.generator, 'path', None)))
+
+	if not dupe:
+		for (k, v) in uids.items():
+			if len(v) > 1:
+				Logs.error('* Several tasks use the same identifier. Please check the information on\n   http://waf.googlecode.com/git/docs/apidocs/Task.html#waflib.Task.Task.uid')
+				for tsk in v:
+					Logs.error('  - object %r (%r) defined in %r' % (tsk.__class__.__name__, tsk, tsk.generator))
+
+def check_invalid_constraints(self):
+	feat = set([])
+	for x in list(TaskGen.feats.values()):
+		feat.union(set(x))
+	for (x, y) in TaskGen.task_gen.prec.items():
+		feat.add(x)
+		feat.union(set(y))
+	ext = set([])
+	for x in TaskGen.task_gen.mappings.values():
+		ext.add(x.__name__)
+	invalid = ext & feat
+	if invalid:
+		Logs.error('The methods %r have invalid annotations:  @extension <-> @feature/@before_method/@after_method' % list(invalid))
+
+	# the build scripts have been read, so we can check for invalid after/before attributes on task classes
+	for cls in list(Task.classes.values()):
+		for x in ('before', 'after'):
+			for y in Utils.to_list(getattr(cls, x, [])):
+				if not Task.classes.get(y, None):
+					Logs.error('Erroneous order constraint %r=%r on task class %r' % (x, y, cls.__name__))
+		if getattr(cls, 'rule', None):
+			Logs.error('Erroneous attribute "rule" on task class %r (rename to "run_str")' % cls.__name__)
+
+def replace(m):
+	"""
+	We could add properties, but they would not work in some cases:
+	bld.program(...) requires 'source' in the attributes
+	"""
+	oldcall = getattr(Build.BuildContext, m)
+	def call(self, *k, **kw):
+		ret = oldcall(self, *k, **kw)
+		for x in typos:
+			if x in kw:
+				err = True
+				Logs.error('Fix the typo %r -> %r on %r' % (x, typos[x], ret))
+		return ret
+	setattr(Build.BuildContext, m, call)
+
+def enhance_lib():
+	"""
+	modify existing classes and methods
+	"""
+	for m in meths_typos:
+		replace(m)
+
+	# catch '..' in ant_glob patterns
+	old_ant_glob = Node.Node.ant_glob
+	def ant_glob(self, *k, **kw):
+		if k:
+			lst=Utils.to_list(k[0])
+			for pat in lst:
+				if '..' in pat.split('/'):
+					Logs.error("In ant_glob pattern %r: '..' means 'two dots', not 'parent directory'" % k[0])
+		return old_ant_glob(self, *k, **kw)
+	Node.Node.ant_glob = ant_glob
+
+	# catch conflicting ext_in/ext_out/before/after declarations
+	old = Task.is_before
+	def is_before(t1, t2):
+		ret = old(t1, t2)
+		if ret and old(t2, t1):
+			Logs.error('Contradictory order constraints in classes %r %r' % (t1, t2))
+		return ret
+	Task.is_before = is_before
+
+	# check for bld(feature='cshlib') where no 'c' is given - this can be either a mistake or on purpose
+	# so we only issue a warning
+	def check_err_features(self):
+		lst = self.to_list(self.features)
+		if 'shlib' in lst:
+			Logs.error('feature shlib -> cshlib, dshlib or cxxshlib')
+		for x in ('c', 'cxx', 'd', 'fc'):
+			if not x in lst and lst and lst[0] in [x+y for y in ('program', 'shlib', 'stlib')]:
+				Logs.error('%r features is probably missing %r' % (self, x))
+	TaskGen.feature('*')(check_err_features)
+
+	# check for erroneous order constraints
+	def check_err_order(self):
+		if not hasattr(self, 'rule'):
+			for x in ('before', 'after', 'ext_in', 'ext_out'):
+				if hasattr(self, x):
+					Logs.warn('Erroneous order constraint %r on non-rule based task generator %r' % (x, self))
+		else:
+			for x in ('before', 'after'):
+				for y in self.to_list(getattr(self, x, [])):
+					if not Task.classes.get(y, None):
+						Logs.error('Erroneous order constraint %s=%r on %r' % (x, y, self))
+	TaskGen.feature('*')(check_err_order)
+
+	# check for @extension used with @feature/@before_method/@after_method
+	def check_compile(self):
+		check_invalid_constraints(self)
+		try:
+			ret = self.orig_compile()
+		finally:
+			check_same_targets(self)
+		return ret
+	Build.BuildContext.orig_compile = Build.BuildContext.compile
+	Build.BuildContext.compile = check_compile
+
+	# check for invalid build groups #914
+	def use_rec(self, name, **kw):
+		try:
+			y = self.bld.get_tgen_by_name(name)
+		except Errors.WafError:
+			pass
+		else:
+			idx = self.bld.get_group_idx(self)
+			odx = self.bld.get_group_idx(y)
+			if odx > idx:
+				msg = "Invalid 'use' across build groups:"
+				if Logs.verbose > 1:
+					msg += '\n  target %r\n  uses:\n  %r' % (self, y)
+				else:
+					msg += " %r uses %r (try 'waf -v -v' for the full error)" % (self.name, name)
+				raise Errors.WafError(msg)
+		self.orig_use_rec(name, **kw)
+	TaskGen.task_gen.orig_use_rec = TaskGen.task_gen.use_rec
+	TaskGen.task_gen.use_rec = use_rec
+
+	# check for env.append
+	def getattri(self, name, default=None):
+		if name == 'append' or name == 'add':
+			raise Errors.WafError('env.append and env.add do not exist: use env.append_value/env.append_unique')
+		elif name == 'prepend':
+			raise Errors.WafError('env.prepend does not exist: use env.prepend_value')
+		if name in self.__slots__:
+			return object.__getattr__(self, name, default)
+		else:
+			return self[name]
+	ConfigSet.ConfigSet.__getattr__ = getattri
+
+
+def options(opt):
+	"""
+	Add a few methods
+	"""
+	enhance_lib()
+
+def configure(conf):
+	pass
+
diff --git a/xpdeint/waf/waflib/Tools/fc.py b/xpdeint/waf/waflib/Tools/fc.py
new file mode 100644
index 0000000..91d01bb
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/fc.py
@@ -0,0 +1,205 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# DC 2008
+# Thomas Nagy 2010 (ita)
+
+"""
+fortran support
+"""
+
+import re
+
+from waflib import Utils, Task, TaskGen, Logs
+from waflib.Tools import ccroot, fc_config, fc_scan
+from waflib.TaskGen import feature, before_method, after_method, extension
+from waflib.Configure import conf
+
+ccroot.USELIB_VARS['fc'] = set(['FCFLAGS', 'DEFINES', 'INCLUDES'])
+ccroot.USELIB_VARS['fcprogram_test'] = ccroot.USELIB_VARS['fcprogram'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS'])
+ccroot.USELIB_VARS['fcshlib'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS'])
+ccroot.USELIB_VARS['fcstlib'] = set(['ARFLAGS', 'LINKDEPS'])
+
+ at feature('fcprogram', 'fcshlib', 'fcstlib', 'fcprogram_test')
+def dummy(self):
+	pass
+
+ at extension('.f', '.f90', '.F', '.F90', '.for', '.FOR')
+def fc_hook(self, node):
+	"Bind the typical Fortran file extensions to the creation of a :py:class:`waflib.Tools.fc.fc` instance"
+	return self.create_compiled_task('fc', node)
+
+ at conf
+def modfile(conf, name):
+	"""
+	Turn a module name into the right module file name.
+	Defaults to all lower case.
+	"""
+	return {'lower'     :name.lower() + '.mod',
+		'lower.MOD' :name.upper() + '.MOD',
+		'UPPER.mod' :name.upper() + '.mod',
+		'UPPER'     :name.upper() + '.MOD'}[conf.env.FC_MOD_CAPITALIZATION or 'lower']
+
+def get_fortran_tasks(tsk):
+	"""
+	Obtain all other fortran tasks from the same build group. Those tasks must not have
+	the attribute 'nomod' or 'mod_fortran_done'
+	"""
+	bld = tsk.generator.bld
+	tasks = bld.get_tasks_group(bld.get_group_idx(tsk.generator))
+	return [x for x in tasks if isinstance(x, fc) and not getattr(x, 'nomod', None) and not getattr(x, 'mod_fortran_done', None)]
+
+class fc(Task.Task):
+	"""
+	The fortran tasks can only run when all fortran tasks in the current group are ready to be executed
+	This may cause a deadlock if another fortran task is waiting for something that cannot happen (circular dependency)
+	in this case, set the 'nomod=True' on those tasks instances to break the loop
+	"""
+
+	color = 'GREEN'
+	run_str = '${FC} ${FCFLAGS} ${FCINCPATH_ST:INCPATHS} ${FCDEFINES_ST:DEFINES} ${_FCMODOUTFLAGS} ${FC_TGT_F}${TGT[0].abspath()} ${FC_SRC_F}${SRC[0].abspath()}'
+	vars = ["FORTRANMODPATHFLAG"]
+
+	def scan(self):
+		"""scanner for fortran dependencies"""
+		tmp = fc_scan.fortran_parser(self.generator.includes_nodes)
+		tmp.task = self
+		tmp.start(self.inputs[0])
+		if Logs.verbose:
+			Logs.debug('deps: deps for %r: %r; unresolved %r' % (self.inputs, tmp.nodes, tmp.names))
+		return (tmp.nodes, tmp.names)
+
+	def runnable_status(self):
+		"""
+		Set the mod file outputs and the dependencies on the mod files over all the fortran tasks
+		executed by the main thread so there are no concurrency issues
+		"""
+		if getattr(self, 'mod_fortran_done', None):
+			return super(fc, self).runnable_status()
+
+		# now, if we reach this part it is because this fortran task is the first in the list
+		bld = self.generator.bld
+
+		# obtain the fortran tasks
+		lst = get_fortran_tasks(self)
+
+		# disable this method for other tasks
+		for tsk in lst:
+			tsk.mod_fortran_done = True
+
+		# wait for all the .f tasks to be ready for execution
+		# and ensure that the scanners are called at least once
+		for tsk in lst:
+			ret = tsk.runnable_status()
+			if ret == Task.ASK_LATER:
+				# we have to wait for one of the other fortran tasks to be ready
+				# this may deadlock if there are dependencies between the fortran tasks
+				# but this should not happen (we are setting them here!)
+				for x in lst:
+					x.mod_fortran_done = None
+
+				# TODO sort the list of tasks in bld.producer.outstanding to put all fortran tasks at the end
+				return Task.ASK_LATER
+
+		ins = Utils.defaultdict(set)
+		outs = Utils.defaultdict(set)
+
+		# the .mod files to create
+		for tsk in lst:
+			key = tsk.uid()
+			for x in bld.raw_deps[key]:
+				if x.startswith('MOD@'):
+					name = bld.modfile(x.replace('MOD@', ''))
+					node = bld.srcnode.find_or_declare(name)
+					tsk.set_outputs(node)
+					outs[id(node)].add(tsk)
+
+		# the .mod files to use
+		for tsk in lst:
+			key = tsk.uid()
+			for x in bld.raw_deps[key]:
+				if x.startswith('USE@'):
+					name = bld.modfile(x.replace('USE@', ''))
+					node = bld.srcnode.find_resource(name)
+					if node and node not in tsk.outputs:
+						if not node in bld.node_deps[key]:
+							bld.node_deps[key].append(node)
+						ins[id(node)].add(tsk)
+
+		# if the intersection matches, set the order
+		for k in ins.keys():
+			for a in ins[k]:
+				a.run_after.update(outs[k])
+
+				# the scanner cannot output nodes, so we have to set them
+				# ourselves as task.dep_nodes (additional input nodes)
+				tmp = []
+				for t in outs[k]:
+					tmp.extend(t.outputs)
+				a.dep_nodes.extend(tmp)
+
+				# old python versions
+				try:
+					a.dep_nodes.sort(key=lambda x: x.abspath())
+				except:
+					a.dep_nodes.sort(lambda x, y: cmp(x.abspath(), y.abspath()))
+
+		# the task objects have changed: clear the signature cache
+		for tsk in lst:
+			try:
+				delattr(tsk, 'cache_sig')
+			except AttributeError:
+				pass
+
+		return super(fc, self).runnable_status()
+
+class fcprogram(ccroot.link_task):
+	"""Link fortran programs"""
+	color = 'YELLOW'
+	run_str = '${FC} ${LINKFLAGS} ${FCLNK_SRC_F}${SRC} ${FCLNK_TGT_F}${TGT[0].abspath()} ${RPATH_ST:RPATH} ${FCSTLIB_MARKER} ${FCSTLIBPATH_ST:STLIBPATH} ${FCSTLIB_ST:STLIB} ${FCSHLIB_MARKER} ${FCLIBPATH_ST:LIBPATH} ${FCLIB_ST:LIB}'
+	inst_to = '${BINDIR}'
+	chmod   = Utils.O755
+
+class fcshlib(fcprogram):
+	"""Link fortran libraries"""
+	inst_to = '${LIBDIR}'
+
+class fcprogram_test(fcprogram):
+	"""Custom link task to obtain the compiler outputs for fortran configuration tests"""
+
+	def can_retrieve_cache(self):
+		"""This task is always executed"""
+		return False
+
+	def runnable_status(self):
+		"""This task is always executed"""
+		ret = super(fcprogram_test, self).runnable_status()
+		if ret == Task.SKIP_ME:
+			ret = Task.RUN_ME
+		return ret
+
+	def exec_command(self, cmd, **kw):
+		"""Store the compiler std our/err onto the build context, to bld.out + bld.err"""
+		bld = self.generator.bld
+
+		kw['shell'] = isinstance(cmd, str)
+		kw['stdout'] = kw['stderr'] = Utils.subprocess.PIPE
+		kw['cwd'] = bld.variant_dir
+		bld.out = bld.err = ''
+
+		bld.to_log('command: %s\n' % cmd)
+
+		kw['output'] = 0
+		try:
+			(bld.out, bld.err) = bld.cmd_and_log(cmd, **kw)
+		except Exception as e:
+			return -1
+
+		if bld.out:
+			bld.to_log("out: %s\n" % bld.out)
+		if bld.err:
+			bld.to_log("err: %s\n" % bld.err)
+
+class fcstlib(ccroot.stlink_task):
+	"""Link fortran static libraries (uses ar by default)"""
+	pass # do not remove the pass statement
+
diff --git a/xpdeint/waf/waflib/Tools/fc_config.py b/xpdeint/waf/waflib/Tools/fc_config.py
new file mode 100644
index 0000000..c9608ff
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/fc_config.py
@@ -0,0 +1,461 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# DC 2008
+# Thomas Nagy 2010 (ita)
+
+"""
+Fortran configuration helpers
+"""
+
+import re, shutil, os, sys, string, shlex
+from waflib.Configure import conf
+from waflib.TaskGen import feature, after_method, before_method
+from waflib import Build, Utils
+
+FC_FRAGMENT = '        program main\n        end     program main\n'
+FC_FRAGMENT2 = '        PROGRAM MAIN\n        END\n' # what's the actual difference between these?
+
+ at conf
+def fc_flags(conf):
+	"""
+	Define common fortran configuration flags and file extensions
+	"""
+	v = conf.env
+
+	v['FC_SRC_F']    = []
+	v['FC_TGT_F']    = ['-c', '-o']
+	v['FCINCPATH_ST']  = '-I%s'
+	v['FCDEFINES_ST']  = '-D%s'
+
+	if not v['LINK_FC']: v['LINK_FC'] = v['FC']
+	v['FCLNK_SRC_F'] = []
+	v['FCLNK_TGT_F'] = ['-o']
+
+	v['FCFLAGS_fcshlib']   = ['-fpic']
+	v['LINKFLAGS_fcshlib'] = ['-shared']
+	v['fcshlib_PATTERN']   = 'lib%s.so'
+
+	v['fcstlib_PATTERN']   = 'lib%s.a'
+
+	v['FCLIB_ST']       = '-l%s'
+	v['FCLIBPATH_ST']   = '-L%s'
+	v['FCSTLIB_ST']     = '-l%s'
+	v['FCSTLIBPATH_ST'] = '-L%s'
+	v['FCSTLIB_MARKER'] = '-Wl,-Bstatic'
+	v['FCSHLIB_MARKER'] = '-Wl,-Bdynamic'
+
+	v['SONAME_ST']           = '-Wl,-h,%s'
+
+
+ at conf
+def check_fortran(self, *k, **kw):
+	"""See if the fortran compiler works by compiling a simple fortran program"""
+	self.check_cc(
+		fragment         = FC_FRAGMENT,
+		compile_filename = 'test.f',
+		features         = 'fc fcprogram',
+		msg              = 'Compiling a simple fortran app')
+
+ at conf
+def check_fc(self, *k, **kw):
+	"""
+	Same as :py:func:`waflib.Tools.c_config.check` but default to the *Fortran* programming language
+	(Overriding the C defaults in :py:func:`waflib.Tools.c_config.validate_c` here)
+	"""
+	kw['compiler'] = 'fc'
+	if not 'compile_mode' in kw:
+		kw['compile_mode'] = 'fc'
+	if not 'type' in kw:
+		kw['type'] = 'fcprogram'
+	if not 'compile_filename' in kw:
+		kw['compile_filename'] = 'test.f90'
+	if not 'code' in kw:
+		kw['code'] = FC_FRAGMENT
+	return self.check(*k, **kw)
+
+# ------------------------------------------------------------------------
+# --- These are the default platform modifiers, refactored here for
+#     convenience.  gfortran and g95 have much overlap.
+# ------------------------------------------------------------------------
+
+ at conf
+def fortran_modifier_darwin(conf):
+	"""
+	Define fortran flags and extensions for the OSX systems
+	"""
+	v = conf.env
+	v['FCFLAGS_fcshlib']   = ['-fPIC', '-compatibility_version', '1', '-current_version', '1']
+	v['LINKFLAGS_fcshlib'] = ['-dynamiclib']
+	v['fcshlib_PATTERN']   = 'lib%s.dylib'
+	v['FRAMEWORKPATH_ST']  = '-F%s'
+	v['FRAMEWORK_ST']      = '-framework %s'
+
+	v['LINKFLAGS_fcstlib'] = []
+
+	v['FCSHLIB_MARKER']    = ''
+	v['FCSTLIB_MARKER']    = ''
+	v['SONAME_ST']         = ''
+
+
+ at conf
+def fortran_modifier_win32(conf):
+	"""Define fortran flags for the windows platforms"""
+	v = conf.env
+	v['fcprogram_PATTERN'] = v['fcprogram_test_PATTERN']  = '%s.exe'
+
+	v['fcshlib_PATTERN']   = '%s.dll'
+	v['implib_PATTERN']    = 'lib%s.dll.a'
+	v['IMPLIB_ST']         = '-Wl,--out-implib,%s'
+
+	v['FCFLAGS_fcshlib']   = []
+
+	v.append_value('FCFLAGS_fcshlib', ['-DDLL_EXPORT']) # TODO adding nonstandard defines like this DLL_EXPORT is not a good idea
+
+	# Auto-import is enabled by default even without this option,
+	# but enabling it explicitly has the nice effect of suppressing the rather boring, debug-level messages
+	# that the linker emits otherwise.
+	v.append_value('LINKFLAGS', ['-Wl,--enable-auto-import'])
+
+ at conf
+def fortran_modifier_cygwin(conf):
+	"""Define fortran flags for use on cygwin"""
+	fortran_modifier_win32(conf)
+	v = conf.env
+	v['fcshlib_PATTERN'] = 'cyg%s.dll'
+	v.append_value('LINKFLAGS_fcshlib', ['-Wl,--enable-auto-image-base'])
+	v['FCFLAGS_fcshlib'] = []
+# ------------------------------------------------------------------------
+
+ at conf
+def check_fortran_dummy_main(self, *k, **kw):
+	"""
+	Guess if a main function is needed by compiling a code snippet with
+	the C compiler and link with the Fortran compiler
+
+	TODO: (DC)
+	- handling dialects (F77, F90, etc... -> needs core support first)
+	- fix dummy main check (AC_FC_DUMMY_MAIN vs AC_FC_MAIN)
+
+	TODO: what does the above mean? (ita)
+	"""
+
+	if not self.env.CC:
+		self.fatal('A c compiler is required for check_fortran_dummy_main')
+
+	lst = ['MAIN__', '__MAIN', '_MAIN', 'MAIN_', 'MAIN']
+	lst.extend([m.lower() for m in lst])
+	lst.append('')
+
+	self.start_msg('Detecting whether we need a dummy main')
+	for main in lst:
+		kw['fortran_main'] = main
+		try:
+			self.check_cc(
+				fragment = 'int %s() { return 0; }\n' % (main or 'test'),
+				features = 'c fcprogram',
+				mandatory = True
+			)
+			if not main:
+				self.env.FC_MAIN = -1
+				self.end_msg('no')
+			else:
+				self.env.FC_MAIN = main
+				self.end_msg('yes %s' % main)
+			break
+		except self.errors.ConfigurationError:
+			pass
+	else:
+		self.end_msg('not found')
+		self.fatal('could not detect whether fortran requires a dummy main, see the config.log')
+
+# ------------------------------------------------------------------------
+
+GCC_DRIVER_LINE = re.compile('^Driving:')
+POSIX_STATIC_EXT = re.compile('\S+\.a')
+POSIX_LIB_FLAGS = re.compile('-l\S+')
+
+ at conf
+def is_link_verbose(self, txt):
+	"""Return True if 'useful' link options can be found in txt"""
+	assert isinstance(txt, str)
+	for line in txt.splitlines():
+		if not GCC_DRIVER_LINE.search(line):
+			if POSIX_STATIC_EXT.search(line) or POSIX_LIB_FLAGS.search(line):
+				return True
+	return False
+
+ at conf
+def check_fortran_verbose_flag(self, *k, **kw):
+	"""
+	Check what kind of verbose (-v) flag works, then set it to env.FC_VERBOSE_FLAG
+	"""
+	self.start_msg('fortran link verbose flag')
+	for x in ['-v', '--verbose', '-verbose', '-V']:
+		try:
+			self.check_cc(
+				features = 'fc fcprogram_test',
+				fragment = FC_FRAGMENT2,
+				compile_filename = 'test.f',
+				linkflags = [x],
+				mandatory=True
+				)
+		except self.errors.ConfigurationError:
+			pass
+		else:
+			# output is on stderr or stdout (for xlf)
+			if self.is_link_verbose(self.test_bld.err) or self.is_link_verbose(self.test_bld.out):
+				self.end_msg(x)
+				break
+	else:
+		self.end_msg('failure')
+		self.fatal('Could not obtain the fortran link verbose flag (see config.log)')
+
+	self.env.FC_VERBOSE_FLAG = x
+	return x
+
+# ------------------------------------------------------------------------
+
+# linkflags which match those are ignored
+LINKFLAGS_IGNORED = [r'-lang*', r'-lcrt[a-zA-Z0-9\.]*\.o', r'-lc$', r'-lSystem', r'-libmil', r'-LIST:*', r'-LNO:*']
+if os.name == 'nt':
+	LINKFLAGS_IGNORED.extend([r'-lfrt*', r'-luser32', r'-lkernel32', r'-ladvapi32', r'-lmsvcrt', r'-lshell32', r'-lmingw', r'-lmoldname'])
+else:
+	LINKFLAGS_IGNORED.append(r'-lgcc*')
+RLINKFLAGS_IGNORED = [re.compile(f) for f in LINKFLAGS_IGNORED]
+
+def _match_ignore(line):
+	"""Returns True if the line should be ignored (fortran test for verbosity)."""
+	for i in RLINKFLAGS_IGNORED:
+		if i.match(line):
+			return True
+	return False
+
+def parse_fortran_link(lines):
+	"""Given the output of verbose link of Fortran compiler, this returns a
+	list of flags necessary for linking using the standard linker."""
+	# TODO: On windows ?
+	final_flags = []
+	for line in lines:
+		if not GCC_DRIVER_LINE.match(line):
+			_parse_flink_line(line, final_flags)
+	return final_flags
+
+SPACE_OPTS = re.compile('^-[LRuYz]$')
+NOSPACE_OPTS = re.compile('^-[RL]')
+
+def _parse_flink_line(line, final_flags):
+	"""private"""
+	lexer = shlex.shlex(line, posix = True)
+	lexer.whitespace_split = True
+
+	t = lexer.get_token()
+	tmp_flags = []
+	while t:
+		def parse(token):
+			# Here we go (convention for wildcard is shell, not regex !)
+			#   1 TODO: we first get some root .a libraries
+			#   2 TODO: take everything starting by -bI:*
+			#   3 Ignore the following flags: -lang* | -lcrt*.o | -lc |
+			#   -lgcc* | -lSystem | -libmil | -LANG:=* | -LIST:* | -LNO:*)
+			#   4 take into account -lkernel32
+			#   5 For options of the kind -[[LRuYz]], as they take one argument
+			#   after, the actual option is the next token
+			#   6 For -YP,*: take and replace by -Larg where arg is the old
+			#   argument
+			#   7 For -[lLR]*: take
+
+			# step 3
+			if _match_ignore(token):
+				pass
+			# step 4
+			elif token.startswith('-lkernel32') and sys.platform == 'cygwin':
+				tmp_flags.append(token)
+			# step 5
+			elif SPACE_OPTS.match(token):
+				t = lexer.get_token()
+				if t.startswith('P,'):
+					t = t[2:]
+				for opt in t.split(os.pathsep):
+					tmp_flags.append('-L%s' % opt)
+			# step 6
+			elif NOSPACE_OPTS.match(token):
+				tmp_flags.append(token)
+			# step 7
+			elif POSIX_LIB_FLAGS.match(token):
+				tmp_flags.append(token)
+			else:
+				# ignore anything not explicitely taken into account
+				pass
+
+			t = lexer.get_token()
+			return t
+		t = parse(t)
+
+	final_flags.extend(tmp_flags)
+	return final_flags
+
+ at conf
+def check_fortran_clib(self, autoadd=True, *k, **kw):
+	"""
+	Obtain the flags for linking with the C library
+	if this check works, add uselib='CLIB' to your task generators
+	"""
+	if not self.env.FC_VERBOSE_FLAG:
+		self.fatal('env.FC_VERBOSE_FLAG is not set: execute check_fortran_verbose_flag?')
+
+	self.start_msg('Getting fortran runtime link flags')
+	try:
+		self.check_cc(
+			fragment = FC_FRAGMENT2,
+			compile_filename = 'test.f',
+			features = 'fc fcprogram_test',
+			linkflags = [self.env.FC_VERBOSE_FLAG]
+		)
+	except:
+		self.end_msg(False)
+		if kw.get('mandatory', True):
+			conf.fatal('Could not find the c library flags')
+	else:
+		out = self.test_bld.err
+		flags = parse_fortran_link(out.splitlines())
+		self.end_msg('ok (%s)' % ' '.join(flags))
+		self.env.LINKFLAGS_CLIB = flags
+		return flags
+	return []
+
+def getoutput(conf, cmd, stdin=False):
+	"""
+	TODO a bit redundant, can be removed anytime
+	"""
+	try:
+		if stdin:
+			stdin = Utils.subprocess.PIPE
+		else:
+			stdin = None
+		p = Utils.subprocess.Popen(cmd, stdin=stdin, stdout=Utils.subprocess.PIPE, stderr=Utils.subprocess.PIPE)
+		if stdin:
+			p.stdin.write('\n'.encode())
+		stdout, stderr = p.communicate()
+	except:
+		conf.fatal('could not determine the compiler version %r' % cmd)
+	else:
+		if not isinstance(stdout, str):
+			stdout = stdout.decode(sys.stdout.encoding)
+		if not isinstance(stderr, str):
+			stderr = stderr.decode(sys.stdout.encoding)
+		return stdout, stderr
+
+# ------------------------------------------------------------------------
+
+ROUTINES_CODE = """\
+      subroutine foobar()
+      return
+      end
+      subroutine foo_bar()
+      return
+      end
+"""
+
+MAIN_CODE = """
+void %(dummy_func_nounder)s(void);
+void %(dummy_func_under)s(void);
+int %(main_func_name)s() {
+  %(dummy_func_nounder)s();
+  %(dummy_func_under)s();
+  return 0;
+}
+"""
+
+ at feature('link_main_routines_func')
+ at before_method('process_source')
+def link_main_routines_tg_method(self):
+	"""
+	The configuration test declares a unique task generator,
+	so we create other task generators from there for fortran link tests
+	"""
+	def write_test_file(task):
+		task.outputs[0].write(task.generator.code)
+	bld = self.bld
+	bld(rule=write_test_file, target='main.c', code=MAIN_CODE % self.__dict__)
+	bld(rule=write_test_file, target='test.f', code=ROUTINES_CODE)
+	bld(features='fc fcstlib', source='test.f', target='test')
+	bld(features='c fcprogram', source='main.c', target='app', use='test')
+
+def mangling_schemes():
+	"""
+	Generate triplets for use with mangle_name
+	(used in check_fortran_mangling)
+	the order is tuned for gfortan
+	"""
+	for u in ['_', '']:
+		for du in ['', '_']:
+			for c in ["lower", "upper"]:
+				yield (u, du, c)
+
+def mangle_name(u, du, c, name):
+	"""Mangle a name from a triplet (used in check_fortran_mangling)"""
+	return getattr(name, c)() + u + (name.find('_') != -1 and du or '')
+
+ at conf
+def check_fortran_mangling(self, *k, **kw):
+	"""
+	Detect the mangling scheme, sets FORTRAN_MANGLING to the triplet found
+
+	This test will compile a fortran static library, then link a c app against it
+	"""
+	if not self.env.CC:
+		self.fatal('A c compiler is required for link_main_routines')
+	if not self.env.FC:
+		self.fatal('A fortran compiler is required for link_main_routines')
+	if not self.env.FC_MAIN:
+		self.fatal('Checking for mangling requires self.env.FC_MAIN (execute "check_fortran_dummy_main" first?)')
+
+	self.start_msg('Getting fortran mangling scheme')
+	for (u, du, c) in mangling_schemes():
+		try:
+			self.check_cc(
+				compile_filename = [],
+				features         = 'link_main_routines_func',
+				msg = 'nomsg',
+				errmsg = 'nomsg',
+				mandatory=True,
+				dummy_func_nounder = mangle_name(u, du, c, "foobar"),
+				dummy_func_under   = mangle_name(u, du, c, "foo_bar"),
+				main_func_name     = self.env.FC_MAIN
+			)
+		except self.errors.ConfigurationError:
+			pass
+		else:
+			self.end_msg("ok ('%s', '%s', '%s-case')" % (u, du, c))
+			self.env.FORTRAN_MANGLING = (u, du, c)
+			break
+	else:
+		self.end_msg(False)
+		self.fatal('mangler not found')
+
+	return (u, du, c)
+
+ at feature('pyext')
+ at before_method('propagate_uselib_vars', 'apply_link')
+def set_lib_pat(self):
+	"""Set the fortran flags for linking with the python library"""
+	self.env['fcshlib_PATTERN'] = self.env['pyext_PATTERN']
+
+ at conf
+def detect_openmp(self):
+	for x in ['-fopenmp','-openmp','-mp','-xopenmp','-omp','-qsmp=omp']:
+		try:
+			self.check_fc(
+				msg='Checking for OpenMP flag %s' % x,
+				fragment='program main\n  call omp_get_num_threads()\nend program main',
+				fcflags=x,
+				linkflags=x,
+				uselib_store='OPENMP'
+			)
+		except self.errors.ConfigurationError:
+			pass
+		else:
+			break
+	else:
+		self.fatal('Could not find OpenMP')
+
diff --git a/xpdeint/waf/waflib/Tools/fc_scan.py b/xpdeint/waf/waflib/Tools/fc_scan.py
new file mode 100644
index 0000000..cbe77d3
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/fc_scan.py
@@ -0,0 +1,126 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# DC 2008
+# Thomas Nagy 2010 (ita)
+
+import re
+
+from waflib import Utils, Task, TaskGen, Logs
+from waflib.TaskGen import feature, before_method, after_method, extension
+from waflib.Configure import conf
+
+INC_REGEX = """(?:^|['">]\s*;)\s*INCLUDE\s+(?:\w+_)?[<"'](.+?)(?=["'>])"""
+USE_REGEX = """(?:^|;)\s*USE(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)"""
+MOD_REGEX = """(?:^|;)\s*MODULE(?!\s*PROCEDURE)(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)"""
+
+# TODO (DC)
+#   - handle pre-processed files (FORTRANPPCOM in scons)
+#   - handle multiple dialects
+# TODO (ita) understand what the above is supposed to mean ^^
+
+re_inc = re.compile(INC_REGEX, re.I)
+re_use = re.compile(USE_REGEX, re.I)
+re_mod = re.compile(MOD_REGEX, re.I)
+
+class fortran_parser(object):
+	"""
+	This parser will return:
+
+	* the nodes corresponding to the module names that will be produced
+	* the nodes corresponding to the include files used
+	* the module names used by the fortran file
+	"""
+
+	def __init__(self, incpaths):
+		self.seen = []
+		"""Files already parsed"""
+
+		self.nodes = []
+		"""List of :py:class:`waflib.Node.Node` representing the dependencies to return"""
+
+		self.names = []
+		"""List of module names to return"""
+
+		self.incpaths = incpaths
+		"""List of :py:class:`waflib.Node.Node` representing the include paths"""
+
+	def find_deps(self, node):
+		"""
+		Parse a fortran file to read the dependencies used and provided
+
+		:param node: fortran file to read
+		:type node: :py:class:`waflib.Node.Node`
+		:return: lists representing the includes, the modules used, and the modules created by a fortran file
+		:rtype: tuple of list of strings
+		"""
+		txt = node.read()
+		incs = []
+		uses = []
+		mods = []
+		for line in txt.splitlines():
+			# line by line regexp search? optimize?
+			m = re_inc.search(line)
+			if m:
+				incs.append(m.group(1))
+			m = re_use.search(line)
+			if m:
+				uses.append(m.group(1))
+			m = re_mod.search(line)
+			if m:
+				mods.append(m.group(1))
+		return (incs, uses, mods)
+
+	def start(self, node):
+		"""
+		Start the parsing. Use the stack self.waiting to hold the nodes to iterate on
+
+		:param node: fortran file
+		:type node: :py:class:`waflib.Node.Node`
+		"""
+		self.waiting = [node]
+		while self.waiting:
+			nd = self.waiting.pop(0)
+			self.iter(nd)
+
+	def iter(self, node):
+		"""
+		Process a single file in the search for dependencies, extract the files used
+		the modules used, and the modules provided.
+		"""
+		path = node.abspath()
+		incs, uses, mods = self.find_deps(node)
+		for x in incs:
+			if x in self.seen:
+				continue
+			self.seen.append(x)
+			self.tryfind_header(x)
+
+		for x in uses:
+			name = "USE@%s" % x
+			if not name in self.names:
+				self.names.append(name)
+
+		for x in mods:
+			name = "MOD@%s" % x
+			if not name in self.names:
+				self.names.append(name)
+
+	def tryfind_header(self, filename):
+		"""
+		Try to find an include and add it the nodes to process
+
+		:param filename: file name
+		:type filename: string
+		"""
+		found = None
+		for n in self.incpaths:
+			found = n.find_resource(filename)
+			if found:
+				self.nodes.append(found)
+				self.waiting.append(found)
+				break
+		if not found:
+			if not filename in self.names:
+				self.names.append(filename)
+
+
diff --git a/xpdeint/waf/waflib/Tools/flex.py b/xpdeint/waf/waflib/Tools/flex.py
new file mode 100644
index 0000000..8fbe2c8
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/flex.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# John O'Meara, 2006
+# Thomas Nagy, 2006-2010 (ita)
+
+"""
+The **flex** program is a code generator which creates C or C++ files.
+The generated files are compiled into object files.
+"""
+
+import waflib.TaskGen
+
+def decide_ext(self, node):
+	if 'cxx' in self.features:
+		return ['.lex.cc']
+	return ['.lex.c']
+
+def flexfun(tsk):
+	env = tsk.env
+	bld = tsk.generator.bld
+	wd = bld.variant_dir
+	def to_list(xx):
+		if isinstance(xx, str): return [xx]
+		return xx
+	tsk.last_cmd = lst = []
+	lst.extend(to_list(env['FLEX']))
+	lst.extend(to_list(env['FLEXFLAGS']))
+	lst.extend([a.path_from(bld.bldnode) for a in tsk.inputs])
+	lst = [x for x in lst if x]
+	txt = bld.cmd_and_log(lst, cwd=wd, env=env.env or None, quiet=0)
+	tsk.outputs[0].write(txt)
+
+waflib.TaskGen.declare_chain(
+	name = 'flex',
+	rule = flexfun, # issue #854
+	ext_in = '.l',
+	decider = decide_ext,
+)
+
+def configure(conf):
+	"""
+	Detect the *flex* program
+	"""
+	conf.find_program('flex', var='FLEX')
+	conf.env.FLEXFLAGS = ['-t']
+
diff --git a/xpdeint/waf/waflib/Tools/g95.py b/xpdeint/waf/waflib/Tools/g95.py
new file mode 100644
index 0000000..46c9d10
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/g95.py
@@ -0,0 +1,65 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# KWS 2010
+# Thomas Nagy 2010 (ita)
+
+import re
+from waflib import Utils
+from waflib.Tools import fc, fc_config, fc_scan
+from waflib.Configure import conf
+
+ at conf
+def find_g95(conf):
+	fc = conf.find_program('g95', var='FC')
+	fc = conf.cmd_to_list(fc)
+	conf.get_g95_version(fc)
+	conf.env.FC_NAME = 'G95'
+
+ at conf
+def g95_flags(conf):
+	v = conf.env
+	v['FCFLAGS_fcshlib']   = ['-fPIC']
+	v['FORTRANMODFLAG']  = ['-fmod=', ''] # template for module path
+	v['FCFLAGS_DEBUG'] = ['-Werror'] # why not
+
+ at conf
+def g95_modifier_win32(conf):
+	fc_config.fortran_modifier_win32(conf)
+
+ at conf
+def g95_modifier_cygwin(conf):
+	fc_config.fortran_modifier_cygwin(conf)
+
+ at conf
+def g95_modifier_darwin(conf):
+	fc_config.fortran_modifier_darwin(conf)
+
+ at conf
+def g95_modifier_platform(conf):
+	dest_os = conf.env['DEST_OS'] or Utils.unversioned_sys_platform()
+	g95_modifier_func = getattr(conf, 'g95_modifier_' + dest_os, None)
+	if g95_modifier_func:
+		g95_modifier_func()
+
+ at conf
+def get_g95_version(conf, fc):
+	"""get the compiler version"""
+
+	version_re = re.compile(r"g95\s*(?P<major>\d*)\.(?P<minor>\d*)").search
+	cmd = fc + ['--version']
+	out, err = fc_config.getoutput(conf, cmd, stdin=False)
+	if out:
+		match = version_re(out)
+	else:
+		match = version_re(err)
+	if not match:
+		conf.fatal('cannot determine g95 version')
+	k = match.groupdict()
+	conf.env['FC_VERSION'] = (k['major'], k['minor'])
+
+def configure(conf):
+	conf.find_g95()
+	conf.find_ar()
+	conf.fc_flags()
+	conf.g95_flags()
+	conf.g95_modifier_platform()
diff --git a/xpdeint/waf/waflib/Tools/gas.py b/xpdeint/waf/waflib/Tools/gas.py
new file mode 100644
index 0000000..81e4dce
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/gas.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2008-2010 (ita)
+
+"Detect as/gas/gcc for compiling assembly files"
+
+import waflib.Tools.asm # - leave this
+from waflib.Tools import ar
+
+def configure(conf):
+	"""
+	Find the programs gas/as/gcc and set the variable *AS*
+	"""
+	conf.find_program(['gas', 'as', 'gcc'], var='AS')
+	conf.env.AS_TGT_F = ['-o']
+	conf.env.ASLNK_TGT_F = ['-o']
+	conf.find_ar()
diff --git a/xpdeint/waf/waflib/Tools/gcc.py b/xpdeint/waf/waflib/Tools/gcc.py
new file mode 100644
index 0000000..1b95d87
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/gcc.py
@@ -0,0 +1,153 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+# Ralf Habacker, 2006 (rh)
+# Yinon Ehrlich, 2009
+
+"""
+gcc/llvm detection.
+"""
+
+import os, sys
+from waflib import Configure, Options, Utils
+from waflib.Tools import ccroot, ar
+from waflib.Configure import conf
+
+ at conf
+def find_gcc(conf):
+	"""
+	Find the program gcc, and if present, try to detect its version number
+	"""
+	cc = conf.find_program(['gcc', 'cc'], var='CC')
+	cc = conf.cmd_to_list(cc)
+	conf.get_cc_version(cc, gcc=True)
+	conf.env.CC_NAME = 'gcc'
+	conf.env.CC      = cc
+
+ at conf
+def gcc_common_flags(conf):
+	"""
+	Common flags for gcc on nearly all platforms
+	"""
+	v = conf.env
+
+	v['CC_SRC_F']            = []
+	v['CC_TGT_F']            = ['-c', '-o']
+
+	# linker
+	if not v['LINK_CC']: v['LINK_CC'] = v['CC']
+	v['CCLNK_SRC_F']         = []
+	v['CCLNK_TGT_F']         = ['-o']
+	v['CPPPATH_ST']          = '-I%s'
+	v['DEFINES_ST']          = '-D%s'
+
+	v['LIB_ST']              = '-l%s' # template for adding libs
+	v['LIBPATH_ST']          = '-L%s' # template for adding libpaths
+	v['STLIB_ST']            = '-l%s'
+	v['STLIBPATH_ST']        = '-L%s'
+	v['RPATH_ST']            = '-Wl,-rpath,%s'
+
+	v['SONAME_ST']           = '-Wl,-h,%s'
+	v['SHLIB_MARKER']        = '-Wl,-Bdynamic'
+	v['STLIB_MARKER']        = '-Wl,-Bstatic'
+
+	# program
+	v['cprogram_PATTERN']    = '%s'
+
+	# shared librar
+	v['CFLAGS_cshlib']       = ['-fPIC']
+	v['LINKFLAGS_cshlib']    = ['-shared']
+	v['cshlib_PATTERN']      = 'lib%s.so'
+
+	# static lib
+	v['LINKFLAGS_cstlib']    = ['-Wl,-Bstatic']
+	v['cstlib_PATTERN']      = 'lib%s.a'
+
+	# osx stuff
+	v['LINKFLAGS_MACBUNDLE'] = ['-bundle', '-undefined', 'dynamic_lookup']
+	v['CFLAGS_MACBUNDLE']    = ['-fPIC']
+	v['macbundle_PATTERN']   = '%s.bundle'
+
+ at conf
+def gcc_modifier_win32(conf):
+	"""Configuration flags for executing gcc on Windows"""
+	v = conf.env
+	v['cprogram_PATTERN']    = '%s.exe'
+
+	v['cshlib_PATTERN']      = '%s.dll'
+	v['implib_PATTERN']      = 'lib%s.dll.a'
+	v['IMPLIB_ST']           = '-Wl,--out-implib,%s'
+
+	v['CFLAGS_cshlib']       = []
+
+	v.append_value('CFLAGS_cshlib', ['-DDLL_EXPORT']) # TODO adding nonstandard defines like this DLL_EXPORT is not a good idea
+
+	# Auto-import is enabled by default even without this option,
+	# but enabling it explicitly has the nice effect of suppressing the rather boring, debug-level messages
+	# that the linker emits otherwise.
+	v.append_value('LINKFLAGS', ['-Wl,--enable-auto-import'])
+
+ at conf
+def gcc_modifier_cygwin(conf):
+	"""Configuration flags for executing gcc on Cygwin"""
+	gcc_modifier_win32(conf)
+	v = conf.env
+	v['cshlib_PATTERN'] = 'cyg%s.dll'
+	v.append_value('LINKFLAGS_cshlib', ['-Wl,--enable-auto-image-base'])
+	v['CFLAGS_cshlib'] = []
+
+ at conf
+def gcc_modifier_darwin(conf):
+	"""Configuration flags for executing gcc on MacOS"""
+	v = conf.env
+	v['CFLAGS_cshlib']       = ['-fPIC', '-compatibility_version', '1', '-current_version', '1']
+	v['LINKFLAGS_cshlib']    = ['-dynamiclib']
+	v['cshlib_PATTERN']      = 'lib%s.dylib'
+	v['FRAMEWORKPATH_ST']    = '-F%s'
+	v['FRAMEWORK_ST']        = ['-framework']
+	v['ARCH_ST']             = ['-arch']
+
+	v['LINKFLAGS_cstlib']    = []
+
+	v['SHLIB_MARKER']        = []
+	v['STLIB_MARKER']        = []
+	v['SONAME_ST']           = []
+
+ at conf
+def gcc_modifier_aix(conf):
+	"""Configuration flags for executing gcc on AIX"""
+	v = conf.env
+	v['LINKFLAGS_cprogram']  = ['-Wl,-brtl']
+	v['LINKFLAGS_cshlib']    = ['-shared','-Wl,-brtl,-bexpfull']
+	v['SHLIB_MARKER']        = []
+
+ at conf
+def gcc_modifier_hpux(conf):
+	v = conf.env
+	v['SHLIB_MARKER']        = []
+	v['CFLAGS_cshlib']       = ['-fPIC','-DPIC']
+	v['cshlib_PATTERN']      = 'lib%s.sl'
+
+ at conf
+def gcc_modifier_platform(conf):
+	"""Execute platform-specific functions based on *gcc_modifier_+NAME*"""
+	# * set configurations specific for a platform.
+	# * the destination platform is detected automatically by looking at the macros the compiler predefines,
+	#   and if it's not recognised, it fallbacks to sys.platform.
+	gcc_modifier_func = getattr(conf, 'gcc_modifier_' + conf.env.DEST_OS, None)
+	if gcc_modifier_func:
+			gcc_modifier_func()
+
+def configure(conf):
+	"""
+	Configuration for gcc
+	"""
+	conf.find_gcc()
+	conf.find_ar()
+	conf.gcc_common_flags()
+	conf.gcc_modifier_platform()
+	conf.cc_load_tools()
+	conf.cc_add_flags()
+	conf.link_add_flags()
+
+
diff --git a/xpdeint/waf/waflib/Tools/gdc.py b/xpdeint/waf/waflib/Tools/gdc.py
new file mode 100644
index 0000000..6bb23a6
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/gdc.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Carlos Rafael Giani, 2007 (dv)
+
+import sys
+from waflib.Tools import ar, d
+from waflib.Configure import conf
+
+ at conf
+def find_gdc(conf):
+	"""
+	Find the program gdc and set the variable *D*
+	"""
+	conf.find_program('gdc', var='D')
+
+ at conf
+def common_flags_gdc(conf):
+	"""
+	Set the flags required by *gdc*
+	"""
+	v = conf.env
+
+	# _DFLAGS _DIMPORTFLAGS
+
+	# for mory info about the meaning of this dict see dmd.py
+	v['DFLAGS']            = []
+
+	v['D_SRC_F']           = ['-c']
+	v['D_TGT_F']           = '-o%s'
+
+	# linker
+	v['D_LINKER']          = v['D']
+	v['DLNK_SRC_F']        = ''
+	v['DLNK_TGT_F']        = '-o%s'
+	v['DINC_ST']           = '-I%s'
+
+	v['DSHLIB_MARKER'] = v['DSTLIB_MARKER'] = ''
+	v['DSTLIB_ST'] = v['DSHLIB_ST']         = '-l%s'
+	v['DSTLIBPATH_ST'] = v['DLIBPATH_ST']   = '-L%s'
+
+	v['LINKFLAGS_dshlib']  = ['-shared']
+
+	v['DHEADER_ext']       = '.di'
+	v.DFLAGS_d_with_header = '-fintfc'
+	v['D_HDR_F']           = '-fintfc-file=%s'
+
+def configure(conf):
+	"""
+	Configuration for gdc
+	"""
+	conf.find_gdc()
+	conf.load('ar')
+	conf.load('d')
+	conf.common_flags_gdc()
+	conf.d_platform_flags()
+
diff --git a/xpdeint/waf/waflib/Tools/gfortran.py b/xpdeint/waf/waflib/Tools/gfortran.py
new file mode 100644
index 0000000..081b430
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/gfortran.py
@@ -0,0 +1,90 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# DC 2008
+# Thomas Nagy 2010 (ita)
+
+import re
+from waflib import Utils
+from waflib.Tools import fc, fc_config, fc_scan
+from waflib.Configure import conf
+
+ at conf
+def find_gfortran(conf):
+	"""Find the gfortran program (will look in the environment variable 'FC')"""
+	fc = conf.find_program(['gfortran','g77'], var='FC')
+	# (fallback to g77 for systems, where no gfortran is available)
+	fc = conf.cmd_to_list(fc)
+	conf.get_gfortran_version(fc)
+	conf.env.FC_NAME = 'GFORTRAN'
+
+ at conf
+def gfortran_flags(conf):
+	v = conf.env
+	v['FCFLAGS_fcshlib']   = ['-fPIC']
+	v['FORTRANMODFLAG']  = ['-J', ''] # template for module path
+	v['FCFLAGS_DEBUG'] = ['-Werror'] # why not
+
+ at conf
+def gfortran_modifier_win32(conf):
+	fc_config.fortran_modifier_win32(conf)
+
+ at conf
+def gfortran_modifier_cygwin(conf):
+	fc_config.fortran_modifier_cygwin(conf)
+
+ at conf
+def gfortran_modifier_darwin(conf):
+	fc_config.fortran_modifier_darwin(conf)
+
+ at conf
+def gfortran_modifier_platform(conf):
+	dest_os = conf.env['DEST_OS'] or Utils.unversioned_sys_platform()
+	gfortran_modifier_func = getattr(conf, 'gfortran_modifier_' + dest_os, None)
+	if gfortran_modifier_func:
+		gfortran_modifier_func()
+
+ at conf
+def get_gfortran_version(conf, fc):
+	"""Get the compiler version"""
+
+	# ensure this is actually gfortran, not an imposter.
+	version_re = re.compile(r"GNU\s*Fortran", re.I).search
+	cmd = fc + ['--version']
+	out, err = fc_config.getoutput(conf, cmd, stdin=False)
+	if out: match = version_re(out)
+	else: match = version_re(err)
+	if not match:
+		conf.fatal('Could not determine the compiler type')
+
+	# --- now get more detailed info -- see c_config.get_cc_version
+	cmd = fc + ['-dM', '-E', '-']
+	out, err = fc_config.getoutput(conf, cmd, stdin=True)
+
+	if out.find('__GNUC__') < 0:
+		conf.fatal('Could not determine the compiler type')
+
+	k = {}
+	out = out.split('\n')
+	import shlex
+
+	for line in out:
+		lst = shlex.split(line)
+		if len(lst)>2:
+			key = lst[1]
+			val = lst[2]
+			k[key] = val
+
+	def isD(var):
+		return var in k
+
+	def isT(var):
+		return var in k and k[var] != '0'
+
+	conf.env['FC_VERSION'] = (k['__GNUC__'], k['__GNUC_MINOR__'], k['__GNUC_PATCHLEVEL__'])
+
+def configure(conf):
+	conf.find_gfortran()
+	conf.find_ar()
+	conf.fc_flags()
+	conf.gfortran_flags()
+	conf.gfortran_modifier_platform()
diff --git a/xpdeint/waf/waflib/Tools/glib2.py b/xpdeint/waf/waflib/Tools/glib2.py
new file mode 100644
index 0000000..c309f02
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/glib2.py
@@ -0,0 +1,378 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+
+"""
+Support for GLib2 tools:
+
+* marshal
+* enums
+* gsettings
+"""
+
+import os
+from waflib import Task, Utils, Options, Errors, Logs
+from waflib.TaskGen import taskgen_method, before_method, after_method, feature
+
+################## marshal files
+
+ at taskgen_method
+def add_marshal_file(self, filename, prefix):
+	"""
+	Add a file to the list of marshal files to process. Store them in the attribute *marshal_list*.
+
+	:param filename: xml file to compile
+	:type filename: string
+	:param prefix: marshal prefix (--prefix=prefix)
+	:type prefix: string
+	"""
+	if not hasattr(self, 'marshal_list'):
+		self.marshal_list = []
+	self.meths.append('process_marshal')
+	self.marshal_list.append((filename, prefix))
+
+ at before_method('process_source')
+def process_marshal(self):
+	"""
+	Process the marshal files stored in the attribute *marshal_list* to create :py:class:`waflib.Tools.glib2.glib_genmarshal` instances.
+	Add the c file created to the list of source to process.
+	"""
+	for f, prefix in getattr(self, 'marshal_list', []):
+		node = self.path.find_resource(f)
+
+		if not node:
+			raise Errors.WafError('file not found %r' % f)
+
+		h_node = node.change_ext('.h')
+		c_node = node.change_ext('.c')
+
+		task = self.create_task('glib_genmarshal', node, [h_node, c_node])
+		task.env.GLIB_GENMARSHAL_PREFIX = prefix
+	self.source = self.to_nodes(getattr(self, 'source', []))
+	self.source.append(c_node)
+
+class glib_genmarshal(Task.Task):
+
+	def run(self):
+
+		bld = self.inputs[0].__class__.ctx
+
+		get = self.env.get_flat
+		cmd1 = "%s %s --prefix=%s --header > %s" % (
+			get('GLIB_GENMARSHAL'),
+			self.inputs[0].srcpath(),
+			get('GLIB_GENMARSHAL_PREFIX'),
+			self.outputs[0].abspath()
+		)
+
+		ret = bld.exec_command(cmd1)
+		if ret: return ret
+
+		#print self.outputs[1].abspath()
+		c = '''#include "%s"\n''' % self.outputs[0].name
+		self.outputs[1].write(c)
+
+		cmd2 = "%s %s --prefix=%s --body >> %s" % (
+			get('GLIB_GENMARSHAL'),
+			self.inputs[0].srcpath(),
+			get('GLIB_GENMARSHAL_PREFIX'),
+			self.outputs[1].abspath()
+		)
+		return bld.exec_command(cmd2)
+
+	vars    = ['GLIB_GENMARSHAL_PREFIX', 'GLIB_GENMARSHAL']
+	color   = 'BLUE'
+	ext_out = ['.h']
+
+########################## glib-mkenums
+
+ at taskgen_method
+def add_enums_from_template(self, source='', target='', template='', comments=''):
+	"""
+	Add a file to the list of enum files to process. Store them in the attribute *enums_list*.
+
+	:param source: enum file to process
+	:type source: string
+	:param target: target file
+	:type target: string
+	:param template: template file
+	:type template: string
+	:param comments: comments
+	:type comments: string
+	"""
+	if not hasattr(self, 'enums_list'):
+		self.enums_list = []
+	self.meths.append('process_enums')
+	self.enums_list.append({'source': source,
+	                        'target': target,
+	                        'template': template,
+	                        'file-head': '',
+	                        'file-prod': '',
+	                        'file-tail': '',
+	                        'enum-prod': '',
+	                        'value-head': '',
+	                        'value-prod': '',
+	                        'value-tail': '',
+	                        'comments': comments})
+
+ at taskgen_method
+def add_enums(self, source='', target='',
+              file_head='', file_prod='', file_tail='', enum_prod='',
+              value_head='', value_prod='', value_tail='', comments=''):
+	"""
+	Add a file to the list of enum files to process. Store them in the attribute *enums_list*.
+
+	:param source: enum file to process
+	:type source: string
+	:param target: target file
+	:type target: string
+	:param file_head: unused
+	:param file_prod: unused
+	:param file_tail: unused
+	:param enum_prod: unused
+	:param value_head: unused
+	:param value_prod: unused
+	:param value_tail: unused
+	:param comments: comments
+	:type comments: string
+	"""
+	if not hasattr(self, 'enums_list'):
+		self.enums_list = []
+	self.meths.append('process_enums')
+	self.enums_list.append({'source': source,
+	                        'template': '',
+	                        'target': target,
+	                        'file-head': file_head,
+	                        'file-prod': file_prod,
+	                        'file-tail': file_tail,
+	                        'enum-prod': enum_prod,
+	                        'value-head': value_head,
+	                        'value-prod': value_prod,
+	                        'value-tail': value_tail,
+	                        'comments': comments})
+
+ at before_method('process_source')
+def process_enums(self):
+	"""
+	Process the enum files stored in the attribute *enum_list* to create :py:class:`waflib.Tools.glib2.glib_mkenums` instances.
+	"""
+	for enum in getattr(self, 'enums_list', []):
+		task = self.create_task('glib_mkenums')
+		env = task.env
+
+		inputs = []
+
+		# process the source
+		source_list = self.to_list(enum['source'])
+		if not source_list:
+			raise Errors.WafError('missing source ' + str(enum))
+		source_list = [self.path.find_resource(k) for k in source_list]
+		inputs += source_list
+		env['GLIB_MKENUMS_SOURCE'] = [k.abspath() for k in source_list]
+
+		# find the target
+		if not enum['target']:
+			raise Errors.WafError('missing target ' + str(enum))
+		tgt_node = self.path.find_or_declare(enum['target'])
+		if tgt_node.name.endswith('.c'):
+			self.source.append(tgt_node)
+		env['GLIB_MKENUMS_TARGET'] = tgt_node.abspath()
+
+
+		options = []
+
+		if enum['template']: # template, if provided
+			template_node = self.path.find_resource(enum['template'])
+			options.append('--template %s' % (template_node.abspath()))
+			inputs.append(template_node)
+		params = {'file-head' : '--fhead',
+		           'file-prod' : '--fprod',
+		           'file-tail' : '--ftail',
+		           'enum-prod' : '--eprod',
+		           'value-head' : '--vhead',
+		           'value-prod' : '--vprod',
+		           'value-tail' : '--vtail',
+		           'comments': '--comments'}
+		for param, option in params.items():
+			if enum[param]:
+				options.append('%s %r' % (option, enum[param]))
+
+		env['GLIB_MKENUMS_OPTIONS'] = ' '.join(options)
+
+		# update the task instance
+		task.set_inputs(inputs)
+		task.set_outputs(tgt_node)
+
+class glib_mkenums(Task.Task):
+	"""
+	Process enum files
+	"""
+	run_str = '${GLIB_MKENUMS} ${GLIB_MKENUMS_OPTIONS} ${GLIB_MKENUMS_SOURCE} > ${GLIB_MKENUMS_TARGET}'
+	color   = 'PINK'
+	ext_out = ['.h']
+
+######################################### gsettings
+
+ at taskgen_method
+def add_settings_schemas(self, filename_list):
+	"""
+	Add settings files to process, add them to *settings_schema_files*
+
+	:param filename_list: files
+	:type filename_list: list of string
+	"""
+	if not hasattr(self, 'settings_schema_files'):
+		self.settings_schema_files = []
+
+	if not isinstance(filename_list, list):
+		filename_list = [filename_list]
+
+	self.settings_schema_files.extend(filename_list)
+
+ at taskgen_method
+def add_settings_enums(self, namespace, filename_list):
+	"""
+	This function may be called only once by task generator to set the enums namespace.
+
+	:param namespace: namespace
+	:type namespace: string
+	:param filename_list: enum files to process
+	:type filename_list: file list
+	"""
+	if hasattr(self, 'settings_enum_namespace'):
+		raise Errors.WafError("Tried to add gsettings enums to '%s' more than once" % self.name)
+	self.settings_enum_namespace = namespace
+
+	if type(filename_list) != 'list':
+		filename_list = [filename_list]
+	self.settings_enum_files = filename_list
+
+
+def r_change_ext(self, ext):
+	"""
+	Change the extension from the *last* dot in the filename. The gsettings schemas
+	often have names of the form org.gsettings.test.gschema.xml
+	"""
+	name = self.name
+	k = name.rfind('.')
+	if k >= 0:
+		name = name[:k] + ext
+	else:
+		name = name + ext
+	return self.parent.find_or_declare([name])
+
+ at feature('glib2')
+def process_settings(self):
+	"""
+	Process the schema files in *settings_schema_files* to create :py:class:`waflib.Tools.glib2.glib_mkenums` instances. The
+	same files are validated through :py:class:`waflib.Tools.glib2.glib_validate_schema` tasks.
+
+	"""
+	enums_tgt_node = []
+	install_files = []
+
+	settings_schema_files = getattr(self, 'settings_schema_files', [])
+	if settings_schema_files and not self.env['GLIB_COMPILE_SCHEMAS']:
+		raise Errors.WafError ("Unable to process GSettings schemas - glib-compile-schemas was not found during configure")
+
+	# 1. process gsettings_enum_files (generate .enums.xml)
+	#
+	if hasattr(self, 'settings_enum_files'):
+		enums_task = self.create_task('glib_mkenums')
+
+		source_list = self.settings_enum_files
+		source_list = [self.path.find_resource(k) for k in source_list]
+		enums_task.set_inputs(source_list)
+		enums_task.env['GLIB_MKENUMS_SOURCE'] = [k.abspath() for k in source_list]
+
+		target = self.settings_enum_namespace + '.enums.xml'
+		tgt_node = self.path.find_or_declare(target)
+		enums_task.set_outputs(tgt_node)
+		enums_task.env['GLIB_MKENUMS_TARGET'] = tgt_node.abspath()
+		enums_tgt_node = [tgt_node]
+
+		install_files.append (tgt_node)
+
+		options = '--comments "<!-- @comment@ -->" --fhead "<schemalist>" --vhead "  <@type@ id=\\"%s. at EnumName@\\">" --vprod "    <value nick=\\"@valuenick@\\" value=\\"@valuenum@\\"/>" --vtail "  </@type@>" --ftail "</schemalist>" ' % (self.settings_enum_namespace)
+		enums_task.env['GLIB_MKENUMS_OPTIONS'] = options
+
+	# 2. process gsettings_schema_files (validate .gschema.xml files)
+	#
+	for schema in settings_schema_files:
+		schema_task = self.create_task ('glib_validate_schema')
+
+		schema_node = self.path.find_resource(schema)
+		if not schema_node:
+			raise Errors.WafError("Cannot find the schema file '%s'" % schema)
+		install_files.append(schema_node)
+		source_list = enums_tgt_node + [schema_node]
+
+		schema_task.set_inputs (source_list)
+		schema_task.env['GLIB_COMPILE_SCHEMAS_OPTIONS'] = [("--schema-file=" + k.abspath()) for k in source_list]
+
+		target_node = r_change_ext (schema_node, '.xml.valid')
+		schema_task.set_outputs (target_node)
+		schema_task.env['GLIB_VALIDATE_SCHEMA_OUTPUT'] = target_node.abspath()
+
+	# 3. schemas install task
+	def compile_schemas_callback(bld):
+		if not bld.is_install: return
+		Logs.pprint ('YELLOW','Updating GSettings schema cache')
+		command = Utils.subst_vars("${GLIB_COMPILE_SCHEMAS} ${GSETTINGSSCHEMADIR}", bld.env)
+		ret = self.bld.exec_command(command)
+
+	if self.bld.is_install:
+		if not self.env['GSETTINGSSCHEMADIR']:
+			raise Errors.WafError ('GSETTINGSSCHEMADIR not defined (should have been set up automatically during configure)')
+
+		if install_files:
+			self.bld.install_files (self.env['GSETTINGSSCHEMADIR'], install_files)
+
+			if not hasattr(self.bld, '_compile_schemas_registered'):
+				self.bld.add_post_fun (compile_schemas_callback)
+				self.bld._compile_schemas_registered = True
+
+class glib_validate_schema(Task.Task):
+	"""
+	Validate schema files
+	"""
+	run_str = 'rm -f ${GLIB_VALIDATE_SCHEMA_OUTPUT} && ${GLIB_COMPILE_SCHEMAS} --dry-run ${GLIB_COMPILE_SCHEMAS_OPTIONS} && touch ${GLIB_VALIDATE_SCHEMA_OUTPUT}'
+	color   = 'PINK'
+
+def configure(conf):
+	"""
+	Find the following programs:
+
+	* *glib-genmarshal* and set *GLIB_GENMARSHAL*
+	* *glib-mkenums* and set *GLIB_MKENUMS*
+	* *glib-compile-schemas* and set *GLIB_COMPILE_SCHEMAS* (not mandatory)
+
+	And set the variable *GSETTINGSSCHEMADIR*
+	"""
+	conf.find_program('glib-genmarshal', var='GLIB_GENMARSHAL')
+	conf.find_perl_program('glib-mkenums', var='GLIB_MKENUMS')
+
+	# when cross-compiling, gsettings.m4 locates the program with the following:
+	#   pkg-config --variable glib_compile_schemas gio-2.0
+	conf.find_program('glib-compile-schemas', var='GLIB_COMPILE_SCHEMAS', mandatory=False)
+
+	def getstr(varname):
+		return getattr(Options.options, varname, getattr(conf.env,varname, ''))
+
+	# TODO make this dependent on the gnu_dirs tool?
+	gsettingsschemadir = getstr('GSETTINGSSCHEMADIR')
+	if not gsettingsschemadir:
+		datadir = getstr('DATADIR')
+		if not datadir:
+			prefix = conf.env['PREFIX']
+			datadir = os.path.join(prefix, 'share')
+		gsettingsschemadir = os.path.join(datadir, 'glib-2.0', 'schemas')
+
+	conf.env['GSETTINGSSCHEMADIR'] = gsettingsschemadir
+
+def options(opt):
+	"""
+	Add the ``--gsettingsschemadir`` command-line option
+	"""
+	opt.add_option('--gsettingsschemadir', help='GSettings schema location [Default: ${datadir}/glib-2.0/schemas]',default='',dest='GSETTINGSSCHEMADIR')
+
diff --git a/xpdeint/waf/waflib/Tools/gnu_dirs.py b/xpdeint/waf/waflib/Tools/gnu_dirs.py
new file mode 100644
index 0000000..c9fbe5c
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/gnu_dirs.py
@@ -0,0 +1,128 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Ali Sabil, 2007
+
+"""
+Sets various standard variables such as INCLUDEDIR. SBINDIR and others. To use this module just call::
+
+	opt.load('gnu_dirs')
+
+and::
+
+	conf.load('gnu_dirs')
+
+Add options for the standard GNU directories, this tool will add the options
+found in autotools, and will update the environment with the following
+installation variables:
+
+============== ========================================= =======================
+Variable       Description                               Value
+============== ========================================= =======================
+PREFIX         architecture-independent files            /usr/local
+EXEC_PREFIX    architecture-dependent files              PREFIX
+BINDIR         user executables                          EXEC_PREFIX/bin
+SBINDIR        user executables                          EXEC_PREFIX/sbin
+LIBEXECDIR     program executables                       EXEC_PREFIX/libexec
+SYSCONFDIR     read-only single-machine data             PREFIX/etc
+SHAREDSTATEDIR modifiable architecture-independent data  PREFIX/com
+LOCALSTATEDIR  modifiable single-machine data            PREFIX/var
+LIBDIR         object code libraries                     EXEC_PREFIX/lib
+INCLUDEDIR     C header files                            PREFIX/include
+OLDINCLUDEDIR  C header files for non-gcc                /usr/include
+DATAROOTDIR    read-only arch.-independent data root     PREFIX/share
+DATADIR        read-only architecture-independent data   DATAROOTDIR
+INFODIR        info documentation                        DATAROOTDIR/info
+LOCALEDIR      locale-dependent data                     DATAROOTDIR/locale
+MANDIR         man documentation                         DATAROOTDIR/man
+DOCDIR         documentation root                        DATAROOTDIR/doc/APPNAME
+HTMLDIR        html documentation                        DOCDIR
+DVIDIR         dvi documentation                         DOCDIR
+PDFDIR         pdf documentation                         DOCDIR
+PSDIR          ps documentation                          DOCDIR
+============== ========================================= =======================
+"""
+
+import os
+from waflib import Utils, Options, Context
+
+_options = [x.split(', ') for x in '''
+bindir, user executables, ${EXEC_PREFIX}/bin
+sbindir, system admin executables, ${EXEC_PREFIX}/sbin
+libexecdir, program executables, ${EXEC_PREFIX}/libexec
+sysconfdir, read-only single-machine data, ${PREFIX}/etc
+sharedstatedir, modifiable architecture-independent data, ${PREFIX}/com
+localstatedir, modifiable single-machine data, ${PREFIX}/var
+libdir, object code libraries, ${EXEC_PREFIX}/lib
+includedir, C header files, ${PREFIX}/include
+oldincludedir, C header files for non-gcc, /usr/include
+datarootdir, read-only arch.-independent data root, ${PREFIX}/share
+datadir, read-only architecture-independent data, ${DATAROOTDIR}
+infodir, info documentation, ${DATAROOTDIR}/info
+localedir, locale-dependent data, ${DATAROOTDIR}/locale
+mandir, man documentation, ${DATAROOTDIR}/man
+docdir, documentation root, ${DATAROOTDIR}/doc/${PACKAGE}
+htmldir, html documentation, ${DOCDIR}
+dvidir, dvi documentation, ${DOCDIR}
+pdfdir, pdf documentation, ${DOCDIR}
+psdir, ps documentation, ${DOCDIR}
+'''.split('\n') if x]
+
+def configure(conf):
+	"""
+	Read the command-line options to set lots of variables in *conf.env*. The variables
+	BINDIR and LIBDIR will be overwritten.
+	"""
+	def get_param(varname, default):
+		return getattr(Options.options, varname, '') or default
+
+	env = conf.env
+	conf.env.LIBDIR = conf.env.BINDIR = []
+	env['EXEC_PREFIX'] = get_param('EXEC_PREFIX', env['PREFIX'])
+	env['PACKAGE'] = getattr(Context.g_module, 'APPNAME', None) or env['PACKAGE']
+
+	complete = False
+	iter = 0
+	while not complete and iter < len(_options) + 1:
+		iter += 1
+		complete = True
+		for name, help, default in _options:
+			name = name.upper()
+			if not env[name]:
+				try:
+					env[name] = Utils.subst_vars(get_param(name, default).replace('/', os.sep), env)
+				except TypeError:
+					complete = False
+	if not complete:
+		lst = [name for name, _, _ in _options if not env[name.upper()]]
+		raise conf.errors.WafError('Variable substitution failure %r' % lst)
+
+def options(opt):
+	"""
+	Add lots of command-line options, for example::
+
+		--exec-prefix: EXEC_PREFIX
+	"""
+	inst_dir = opt.add_option_group('Installation directories',
+'By default, "waf install" will put the files in\
+ "/usr/local/bin", "/usr/local/lib" etc. An installation prefix other\
+ than "/usr/local" can be given using "--prefix", for example "--prefix=$HOME"')
+
+	for k in ('--prefix', '--destdir'):
+		option = opt.parser.get_option(k)
+		if option:
+			opt.parser.remove_option(k)
+			inst_dir.add_option(option)
+
+	inst_dir.add_option('--exec-prefix',
+		help = 'installation prefix [Default: ${PREFIX}]',
+		default = '',
+		dest = 'EXEC_PREFIX')
+
+	dirs_options = opt.add_option_group('Pre-defined installation directories', '')
+
+	for name, help, default in _options:
+		option_name = '--' + name
+		str_default = default
+		str_help = '%s [Default: %s]' % (help, str_default)
+		dirs_options.add_option(option_name, help=str_help, default='', dest=name.upper())
+
diff --git a/xpdeint/waf/waflib/Tools/gxx.py b/xpdeint/waf/waflib/Tools/gxx.py
new file mode 100644
index 0000000..4ab486b
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/gxx.py
@@ -0,0 +1,153 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+# Ralf Habacker, 2006 (rh)
+# Yinon Ehrlich, 2009
+
+"""
+g++/llvm detection.
+"""
+
+import os, sys
+from waflib import Configure, Options, Utils
+from waflib.Tools import ccroot, ar
+from waflib.Configure import conf
+
+ at conf
+def find_gxx(conf):
+	"""
+	Find the program g++, and if present, try to detect its version number
+	"""
+	cxx = conf.find_program(['g++', 'c++'], var='CXX')
+	cxx = conf.cmd_to_list(cxx)
+	conf.get_cc_version(cxx, gcc=True)
+	conf.env.CXX_NAME = 'gcc'
+	conf.env.CXX      = cxx
+
+ at conf
+def gxx_common_flags(conf):
+	"""
+	Common flags for g++ on nearly all platforms
+	"""
+	v = conf.env
+
+	v['CXX_SRC_F']           = []
+	v['CXX_TGT_F']           = ['-c', '-o']
+
+	# linker
+	if not v['LINK_CXX']: v['LINK_CXX'] = v['CXX']
+	v['CXXLNK_SRC_F']        = []
+	v['CXXLNK_TGT_F']        = ['-o']
+	v['CPPPATH_ST']          = '-I%s'
+	v['DEFINES_ST']          = '-D%s'
+
+	v['LIB_ST']              = '-l%s' # template for adding libs
+	v['LIBPATH_ST']          = '-L%s' # template for adding libpaths
+	v['STLIB_ST']            = '-l%s'
+	v['STLIBPATH_ST']        = '-L%s'
+	v['RPATH_ST']            = '-Wl,-rpath,%s'
+
+	v['SONAME_ST']           = '-Wl,-h,%s'
+	v['SHLIB_MARKER']        = '-Wl,-Bdynamic'
+	v['STLIB_MARKER']        = '-Wl,-Bstatic'
+
+	# program
+	v['cxxprogram_PATTERN']  = '%s'
+
+	# shared library
+	v['CXXFLAGS_cxxshlib']   = ['-fPIC']
+	v['LINKFLAGS_cxxshlib']  = ['-shared']
+	v['cxxshlib_PATTERN']    = 'lib%s.so'
+
+	# static lib
+	v['LINKFLAGS_cxxstlib']  = ['-Wl,-Bstatic']
+	v['cxxstlib_PATTERN']    = 'lib%s.a'
+
+	# osx stuff
+	v['LINKFLAGS_MACBUNDLE'] = ['-bundle', '-undefined', 'dynamic_lookup']
+	v['CXXFLAGS_MACBUNDLE']  = ['-fPIC']
+	v['macbundle_PATTERN']   = '%s.bundle'
+
+ at conf
+def gxx_modifier_win32(conf):
+	"""Configuration flags for executing gcc on Windows"""
+	v = conf.env
+	v['cxxprogram_PATTERN']  = '%s.exe'
+
+	v['cxxshlib_PATTERN']    = '%s.dll'
+	v['implib_PATTERN']      = 'lib%s.dll.a'
+	v['IMPLIB_ST']           = '-Wl,--out-implib,%s'
+
+	v['CXXFLAGS_cxxshlib']   = []
+
+	v.append_value('CXXFLAGS_cxxshlib', ['-DDLL_EXPORT']) # TODO adding nonstandard defines like this DLL_EXPORT is not a good idea
+
+	# Auto-import is enabled by default even without this option,
+	# but enabling it explicitly has the nice effect of suppressing the rather boring, debug-level messages
+	# that the linker emits otherwise.
+	v.append_value('LINKFLAGS', ['-Wl,--enable-auto-import'])
+
+ at conf
+def gxx_modifier_cygwin(conf):
+	"""Configuration flags for executing g++ on Cygwin"""
+	gxx_modifier_win32(conf)
+	v = conf.env
+	v['cxxshlib_PATTERN']    = 'cyg%s.dll'
+	v.append_value('LINKFLAGS_cxxshlib', ['-Wl,--enable-auto-image-base'])
+	v['CXXFLAGS_cxxshlib']   = []
+
+ at conf
+def gxx_modifier_darwin(conf):
+	"""Configuration flags for executing g++ on MacOS"""
+	v = conf.env
+	v['CXXFLAGS_cxxshlib']   = ['-fPIC', '-compatibility_version', '1', '-current_version', '1']
+	v['LINKFLAGS_cxxshlib']  = ['-dynamiclib']
+	v['cxxshlib_PATTERN']    = 'lib%s.dylib'
+	v['FRAMEWORKPATH_ST']    = '-F%s'
+	v['FRAMEWORK_ST']        = ['-framework']
+	v['ARCH_ST']             = ['-arch']
+
+	v['LINKFLAGS_cxxstlib']  = []
+
+	v['SHLIB_MARKER']        = []
+	v['STLIB_MARKER']        = []
+	v['SONAME_ST']           = []
+
+ at conf
+def gxx_modifier_aix(conf):
+	"""Configuration flags for executing g++ on AIX"""
+	v = conf.env
+	v['LINKFLAGS_cxxprogram']= ['-Wl,-brtl']
+
+	v['LINKFLAGS_cxxshlib']  = ['-shared', '-Wl,-brtl,-bexpfull']
+	v['SHLIB_MARKER']        = []
+
+ at conf
+def gxx_modifier_hpux(conf):
+	v = conf.env
+	v['SHLIB_MARKER']        = []
+	v['CFLAGS_cxxshlib']     = ['-fPIC','-DPIC']
+	v['cxxshlib_PATTERN']    = 'lib%s.sl'
+
+ at conf
+def gxx_modifier_platform(conf):
+	"""Execute platform-specific functions based on *gxx_modifier_+NAME*"""
+	# * set configurations specific for a platform.
+	# * the destination platform is detected automatically by looking at the macros the compiler predefines,
+	#   and if it's not recognised, it fallbacks to sys.platform.
+	gxx_modifier_func = getattr(conf, 'gxx_modifier_' + conf.env.DEST_OS, None)
+	if gxx_modifier_func:
+			gxx_modifier_func()
+
+def configure(conf):
+	"""
+	Configuration for g++
+	"""
+	conf.find_gxx()
+	conf.find_ar()
+	conf.gxx_common_flags()
+	conf.gxx_modifier_platform()
+	conf.cxx_load_tools()
+	conf.cxx_add_flags()
+	conf.link_add_flags()
+
diff --git a/xpdeint/waf/waflib/Tools/icc.py b/xpdeint/waf/waflib/Tools/icc.py
new file mode 100644
index 0000000..7f506f8
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/icc.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Stian Selnes, 2008
+# Thomas Nagy 2009-2010 (ita)
+
+"""
+Detect the Intel C compiler
+"""
+
+import os, sys
+from waflib.Tools import ccroot, ar, gcc
+from waflib.Configure import conf
+
+ at conf
+def find_icc(conf):
+	"""
+	Find the program icc and execute it to ensure it really is icc
+	"""
+	if sys.platform == 'cygwin':
+		conf.fatal('The Intel compiler does not work on Cygwin')
+
+	v = conf.env
+	cc = None
+	if v['CC']: cc = v['CC']
+	elif 'CC' in conf.environ: cc = conf.environ['CC']
+	if not cc: cc = conf.find_program('icc', var='CC')
+	if not cc: cc = conf.find_program('ICL', var='CC')
+	if not cc: conf.fatal('Intel C Compiler (icc) was not found')
+	cc = conf.cmd_to_list(cc)
+
+	conf.get_cc_version(cc, icc=True)
+	v['CC'] = cc
+	v['CC_NAME'] = 'icc'
+
+def configure(conf):
+	conf.find_icc()
+	conf.find_ar()
+	conf.gcc_common_flags()
+	conf.gcc_modifier_platform()
+	conf.cc_load_tools()
+	conf.cc_add_flags()
+	conf.link_add_flags()
diff --git a/xpdeint/waf/waflib/Tools/icpc.py b/xpdeint/waf/waflib/Tools/icpc.py
new file mode 100644
index 0000000..138f882
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/icpc.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy 2009-2010 (ita)
+
+"""
+Detect the Intel C++ compiler
+"""
+
+import os, sys
+from waflib.Tools import ccroot, ar, gxx
+from waflib.Configure import conf
+
+ at conf
+def find_icpc(conf):
+	"""
+	Find the program icpc, and execute it to ensure it really is icpc
+	"""
+	if sys.platform == 'cygwin':
+		conf.fatal('The Intel compiler does not work on Cygwin')
+
+	v = conf.env
+	cxx = None
+	if v['CXX']: cxx = v['CXX']
+	elif 'CXX' in conf.environ: cxx = conf.environ['CXX']
+	if not cxx: cxx = conf.find_program('icpc', var='CXX')
+	if not cxx: conf.fatal('Intel C++ Compiler (icpc) was not found')
+	cxx = conf.cmd_to_list(cxx)
+
+	conf.get_cc_version(cxx, icc=True)
+	v['CXX'] = cxx
+	v['CXX_NAME'] = 'icc'
+
+def configure(conf):
+	conf.find_icpc()
+	conf.find_ar()
+	conf.gxx_common_flags()
+	conf.gxx_modifier_platform()
+	conf.cxx_load_tools()
+	conf.cxx_add_flags()
+	conf.link_add_flags()
+
diff --git a/xpdeint/waf/waflib/Tools/ifort.py b/xpdeint/waf/waflib/Tools/ifort.py
new file mode 100644
index 0000000..7588416
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/ifort.py
@@ -0,0 +1,58 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# DC 2008
+# Thomas Nagy 2010 (ita)
+
+import re
+from waflib import Utils
+from waflib.Tools import fc, fc_config, fc_scan
+from waflib.Configure import conf
+
+ at conf
+def find_ifort(conf):
+	fc = conf.find_program('ifort', var='FC')
+	fc = conf.cmd_to_list(fc)
+	conf.get_ifort_version(fc)
+	conf.env.FC_NAME = 'IFORT'
+
+ at conf
+def ifort_modifier_cygwin(conf):
+	raise NotImplementedError("Ifort on cygwin not yet implemented")
+
+ at conf
+def ifort_modifier_win32(conf):
+	fc_config.fortran_modifier_win32(conf)
+
+ at conf
+def ifort_modifier_darwin(conf):
+	fc_config.fortran_modifier_darwin(conf)
+
+ at conf
+def ifort_modifier_platform(conf):
+	dest_os = conf.env['DEST_OS'] or Utils.unversioned_sys_platform()
+	ifort_modifier_func = getattr(conf, 'ifort_modifier_' + dest_os, None)
+	if ifort_modifier_func:
+		ifort_modifier_func()
+
+ at conf
+def get_ifort_version(conf, fc):
+	"""get the compiler version"""
+
+	version_re = re.compile(r"ifort\s*\(IFORT\)\s*(?P<major>\d*)\.(?P<minor>\d*)", re.I).search
+	cmd = fc + ['--version']
+	out, err = fc_config.getoutput(conf, cmd, stdin=False)
+	if out:
+		match = version_re(out)
+	else:
+		match = version_re(err)
+	if not match:
+		conf.fatal('cannot determine ifort version.')
+	k = match.groupdict()
+	conf.env['FC_VERSION'] = (k['major'], k['minor'])
+
+def configure(conf):
+	conf.find_ifort()
+	conf.find_ar()
+	conf.fc_flags()
+	conf.ifort_modifier_platform()
+
diff --git a/xpdeint/waf/waflib/Tools/intltool.py b/xpdeint/waf/waflib/Tools/intltool.py
new file mode 100644
index 0000000..207508d
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/intltool.py
@@ -0,0 +1,176 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+
+"""
+Support for translation tools such as msgfmt and intltool
+
+Usage::
+
+	def configure(conf):
+		conf.load('gnu_dirs intltool')
+
+	def build(bld):
+		# process the .po files into .gmo files, and install them in LOCALEDIR
+		bld(features='intltool_po', appname='myapp', podir='po', install_path="${LOCALEDIR}")
+
+		# process an input file, substituting the translations from the po dir
+		bld(
+			features  = "intltool_in",
+			podir     = "../po",
+			flags     = ["-d", "-q", "-u", "-c"],
+			source    = 'kupfer.desktop.in',
+			install_path = "${DATADIR}/applications",
+		)
+
+Usage of the :py:mod:`waflib.Tools.gnu_dirs` is recommended, but not obligatory.
+"""
+
+import os, re
+from waflib import Configure, TaskGen, Task, Utils, Runner, Options, Build, Logs
+import waflib.Tools.ccroot
+from waflib.TaskGen import feature, before_method
+from waflib.Logs import error
+
+ at before_method('process_source')
+ at feature('intltool_in')
+def apply_intltool_in_f(self):
+	"""
+	Create tasks to translate files by intltool-merge::
+
+		def build(bld):
+			bld(
+				features  = "intltool_in",
+				podir     = "../po",
+				flags     = ["-d", "-q", "-u", "-c"],
+				source    = 'kupfer.desktop.in',
+				install_path = "${DATADIR}/applications",
+			)
+
+	:param podir: location of the .po files
+	:type podir: string
+	:param source: source files to process
+	:type source: list of string
+	:param flags: compilation flags ("-quc" by default)
+	:type flags: list of string
+	:param install_path: installation path
+	:type install_path: string
+	"""
+	try: self.meths.remove('process_source')
+	except ValueError: pass
+
+	if not self.env.LOCALEDIR:
+		self.env.LOCALEDIR = self.env.PREFIX + '/share/locale'
+
+	for i in self.to_list(self.source):
+		node = self.path.find_resource(i)
+
+		podir = getattr(self, 'podir', 'po')
+		podirnode = self.path.find_dir(podir)
+		if not podirnode:
+			error("could not find the podir %r" % podir)
+			continue
+
+		cache = getattr(self, 'intlcache', '.intlcache')
+		self.env['INTLCACHE'] = os.path.join(self.path.bldpath(), podir, cache)
+		self.env['INTLPODIR'] = podirnode.bldpath()
+		self.env['INTLFLAGS'] = getattr(self, 'flags', ['-q', '-u', '-c'])
+
+		task = self.create_task('intltool', node, node.change_ext(''))
+		inst = getattr(self, 'install_path', '${LOCALEDIR}')
+		if inst:
+			self.bld.install_files(inst, task.outputs)
+
+ at feature('intltool_po')
+def apply_intltool_po(self):
+	"""
+	Create tasks to process po files::
+
+		def build(bld):
+			bld(features='intltool_po', appname='myapp', podir='po', install_path="${LOCALEDIR}")
+
+	The relevant task generator arguments are:
+
+	:param podir: directory of the .po files
+	:type podir: string
+	:param appname: name of the application
+	:type appname: string
+	:param install_path: installation directory
+	:type install_path: string
+
+	The file LINGUAS must be present in the directory pointed by *podir* and list the translation files to process.
+	"""
+	try: self.meths.remove('process_source')
+	except ValueError: pass
+
+	if not self.env.LOCALEDIR:
+		self.env.LOCALEDIR = self.env.PREFIX + '/share/locale'
+
+	appname = getattr(self, 'appname', 'set_your_app_name')
+	podir = getattr(self, 'podir', '')
+	inst = getattr(self, 'install_path', '${LOCALEDIR}')
+
+	linguas = self.path.find_node(os.path.join(podir, 'LINGUAS'))
+	if linguas:
+		# scan LINGUAS file for locales to process
+		file = open(linguas.abspath())
+		langs = []
+		for line in file.readlines():
+			# ignore lines containing comments
+			if not line.startswith('#'):
+				langs += line.split()
+		file.close()
+		re_linguas = re.compile('[-a-zA-Z_ at .]+')
+		for lang in langs:
+			# Make sure that we only process lines which contain locales
+			if re_linguas.match(lang):
+				node = self.path.find_resource(os.path.join(podir, re_linguas.match(lang).group() + '.po'))
+				task = self.create_task('po', node, node.change_ext('.mo'))
+
+				if inst:
+					filename = task.outputs[0].name
+					(langname, ext) = os.path.splitext(filename)
+					inst_file = inst + os.sep + langname + os.sep + 'LC_MESSAGES' + os.sep + appname + '.mo'
+					self.bld.install_as(inst_file, task.outputs[0], chmod=getattr(self, 'chmod', Utils.O644), env=task.env)
+
+	else:
+		Logs.pprint('RED', "Error no LINGUAS file found in po directory")
+
+class po(Task.Task):
+	"""
+	Compile .po files into .gmo files
+	"""
+	run_str = '${MSGFMT} -o ${TGT} ${SRC}'
+	color   = 'BLUE'
+
+class intltool(Task.Task):
+	"""
+	Let intltool-merge translate an input file
+	"""
+	run_str = '${INTLTOOL} ${INTLFLAGS} ${INTLCACHE} ${INTLPODIR} ${SRC} ${TGT}'
+	color   = 'BLUE'
+
+def configure(conf):
+	"""
+	Detect the program *msgfmt* and set *conf.env.MSGFMT*.
+	Detect the program *intltool-merge* and set *conf.env.INTLTOOL*.
+	It is possible to set INTLTOOL in the environment, but it must not have spaces in it::
+
+		$ INTLTOOL="/path/to/the program/intltool" waf configure
+
+	If a C/C++ compiler is present, execute a compilation test to find the header *locale.h*.
+	"""
+	conf.find_program('msgfmt', var='MSGFMT')
+	conf.find_perl_program('intltool-merge', var='INTLTOOL')
+
+	prefix  = conf.env.PREFIX
+	datadir = conf.env.DATADIR
+	if not datadir:
+		datadir = os.path.join(prefix,'share')
+
+	conf.define('LOCALEDIR', os.path.join(datadir, 'locale').replace('\\', '\\\\'))
+	conf.define('DATADIR', datadir.replace('\\', '\\\\'))
+
+	if conf.env.CC or conf.env.CXX:
+		conf.check(header_name='locale.h')
+
diff --git a/xpdeint/waf/waflib/Tools/irixcc.py b/xpdeint/waf/waflib/Tools/irixcc.py
new file mode 100644
index 0000000..f609359
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/irixcc.py
@@ -0,0 +1,63 @@
+#! /usr/bin/env python
+# imported from samba
+
+"""
+compiler definition for irix/MIPSpro cc compiler
+based on suncc.py from waf
+"""
+
+import os
+from waflib import Utils
+from waflib.Tools import ccroot, ar
+from waflib.Configure import conf
+
+ at conf
+def find_irixcc(conf):
+	v = conf.env
+	cc = None
+	if v['CC']: cc = v['CC']
+	elif 'CC' in conf.environ: cc = conf.environ['CC']
+	if not cc: cc = conf.find_program('cc', var='CC')
+	if not cc: conf.fatal('irixcc was not found')
+	cc = conf.cmd_to_list(cc)
+
+	try:
+		conf.cmd_and_log(cc + ['-version'])
+	except:
+		conf.fatal('%r -version could not be executed' % cc)
+
+	v['CC']  = cc
+	v['CC_NAME'] = 'irix'
+
+ at conf
+def irixcc_common_flags(conf):
+	v = conf.env
+
+	v['CC_SRC_F']            = ''
+	v['CC_TGT_F']            = ['-c', '-o']
+	v['CPPPATH_ST']          = '-I%s'
+	v['DEFINES_ST']          = '-D%s'
+
+	# linker
+	if not v['LINK_CC']: v['LINK_CC'] = v['CC']
+	v['CCLNK_SRC_F']         = ''
+	v['CCLNK_TGT_F']         = ['-o']
+
+	v['LIB_ST']              = '-l%s' # template for adding libs
+	v['LIBPATH_ST']          = '-L%s' # template for adding libpaths
+	v['STLIB_ST']            = '-l%s'
+	v['STLIBPATH_ST']        = '-L%s'
+
+	v['cprogram_PATTERN']     = '%s'
+	v['cshlib_PATTERN']       = 'lib%s.so'
+	v['cstlib_PATTERN']      = 'lib%s.a'
+
+def configure(conf):
+	conf.find_irixcc()
+	conf.find_cpp()
+	conf.find_ar()
+	conf.irixcc_common_flags()
+	conf.cc_load_tools()
+	conf.cc_add_flags()
+	conf.link_add_flags()
+
diff --git a/xpdeint/waf/waflib/Tools/javaw.py b/xpdeint/waf/waflib/Tools/javaw.py
new file mode 100644
index 0000000..0e8ed95
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/javaw.py
@@ -0,0 +1,411 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+
+"""
+Java support
+
+Javac is one of the few compilers that behaves very badly:
+
+#. it outputs files where it wants to (-d is only for the package root)
+
+#. it recompiles files silently behind your back
+
+#. it outputs an undefined amount of files (inner classes)
+
+Remember that the compilation can be performed using Jython[1] rather than regular Python. Instead of
+running one of the following commands::
+
+    ./waf configure
+    python waf configure
+
+You would have to run::
+
+    java -jar /path/to/jython.jar waf configure
+
+[1] http://www.jython.org/
+"""
+
+import os, re
+from waflib.Configure import conf
+from waflib import TaskGen, Task, Utils, Options, Build, Errors, Node
+from waflib.TaskGen import feature, before_method, after_method
+
+from waflib.Tools import ccroot
+ccroot.USELIB_VARS['javac'] = set(['CLASSPATH', 'JAVACFLAGS'])
+
+
+SOURCE_RE = '**/*.java'
+JAR_RE = '**/*'
+
+class_check_source = '''
+public class Test {
+	public static void main(String[] argv) {
+		Class lib;
+		if (argv.length < 1) {
+			System.err.println("Missing argument");
+			System.exit(77);
+		}
+		try {
+			lib = Class.forName(argv[0]);
+		} catch (ClassNotFoundException e) {
+			System.err.println("ClassNotFoundException");
+			System.exit(1);
+		}
+		lib = null;
+		System.exit(0);
+	}
+}
+'''
+
+ at feature('javac')
+ at before_method('process_source')
+def apply_java(self):
+	"""
+	Create a javac task for compiling *.java files*. There can be
+	only one javac task by task generator.
+	"""
+	Utils.def_attrs(self, jarname='', classpath='',
+		sourcepath='.', srcdir='.',
+		jar_mf_attributes={}, jar_mf_classpath=[])
+
+	nodes_lst = []
+
+	outdir = getattr(self, 'outdir', None)
+	if outdir:
+		if not isinstance(outdir, Node.Node):
+			outdir = self.path.get_bld().make_node(self.outdir)
+	else:
+		outdir = self.path.get_bld()
+	outdir.mkdir()
+	self.outdir = outdir
+	self.env['OUTDIR'] = outdir.abspath()
+
+	self.javac_task = tsk = self.create_task('javac')
+	tmp = []
+
+	srcdir = getattr(self, 'srcdir', '')
+	if isinstance(srcdir, Node.Node):
+		srcdir = [srcdir]
+	for x in Utils.to_list(srcdir):
+		if isinstance(x, Node.Node):
+			y = x
+		else:
+			y = self.path.find_dir(x)
+			if not y:
+				self.bld.fatal('Could not find the folder %s from %s' % (x, self.path))
+		tmp.append(y)
+	tsk.srcdir = tmp
+
+	if getattr(self, 'compat', None):
+		tsk.env.append_value('JAVACFLAGS', ['-source', self.compat])
+
+	if hasattr(self, 'sourcepath'):
+		fold = [isinstance(x, Node.Node) and x or self.path.find_dir(x) for x in self.to_list(self.sourcepath)]
+		names = os.pathsep.join([x.srcpath() for x in fold])
+	else:
+		names = [x.srcpath() for x in tsk.srcdir]
+
+	if names:
+		tsk.env.append_value('JAVACFLAGS', ['-sourcepath', names])
+
+ at feature('javac')
+ at after_method('apply_java')
+def use_javac_files(self):
+	"""
+	Process the *use* attribute referring to other java compilations
+	"""
+	lst = []
+	self.uselib = self.to_list(getattr(self, 'uselib', []))
+	names = self.to_list(getattr(self, 'use', []))
+	get = self.bld.get_tgen_by_name
+	for x in names:
+		try:
+			y = get(x)
+		except:
+			self.uselib.append(x)
+		else:
+			y.post()
+			lst.append(y.jar_task.outputs[0].abspath())
+			self.javac_task.set_run_after(y.jar_task)
+
+	if lst:
+		self.env.append_value('CLASSPATH', lst)
+
+ at feature('javac')
+ at after_method('apply_java', 'propagate_uselib_vars', 'use_javac_files')
+def set_classpath(self):
+	"""
+	Set the CLASSPATH value on the *javac* task previously created.
+	"""
+	self.env.append_value('CLASSPATH', getattr(self, 'classpath', []))
+	for x in self.tasks:
+		x.env.CLASSPATH = os.pathsep.join(self.env.CLASSPATH) + os.pathsep
+
+ at feature('jar')
+ at after_method('apply_java', 'use_javac_files')
+ at before_method('process_source')
+def jar_files(self):
+	"""
+	Create a jar task. There can be only one jar task by task generator.
+	"""
+	destfile = getattr(self, 'destfile', 'test.jar')
+	jaropts = getattr(self, 'jaropts', [])
+        manifest = getattr(self, 'manifest', None)
+
+	basedir = getattr(self, 'basedir', None)
+	if basedir:
+		if not isinstance(self.basedir, Node.Node):
+			basedir = self.path.get_bld().make_node(basedir)
+	else:
+		basedir = self.path.get_bld()
+	if not basedir:
+		self.bld.fatal('Could not find the basedir %r for %r' % (self.basedir, self))
+
+	self.jar_task = tsk = self.create_task('jar_create')
+        if manifest:
+            jarcreate = getattr(self, 'jarcreate', 'cfm')
+            node = self.path.find_node(manifest)
+            tsk.dep_nodes.append(node)
+            jaropts.insert(0, node.abspath())
+        else:
+            jarcreate = getattr(self, 'jarcreate', 'cf')
+	if not isinstance(destfile, Node.Node):
+		destfile = self.path.find_or_declare(destfile)
+	if not destfile:
+		self.bld.fatal('invalid destfile %r for %r' % (destfile, self))
+	tsk.set_outputs(destfile)
+	tsk.basedir = basedir
+
+	jaropts.append('-C')
+	jaropts.append(basedir.bldpath())
+	jaropts.append('.')
+
+	tsk.env['JAROPTS'] = jaropts
+	tsk.env['JARCREATE'] = jarcreate
+
+	if getattr(self, 'javac_task', None):
+		tsk.set_run_after(self.javac_task)
+
+ at feature('jar')
+ at after_method('jar_files')
+def use_jar_files(self):
+	"""
+	Process the *use* attribute to set the build order on the
+	tasks created by another task generator.
+	"""
+	lst = []
+	self.uselib = self.to_list(getattr(self, 'uselib', []))
+	names = self.to_list(getattr(self, 'use', []))
+	get = self.bld.get_tgen_by_name
+	for x in names:
+		try:
+			y = get(x)
+		except:
+			self.uselib.append(x)
+		else:
+			y.post()
+			self.jar_task.run_after.update(y.tasks)
+
+class jar_create(Task.Task):
+	"""
+	Create a jar file
+	"""
+	color   = 'GREEN'
+	run_str = '${JAR} ${JARCREATE} ${TGT} ${JAROPTS}'
+
+	def runnable_status(self):
+		"""
+		Wait for dependent tasks to be executed, then read the
+		files to update the list of inputs.
+		"""
+		for t in self.run_after:
+			if not t.hasrun:
+				return Task.ASK_LATER
+		if not self.inputs:
+			global JAR_RE
+			try:
+				self.inputs = [x for x in self.basedir.ant_glob(JAR_RE, remove=False) if id(x) != id(self.outputs[0])]
+			except:
+				raise Errors.WafError('Could not find the basedir %r for %r' % (self.basedir, self))
+		return super(jar_create, self).runnable_status()
+
+class javac(Task.Task):
+	"""
+	Compile java files
+	"""
+	color   = 'BLUE'
+
+	nocache = True
+	"""
+	The .class files cannot be put into a cache at the moment
+	"""
+
+	vars    = ['CLASSPATH', 'JAVACFLAGS', 'JAVAC', 'OUTDIR']
+	"""
+	The javac task will be executed again if the variables CLASSPATH, JAVACFLAGS, JAVAC or OUTDIR change.
+	"""
+
+	def runnable_status(self):
+		"""
+		Wait for dependent tasks to be complete, then read the file system to find the input nodes.
+		"""
+		for t in self.run_after:
+			if not t.hasrun:
+				return Task.ASK_LATER
+
+		if not self.inputs:
+			global SOURCE_RE
+			self.inputs  = []
+			for x in self.srcdir:
+				self.inputs.extend(x.ant_glob(SOURCE_RE, remove=False))
+		return super(javac, self).runnable_status()
+
+	def run(self):
+		"""
+		Execute the javac compiler
+		"""
+		env = self.env
+		gen = self.generator
+		bld = gen.bld
+		wd = bld.bldnode.abspath()
+		def to_list(xx):
+			if isinstance(xx, str): return [xx]
+			return xx
+		self.last_cmd = lst = []
+		lst.extend(to_list(env['JAVAC']))
+		lst.extend(['-classpath'])
+		lst.extend(to_list(env['CLASSPATH']))
+		lst.extend(['-d'])
+		lst.extend(to_list(env['OUTDIR']))
+		lst.extend(to_list(env['JAVACFLAGS']))
+		lst.extend([a.path_from(bld.bldnode) for a in self.inputs])
+		lst = [x for x in lst if x]
+		return self.exec_command(lst, cwd=wd, env=env.env or None)
+
+	def post_run(self):
+		"""
+		"""
+		for n in self.generator.outdir.ant_glob('**/*.class'):
+			n.sig = Utils.h_file(n.abspath()) # careful with this
+		self.generator.bld.task_sigs[self.uid()] = self.cache_sig
+
+def configure(self):
+	"""
+	Detect the javac, java and jar programs
+	"""
+	# If JAVA_PATH is set, we prepend it to the path list
+	java_path = self.environ['PATH'].split(os.pathsep)
+	v = self.env
+
+	if 'JAVA_HOME' in self.environ:
+		java_path = [os.path.join(self.environ['JAVA_HOME'], 'bin')] + java_path
+		self.env['JAVA_HOME'] = [self.environ['JAVA_HOME']]
+
+	for x in 'javac java jar'.split():
+		self.find_program(x, var=x.upper(), path_list=java_path)
+		self.env[x.upper()] = self.cmd_to_list(self.env[x.upper()])
+
+	if 'CLASSPATH' in self.environ:
+		v['CLASSPATH'] = self.environ['CLASSPATH']
+
+	if not v['JAR']: self.fatal('jar is required for making java packages')
+	if not v['JAVAC']: self.fatal('javac is required for compiling java classes')
+	v['JARCREATE'] = 'cf' # can use cvf
+	v['JAVACFLAGS'] = []
+
+ at conf
+def check_java_class(self, classname, with_classpath=None):
+	"""
+	Check if the specified java class exists
+
+	:param classname: class to check, like java.util.HashMap
+	:type classname: string
+	:param with_classpath: additional classpath to give
+	:type with_classpath: string
+	"""
+
+	import shutil
+
+	javatestdir = '.waf-javatest'
+
+	classpath = javatestdir
+	if self.env['CLASSPATH']:
+		classpath += os.pathsep + self.env['CLASSPATH']
+	if isinstance(with_classpath, str):
+		classpath += os.pathsep + with_classpath
+
+	shutil.rmtree(javatestdir, True)
+	os.mkdir(javatestdir)
+
+	java_file = open(os.path.join(javatestdir, 'Test.java'), 'w')
+	java_file.write(class_check_source)
+	java_file.close()
+
+	# Compile the source
+	self.exec_command(self.env['JAVAC'] + [os.path.join(javatestdir, 'Test.java')], shell=False)
+
+	# Try to run the app
+	cmd = self.env['JAVA'] + ['-cp', classpath, 'Test', classname]
+	self.to_log("%s\n" % str(cmd))
+	found = self.exec_command(cmd, shell=False)
+
+	self.msg('Checking for java class %s' % classname, not found)
+
+	shutil.rmtree(javatestdir, True)
+
+	return found
+
+ at conf
+def check_jni_headers(conf):
+	"""
+	Check for jni headers and libraries. On success the conf.env variables xxx_JAVA are added for use in C/C++ targets::
+
+		def options(opt):
+			opt.load('compiler_c')
+
+		def configure(conf):
+			conf.load('compiler_c java')
+			conf.check_jni_headers()
+
+		def build(bld):
+			bld.shlib(source='a.c', target='app', use='JAVA')
+	"""
+
+	if not conf.env.CC_NAME and not conf.env.CXX_NAME:
+		conf.fatal('load a compiler first (gcc, g++, ..)')
+
+	if not conf.env.JAVA_HOME:
+		conf.fatal('set JAVA_HOME in the system environment')
+
+	# jni requires the jvm
+	javaHome = conf.env['JAVA_HOME'][0]
+
+	dir = conf.root.find_dir(conf.env.JAVA_HOME[0] + '/include')
+	if dir is None:
+		conf.fatal('JAVA_HOME does not seem to be set properly')
+
+	f = dir.ant_glob('**/(jni|jni_md).h')
+	incDirs = [x.parent.abspath() for x in f]
+
+	dir = conf.root.find_dir(conf.env.JAVA_HOME[0])
+	f = dir.ant_glob('**/*jvm.(so|dll|dylib)')
+	libDirs = [x.parent.abspath() for x in f] or [javaHome]
+
+	# On windows, we need both the .dll and .lib to link.  On my JDK, they are
+	# in different directories...
+	f = dir.ant_glob('**/*jvm.(lib)')
+	if f:
+		libDirs = [[x, y.parent.abspath()] for x in libDirs for y in f]
+
+	for d in libDirs:
+		try:
+			conf.check(header_name='jni.h', define_name='HAVE_JNI_H', lib='jvm',
+				libpath=d, includes=incDirs, uselib_store='JAVA', uselib='JAVA')
+		except:
+			pass
+		else:
+			break
+	else:
+		conf.fatal('could not find lib jvm in %r (see config.log)' % libDirs)
+
diff --git a/xpdeint/waf/waflib/Tools/kde4.py b/xpdeint/waf/waflib/Tools/kde4.py
new file mode 100644
index 0000000..700b14d
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/kde4.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+
+"""
+Support for the KDE4 libraries and msgfmt
+"""
+
+import os, sys, re
+from waflib import Options, TaskGen, Task, Utils
+from waflib.TaskGen import feature, after_method
+
+ at feature('msgfmt')
+def apply_msgfmt(self):
+	"""
+	Process all languages to create .mo files and to install them::
+
+		def build(bld):
+			bld(features='msgfmt', langs='es de fr', appname='myapp', install_path='${KDE4_LOCALE_INSTALL_DIR}')
+	"""
+	for lang in self.to_list(self.langs):
+		node = self.path.find_resource(lang+'.po')
+		task = self.create_task('msgfmt', node, node.change_ext('.mo'))
+
+		langname = lang.split('/')
+		langname = langname[-1]
+
+		inst = getattr(self, 'install_path', '${KDE4_LOCALE_INSTALL_DIR}')
+
+		self.bld.install_as(
+			inst + os.sep + langname + os.sep + 'LC_MESSAGES' + os.sep + getattr(self, 'appname', 'set_your_appname') + '.mo',
+			task.outputs[0],
+			chmod = getattr(self, 'chmod', Utils.O644))
+
+class msgfmt(Task.Task):
+	"""
+	Transform .po files into .mo files
+	"""
+	color   = 'BLUE'
+	run_str = '${MSGFMT} ${SRC} -o ${TGT}'
+
+def configure(self):
+	"""
+	Detect kde4-config and set various variables for the *use* system::
+
+		def options(opt):
+			opt.load('compiler_cxx kde4')
+		def configure(conf):
+			conf.load('compiler_cxx kde4')
+		def build(bld):
+			bld.program(source='main.c', target='app', use='KDECORE KIO KHTML')
+	"""
+	kdeconfig = self.find_program('kde4-config')
+	prefix = self.cmd_and_log('%s --prefix' % kdeconfig).strip()
+	fname = '%s/share/apps/cmake/modules/KDELibsDependencies.cmake' % prefix
+	try: os.stat(fname)
+	except OSError:
+		fname = '%s/share/kde4/apps/cmake/modules/KDELibsDependencies.cmake' % prefix
+		try: os.stat(fname)
+		except OSError: self.fatal('could not open %s' % fname)
+
+	try:
+		txt = Utils.readf(fname)
+	except (OSError, IOError):
+		self.fatal('could not read %s' % fname)
+
+	txt = txt.replace('\\\n', '\n')
+	fu = re.compile('#(.*)\n')
+	txt = fu.sub('', txt)
+
+	setregexp = re.compile('([sS][eE][tT]\s*\()\s*([^\s]+)\s+\"([^"]+)\"\)')
+	found = setregexp.findall(txt)
+
+	for (_, key, val) in found:
+		#print key, val
+		self.env[key] = val
+
+	# well well, i could just write an interpreter for cmake files
+	self.env['LIB_KDECORE']= ['kdecore']
+	self.env['LIB_KDEUI']  = ['kdeui']
+	self.env['LIB_KIO']    = ['kio']
+	self.env['LIB_KHTML']  = ['khtml']
+	self.env['LIB_KPARTS'] = ['kparts']
+
+	self.env['LIBPATH_KDECORE']  = [self.env['KDE4_LIB_INSTALL_DIR']]
+	self.env['INCLUDES_KDECORE'] = [self.env['KDE4_INCLUDE_INSTALL_DIR']]
+	self.env.append_value('INCLUDES_KDECORE', [self.env['KDE4_INCLUDE_INSTALL_DIR']+ os.sep + 'KDE'])
+
+	self.find_program('msgfmt', var='MSGFMT')
+
diff --git a/xpdeint/waf/waflib/Tools/lua.py b/xpdeint/waf/waflib/Tools/lua.py
new file mode 100644
index 0000000..814f77d
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/lua.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Sebastian Schlingmann, 2008
+# Thomas Nagy, 2008-2010 (ita)
+
+"""
+Lua support.
+
+Compile *.lua* files into *.luac*::
+
+	def configure(conf):
+		conf.load('lua')
+		conf.env.LUADIR = '/usr/local/share/myapp/scripts/'
+	def build(bld):
+		bld(source='foo.lua')
+"""
+
+from waflib.TaskGen import extension
+from waflib import Task, Utils
+
+ at extension('.lua')
+def add_lua(self, node):
+	tsk = self.create_task('luac', node, node.change_ext('.luac'))
+	inst_to = getattr(self, 'install_path', self.env.LUADIR and '${LUADIR}' or None)
+	if inst_to:
+		self.bld.install_files(inst_to, tsk.outputs)
+	return tsk
+
+class luac(Task.Task):
+	run_str = '${LUAC} -s -o ${TGT} ${SRC}'
+	color   = 'PINK'
+
+def configure(conf):
+	"""
+	Detect the luac compiler and set *conf.env.LUAC*
+	"""
+	conf.find_program('luac', var='LUAC')
+
diff --git a/xpdeint/waf/waflib/Tools/msvc.py b/xpdeint/waf/waflib/Tools/msvc.py
new file mode 100644
index 0000000..2e5c37f
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/msvc.py
@@ -0,0 +1,938 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Carlos Rafael Giani, 2006 (dv)
+# Tamas Pal, 2007 (folti)
+# Nicolas Mercier, 2009
+
+"""
+Microsoft Visual C++/Intel C++ compiler support
+
+Usage::
+
+	$ waf configure --msvc_version="msvc 10.0,msvc 9.0" --msvc_target="x64"
+
+or::
+
+	def configure(conf):
+		conf.env['MSVC_VERSIONS'] = ['msvc 10.0', 'msvc 9.0', 'msvc 8.0', 'msvc 7.1', 'msvc 7.0', 'msvc 6.0', 'wsdk 7.0', 'intel 11', 'PocketPC 9.0', 'Smartphone 8.0']
+		conf.env['MSVC_TARGETS'] = ['x64']
+		conf.load('msvc')
+
+or::
+
+	def configure(conf):
+		conf.load('msvc', funs='no_autodetect')
+		conf.check_lib_msvc('gdi32')
+		conf.check_libs_msvc('kernel32 user32')
+	def build(bld):
+		tg = bld.program(source='main.c', target='app', use='KERNEL32 USER32 GDI32')
+
+Platforms and targets will be tested in the order they appear;
+the first good configuration will be used.
+Supported platforms: ia64, x64, x86, x86_amd64, x86_ia64
+
+Compilers supported:
+
+* msvc       => Visual Studio, versions 6.0 (VC 98, VC .NET 2002) to 10.0 (Visual Studio 2010)
+* wsdk       => Windows SDK, versions 6.0, 6.1, 7.0
+* icl        => Intel compiler, versions 9,10,11
+* Smartphone => Compiler/SDK for Smartphone devices (armv4/v4i)
+* PocketPC   => Compiler/SDK for PocketPC devices (armv4/v4i)
+
+To use WAF in a VS2008 Make file project (see http://code.google.com/p/waf/issues/detail?id=894)
+You may consider to set the environment variable "VS_UNICODE_OUTPUT" to nothing before calling waf.
+So in your project settings use something like 'cmd.exe /C "set VS_UNICODE_OUTPUT=& set PYTHONUNBUFFERED=true & waf build"'.
+cmd.exe  /C  "chcp 1252 & set PYTHONUNBUFFERED=true && set && waf  configure"
+Setting PYTHONUNBUFFERED gives the unbuffered output.
+"""
+
+import os, sys, re, tempfile
+try:
+	import _winreg
+except:
+	try:
+		import winreg as _winreg
+	except:
+		_winreg = None
+
+from waflib import Utils, TaskGen, Runner, Configure, Task, Options
+from waflib.Logs import debug, info, warn, error
+from waflib.TaskGen import after_method, before_method, feature
+
+from waflib.Configure import conf
+from waflib.Tools import ccroot, c, cxx, ar, winres
+
+
+g_msvc_systemlibs = '''
+aclui activeds ad1 adptif adsiid advapi32 asycfilt authz bhsupp bits bufferoverflowu cabinet
+cap certadm certidl ciuuid clusapi comctl32 comdlg32 comsupp comsuppd comsuppw comsuppwd comsvcs
+credui crypt32 cryptnet cryptui d3d8thk daouuid dbgeng dbghelp dciman32 ddao35 ddao35d
+ddao35u ddao35ud delayimp dhcpcsvc dhcpsapi dlcapi dnsapi dsprop dsuiext dtchelp
+faultrep fcachdll fci fdi framedyd framedyn gdi32 gdiplus glauxglu32 gpedit gpmuuid
+gtrts32w gtrtst32hlink htmlhelp httpapi icm32 icmui imagehlp imm32 iphlpapi iprop
+kernel32 ksguid ksproxy ksuser libcmt libcmtd libcpmt libcpmtd loadperf lz32 mapi
+mapi32 mgmtapi minidump mmc mobsync mpr mprapi mqoa mqrt msacm32 mscms mscoree
+msdasc msimg32 msrating mstask msvcmrt msvcurt msvcurtd mswsock msxml2 mtx mtxdm
+netapi32 nmapinmsupp npptools ntdsapi ntdsbcli ntmsapi ntquery odbc32 odbcbcp
+odbccp32 oldnames ole32 oleacc oleaut32 oledb oledlgolepro32 opends60 opengl32
+osptk parser pdh penter pgobootrun pgort powrprof psapi ptrustm ptrustmd ptrustu
+ptrustud qosname rasapi32 rasdlg rassapi resutils riched20 rpcndr rpcns4 rpcrt4 rtm
+rtutils runtmchk scarddlg scrnsave scrnsavw secur32 sensapi setupapi sfc shell32
+shfolder shlwapi sisbkup snmpapi sporder srclient sti strsafe svcguid tapi32 thunk32
+traffic unicows url urlmon user32 userenv usp10 uuid uxtheme vcomp vcompd vdmdbg
+version vfw32 wbemuuid  webpost wiaguid wininet winmm winscard winspool winstrm
+wintrust wldap32 wmiutils wow32 ws2_32 wsnmp32 wsock32 wst wtsapi32 xaswitch xolehlp
+'''.split()
+"""importlibs provided by MSVC/Platform SDK. Do NOT search them"""
+
+all_msvc_platforms = [ ('x64', 'amd64'), ('x86', 'x86'), ('ia64', 'ia64'), ('x86_amd64', 'amd64'), ('x86_ia64', 'ia64') ]
+"""List of msvc platforms"""
+
+all_wince_platforms = [ ('armv4', 'arm'), ('armv4i', 'arm'), ('mipsii', 'mips'), ('mipsii_fp', 'mips'), ('mipsiv', 'mips'), ('mipsiv_fp', 'mips'), ('sh4', 'sh'), ('x86', 'cex86') ]
+"""List of wince platforms"""
+
+all_icl_platforms = [ ('intel64', 'amd64'), ('em64t', 'amd64'), ('ia32', 'x86'), ('Itanium', 'ia64')]
+"""List of icl platforms"""
+
+def options(opt):
+	opt.add_option('--msvc_version', type='string', help = 'msvc version, eg: "msvc 10.0,msvc 9.0"', default='')
+	opt.add_option('--msvc_targets', type='string', help = 'msvc targets, eg: "x64,arm"', default='')
+
+def setup_msvc(conf, versions):
+	platforms = getattr(Options.options, 'msvc_targets', '').split(',')
+	if platforms == ['']:
+		platforms=Utils.to_list(conf.env['MSVC_TARGETS']) or [i for i,j in all_msvc_platforms+all_icl_platforms+all_wince_platforms]
+	desired_versions = getattr(Options.options, 'msvc_version', '').split(',')
+	if desired_versions == ['']:
+		desired_versions = conf.env['MSVC_VERSIONS'] or [v for v,_ in versions][::-1]
+	versiondict = dict(versions)
+
+	for version in desired_versions:
+		try:
+			targets = dict(versiondict [version])
+			for target in platforms:
+				try:
+					arch,(p1,p2,p3) = targets[target]
+					compiler,revision = version.rsplit(' ', 1)
+					return compiler,revision,p1,p2,p3
+				except KeyError: continue
+		except KeyError: continue
+	conf.fatal('msvc: Impossible to find a valid architecture for building (in setup_msvc)')
+
+ at conf
+def get_msvc_version(conf, compiler, version, target, vcvars):
+	"""
+	Create a bat file to obtain the location of the libraries
+
+	:param compiler: ?
+	:param version: ?
+	:target: ?
+	:vcvars: ?
+	:return: the location of msvc, the location of include dirs, and the library paths
+	:rtype: tuple of strings
+	"""
+	debug('msvc: get_msvc_version: %r %r %r', compiler, version, target)
+	batfile = conf.bldnode.make_node('waf-print-msvc.bat')
+	batfile.write("""@echo off
+set INCLUDE=
+set LIB=
+call "%s" %s
+echo PATH=%%PATH%%
+echo INCLUDE=%%INCLUDE%%
+echo LIB=%%LIB%%
+""" % (vcvars,target))
+	sout = conf.cmd_and_log(['cmd', '/E:on', '/V:on', '/C', batfile.abspath()])
+	lines = sout.splitlines()
+
+	if not lines[0]: lines=lines[1:]
+	for x in ('Setting environment', 'Setting SDK environment', 'Intel(R) C++ Compiler', 'Intel Parallel Studio'):
+		if lines[0].find(x) != -1:
+			break
+	else:
+		debug('msvc: get_msvc_version: %r %r %r -> not found', compiler, version, target)
+		conf.fatal('msvc: Impossible to find a valid architecture for building (in get_msvc_version)')
+
+	for line in lines[1:]:
+		if line.startswith('PATH='):
+			path = line[5:]
+			MSVC_PATH = path.split(';')
+		elif line.startswith('INCLUDE='):
+			MSVC_INCDIR = [i for i in line[8:].split(';') if i]
+		elif line.startswith('LIB='):
+			MSVC_LIBDIR = [i for i in line[4:].split(';') if i]
+
+	# Check if the compiler is usable at all.
+	# The detection may return 64-bit versions even on 32-bit systems, and these would fail to run.
+	env = {}
+	env.update(os.environ)
+	env.update(PATH = path)
+	compiler_name, linker_name, lib_name = _get_prog_names(conf, compiler)
+	cxx = conf.find_program(compiler_name, path_list=MSVC_PATH)
+	cxx = conf.cmd_to_list(cxx)
+
+	# delete CL if exists. because it could contain parameters wich can change cl's behaviour rather catastrophically.
+	if 'CL' in env:
+		del(env['CL'])
+
+	try:
+		try:
+			conf.cmd_and_log(cxx + ['/help'], env=env)
+		except Exception as e:
+			debug('msvc: get_msvc_version: %r %r %r -> failure' % (compiler, version, target))
+			debug(str(e))
+			conf.fatal('msvc: cannot run the compiler (in get_msvc_version)')
+		else:
+			debug('msvc: get_msvc_version: %r %r %r -> OK', compiler, version, target)
+	finally:
+		conf.env[compiler_name] = ''
+
+	return (MSVC_PATH, MSVC_INCDIR, MSVC_LIBDIR)
+
+ at conf
+def gather_wsdk_versions(conf, versions):
+	"""
+	Use winreg to add the msvc versions to the input list
+
+	:param versions: list to modify
+	:type versions: list
+	"""
+	version_pattern = re.compile('^v..?.?\...?.?')
+	try:
+		all_versions = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Microsoft\\Microsoft SDKs\\Windows')
+	except WindowsError:
+		try:
+			all_versions = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows')
+		except WindowsError:
+			return
+	index = 0
+	while 1:
+		try:
+			version = _winreg.EnumKey(all_versions, index)
+		except WindowsError:
+			break
+		index = index + 1
+		if not version_pattern.match(version):
+			continue
+		try:
+			msvc_version = _winreg.OpenKey(all_versions, version)
+			path,type = _winreg.QueryValueEx(msvc_version,'InstallationFolder')
+		except WindowsError:
+			continue
+		if os.path.isfile(os.path.join(path, 'bin', 'SetEnv.cmd')):
+			targets = []
+			for target,arch in all_msvc_platforms:
+				try:
+					targets.append((target, (arch, conf.get_msvc_version('wsdk', version, '/'+target, os.path.join(path, 'bin', 'SetEnv.cmd')))))
+				except conf.errors.ConfigurationError:
+					pass
+			versions.append(('wsdk ' + version[1:], targets))
+
+def gather_wince_supported_platforms():
+	"""
+	Checks SmartPhones SDKs
+
+	:param versions: list to modify
+	:type versions: list
+	"""
+	supported_wince_platforms = []
+	try:
+		ce_sdk = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Microsoft\\Windows CE Tools\\SDKs')
+	except WindowsError:
+		try:
+			ce_sdk = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows CE Tools\\SDKs')
+		except WindowsError:
+			ce_sdk = ''
+	if not ce_sdk:
+		return supported_wince_platforms
+
+	ce_index = 0
+	while 1:
+		try:
+			sdk_device = _winreg.EnumKey(ce_sdk, ce_index)
+		except WindowsError:
+			break
+		ce_index = ce_index + 1
+		sdk = _winreg.OpenKey(ce_sdk, sdk_device)
+		try:
+			path,type = _winreg.QueryValueEx(sdk, 'SDKRootDir')
+		except WindowsError:
+			try:
+				path,type = _winreg.QueryValueEx(sdk,'SDKInformation')
+				path,xml = os.path.split(path)
+			except WindowsError:
+				continue
+		path=str(path)
+		path,device = os.path.split(path)
+		if not device:
+			path,device = os.path.split(path)
+		for arch,compiler in all_wince_platforms:
+			platforms = []
+			if os.path.isdir(os.path.join(path, device, 'Lib', arch)):
+				platforms.append((arch, compiler, os.path.join(path, device, 'Include', arch), os.path.join(path, device, 'Lib', arch)))
+			if platforms:
+				supported_wince_platforms.append((device, platforms))
+	return supported_wince_platforms
+
+def gather_msvc_detected_versions():
+	#Detected MSVC versions!
+	version_pattern = re.compile('^(\d\d?\.\d\d?)(Exp)?$')
+	detected_versions = []
+	for vcver,vcvar in [('VCExpress','Exp'), ('VisualStudio','')]:
+		try:
+			prefix = 'SOFTWARE\\Wow6432node\\Microsoft\\'+vcver
+			all_versions = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, prefix)
+		except WindowsError:
+			try:
+				prefix = 'SOFTWARE\\Microsoft\\'+vcver
+				all_versions = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, prefix)
+			except WindowsError:
+				continue
+
+		index = 0
+		while 1:
+			try:
+				version = _winreg.EnumKey(all_versions, index)
+			except WindowsError:
+				break
+			index = index + 1
+			match = version_pattern.match(version)
+			if not match:
+				continue
+			else:
+				versionnumber = float(match.group(1))
+			detected_versions.append((versionnumber, version+vcvar, prefix+"\\"+version))
+	def fun(tup):
+		return tup[0]
+
+	try:
+		detected_versions.sort(key = fun)
+	except:
+		# old python sort
+		detected_versions.sort(lambda x,y: cmp(x[0], y[0]))
+	return detected_versions
+
+ at conf
+def gather_msvc_targets(conf, versions, version, vc_path):
+	#Looking for normal MSVC compilers!
+	targets = []
+	if os.path.isfile(os.path.join(vc_path, 'vcvarsall.bat')):
+		for target,realtarget in all_msvc_platforms[::-1]:
+			try:
+				targets.append((target, (realtarget, conf.get_msvc_version('msvc', version, target, os.path.join(vc_path, 'vcvarsall.bat')))))
+			except conf.errors.ConfigurationError:
+				pass
+	elif os.path.isfile(os.path.join(vc_path, 'Common7', 'Tools', 'vsvars32.bat')):
+		try:
+			targets.append(('x86', ('x86', conf.get_msvc_version('msvc', version, 'x86', os.path.join(vc_path, 'Common7', 'Tools', 'vsvars32.bat')))))
+		except conf.errors.ConfigurationError:
+			pass
+	elif os.path.isfile(os.path.join(vc_path, 'Bin', 'vcvars32.bat')):
+		try:
+			targets.append(('x86', ('x86', conf.get_msvc_version('msvc', version, '', os.path.join(vc_path, 'Bin', 'vcvars32.bat')))))
+		except conf.errors.ConfigurationError:
+			pass
+	versions.append(('msvc '+ version, targets))
+
+ at conf
+def gather_wince_targets(conf, versions, version, vc_path, vsvars, supported_platforms):
+	#Looking for Win CE compilers!
+	for device,platforms in supported_platforms:
+		cetargets = []
+		for platform,compiler,include,lib in platforms:
+			winCEpath = os.path.join(vc_path, 'ce')
+			if not os.path.isdir(winCEpath):
+				continue
+			try:
+				common_bindirs,_1,_2 = conf.get_msvc_version('msvc', version, 'x86', vsvars)
+			except conf.errors.ConfigurationError:
+				continue
+			if os.path.isdir(os.path.join(winCEpath, 'lib', platform)):
+				bindirs = [os.path.join(winCEpath, 'bin', compiler), os.path.join(winCEpath, 'bin', 'x86_'+compiler)] + common_bindirs
+				incdirs = [os.path.join(winCEpath, 'include'), os.path.join(winCEpath, 'atlmfc', 'include'), include]
+				libdirs = [os.path.join(winCEpath, 'lib', platform), os.path.join(winCEpath, 'atlmfc', 'lib', platform), lib]
+				cetargets.append((platform, (platform, (bindirs,incdirs,libdirs))))
+		if cetargets:
+			versions.append((device + ' ' + version, cetargets))
+
+ at conf
+def gather_msvc_versions(conf, versions):
+	vc_paths = []
+	for (v,version,reg) in gather_msvc_detected_versions():
+		try:
+			try:
+				msvc_version = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, reg + "\\Setup\\VC")
+			except WindowsError:
+				msvc_version = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, reg + "\\Setup\\Microsoft Visual C++")
+			path,type = _winreg.QueryValueEx(msvc_version, 'ProductDir')
+			vc_paths.append((version, os.path.abspath(str(path))))
+		except WindowsError:
+			continue
+
+	wince_supported_platforms = gather_wince_supported_platforms()
+
+	for version,vc_path in vc_paths:
+		vs_path = os.path.dirname(vc_path)
+		vsvars = os.path.join(vs_path, 'Common7', 'Tools', 'vsvars32.bat')
+		if wince_supported_platforms and os.path.isfile(vsvars):
+			conf.gather_wince_targets(versions, version, vc_path, vsvars, wince_supported_platforms)
+
+	for version,vc_path in vc_paths:
+		vs_path = os.path.dirname(vc_path)
+		conf.gather_msvc_targets(versions, version, vc_path)
+
+ at conf
+def gather_icl_versions(conf, versions):
+	"""
+	Checks ICL compilers
+
+	:param versions: list to modify
+	:type versions: list
+	"""
+	version_pattern = re.compile('^...?.?\....?.?')
+	try:
+		all_versions = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Intel\\Compilers\\C++')
+	except WindowsError:
+		try:
+			all_versions = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Intel\\Compilers\\C++')
+		except WindowsError:
+			return
+	index = 0
+	while 1:
+		try:
+			version = _winreg.EnumKey(all_versions, index)
+		except WindowsError:
+			break
+		index = index + 1
+		if not version_pattern.match(version):
+			continue
+		targets = []
+		for target,arch in all_icl_platforms:
+			try:
+				if target=='intel64': targetDir='EM64T_NATIVE'
+				else: targetDir=target
+				_winreg.OpenKey(all_versions,version+'\\'+targetDir)
+				icl_version=_winreg.OpenKey(all_versions,version)
+				path,type=_winreg.QueryValueEx(icl_version,'ProductDir')
+				if os.path.isfile(os.path.join(path,'bin','iclvars.bat')):
+					try:
+						targets.append((target,(arch,conf.get_msvc_version('intel',version,target,os.path.join(path,'bin','iclvars.bat')))))
+					except conf.errors.ConfigurationError:
+						pass
+			except WindowsError:
+				pass
+		for target,arch in all_icl_platforms:
+			try:
+				icl_version = _winreg.OpenKey(all_versions, version+'\\'+target)
+				path,type = _winreg.QueryValueEx(icl_version,'ProductDir')
+				if os.path.isfile(os.path.join(path, 'bin', 'iclvars.bat')):
+					try:
+						targets.append((target, (arch, conf.get_msvc_version('intel', version, target, os.path.join(path, 'bin', 'iclvars.bat')))))
+					except conf.errors.ConfigurationError:
+						pass
+			except WindowsError:
+				continue
+		major = version[0:2]
+		versions.append(('intel ' + major, targets))
+
+ at conf
+def get_msvc_versions(conf):
+	"""
+	:return: list of compilers installed
+	:rtype: list of string
+	"""
+	if not conf.env['MSVC_INSTALLED_VERSIONS']:
+		lst = []
+		conf.gather_icl_versions(lst)
+		conf.gather_wsdk_versions(lst)
+		conf.gather_msvc_versions(lst)
+		conf.env['MSVC_INSTALLED_VERSIONS'] = lst
+	return conf.env['MSVC_INSTALLED_VERSIONS']
+
+ at conf
+def print_all_msvc_detected(conf):
+	"""
+	Print the contents of *conf.env.MSVC_INSTALLED_VERSIONS*
+	"""
+	for version,targets in conf.env['MSVC_INSTALLED_VERSIONS']:
+		info(version)
+		for target,l in targets:
+			info("\t"+target)
+
+ at conf
+def detect_msvc(conf):
+	versions = get_msvc_versions(conf)
+	return setup_msvc(conf, versions)
+
+ at conf
+def find_lt_names_msvc(self, libname, is_static=False):
+	"""
+	Win32/MSVC specific code to glean out information from libtool la files.
+	this function is not attached to the task_gen class
+	"""
+	lt_names=[
+		'lib%s.la' % libname,
+		'%s.la' % libname,
+	]
+
+	for path in self.env['LIBPATH']:
+		for la in lt_names:
+			laf=os.path.join(path,la)
+			dll=None
+			if os.path.exists(laf):
+				ltdict = Utils.read_la_file(laf)
+				lt_libdir=None
+				if ltdict.get('libdir', ''):
+					lt_libdir = ltdict['libdir']
+				if not is_static and ltdict.get('library_names', ''):
+					dllnames=ltdict['library_names'].split()
+					dll=dllnames[0].lower()
+					dll=re.sub('\.dll$', '', dll)
+					return (lt_libdir, dll, False)
+				elif ltdict.get('old_library', ''):
+					olib=ltdict['old_library']
+					if os.path.exists(os.path.join(path,olib)):
+						return (path, olib, True)
+					elif lt_libdir != '' and os.path.exists(os.path.join(lt_libdir,olib)):
+						return (lt_libdir, olib, True)
+					else:
+						return (None, olib, True)
+				else:
+					raise self.errors.WafError('invalid libtool object file: %s' % laf)
+	return (None, None, None)
+
+ at conf
+def libname_msvc(self, libname, is_static=False):
+	lib = libname.lower()
+	lib = re.sub('\.lib$','',lib)
+
+	if lib in g_msvc_systemlibs:
+		return lib
+
+	lib=re.sub('^lib','',lib)
+
+	if lib == 'm':
+		return None
+
+	(lt_path, lt_libname, lt_static) = self.find_lt_names_msvc(lib, is_static)
+
+	if lt_path != None and lt_libname != None:
+		if lt_static == True:
+			# file existance check has been made by find_lt_names
+			return os.path.join(lt_path,lt_libname)
+
+	if lt_path != None:
+		_libpaths=[lt_path] + self.env['LIBPATH']
+	else:
+		_libpaths=self.env['LIBPATH']
+
+	static_libs=[
+		'lib%ss.lib' % lib,
+		'lib%s.lib' % lib,
+		'%ss.lib' % lib,
+		'%s.lib' %lib,
+		]
+
+	dynamic_libs=[
+		'lib%s.dll.lib' % lib,
+		'lib%s.dll.a' % lib,
+		'%s.dll.lib' % lib,
+		'%s.dll.a' % lib,
+		'lib%s_d.lib' % lib,
+		'%s_d.lib' % lib,
+		'%s.lib' %lib,
+		]
+
+	libnames=static_libs
+	if not is_static:
+		libnames=dynamic_libs + static_libs
+
+	for path in _libpaths:
+		for libn in libnames:
+			if os.path.exists(os.path.join(path, libn)):
+				debug('msvc: lib found: %s' % os.path.join(path,libn))
+				return re.sub('\.lib$', '',libn)
+
+	#if no lib can be found, just return the libname as msvc expects it
+	self.fatal("The library %r could not be found" % libname)
+	return re.sub('\.lib$', '', libname)
+
+ at conf
+def check_lib_msvc(self, libname, is_static=False, uselib_store=None):
+	"""
+	Ideally we should be able to place the lib in the right env var, either STLIB or LIB,
+	but we don't distinguish static libs from shared libs.
+	This is ok since msvc doesn't have any special linker flag to select static libs (no env['STLIB_MARKER'])
+	"""
+	libn = self.libname_msvc(libname, is_static)
+
+	if not uselib_store:
+		uselib_store = libname.upper()
+
+	if False and is_static: # disabled
+		self.env['STLIB_' + uselib_store] = [libn]
+	else:
+		self.env['LIB_' + uselib_store] = [libn]
+
+ at conf
+def check_libs_msvc(self, libnames, is_static=False):
+	for libname in Utils.to_list(libnames):
+		self.check_lib_msvc(libname, is_static)
+
+def configure(conf):
+	"""
+	Configuration methods to call for detecting msvc
+	"""
+	conf.autodetect()
+	conf.find_msvc()
+	conf.msvc_common_flags()
+	conf.cc_load_tools()
+	conf.cxx_load_tools()
+	conf.cc_add_flags()
+	conf.cxx_add_flags()
+	conf.link_add_flags()
+	conf.visual_studio_add_flags()
+
+ at conf
+def no_autodetect(conf):
+	conf.env.NO_MSVC_DETECT = 1
+	configure(conf)
+
+ at conf
+def autodetect(conf):
+	v = conf.env
+	if v.NO_MSVC_DETECT:
+		return
+	compiler, version, path, includes, libdirs = conf.detect_msvc()
+	v['PATH'] = path
+	v['INCLUDES'] = includes
+	v['LIBPATH'] = libdirs
+	v['MSVC_COMPILER'] = compiler
+	try:
+		v['MSVC_VERSION'] = float(version)
+	except:
+		v['MSVC_VERSION'] = float(version[:-3])
+
+def _get_prog_names(conf, compiler):
+	if compiler=='intel':
+		compiler_name = 'ICL'
+		linker_name = 'XILINK'
+		lib_name = 'XILIB'
+	else:
+		# assumes CL.exe
+		compiler_name = 'CL'
+		linker_name = 'LINK'
+		lib_name = 'LIB'
+	return compiler_name, linker_name, lib_name
+
+ at conf
+def find_msvc(conf):
+	"""Due to path format limitations, limit operation only to native Win32. Yeah it sucks."""
+	if sys.platform == 'cygwin':
+		conf.fatal('MSVC module does not work under cygwin Python!')
+
+	# the autodetection is supposed to be performed before entering in this method
+	v = conf.env
+	path = v['PATH']
+	compiler = v['MSVC_COMPILER']
+	version = v['MSVC_VERSION']
+
+	compiler_name, linker_name, lib_name = _get_prog_names(conf, compiler)
+	v.MSVC_MANIFEST = (compiler == 'msvc' and version >= 8) or (compiler == 'wsdk' and version >= 6) or (compiler == 'intel' and version >= 11)
+
+	# compiler
+	cxx = None
+	if v['CXX']: cxx = v['CXX']
+	elif 'CXX' in conf.environ: cxx = conf.environ['CXX']
+	cxx = conf.find_program(compiler_name, var='CXX', path_list=path)
+	cxx = conf.cmd_to_list(cxx)
+
+	# before setting anything, check if the compiler is really msvc
+	env = dict(conf.environ)
+	if path: env.update(PATH = ';'.join(path))
+	if not conf.cmd_and_log(cxx + ['/nologo', '/help'], env=env):
+		conf.fatal('the msvc compiler could not be identified')
+
+	# c/c++ compiler
+	v['CC'] = v['CXX'] = cxx
+	v['CC_NAME'] = v['CXX_NAME'] = 'msvc'
+
+	# linker
+	if not v['LINK_CXX']:
+		link = conf.find_program(linker_name, path_list=path)
+		if link: v['LINK_CXX'] = link
+		else: conf.fatal('%s was not found (linker)' % linker_name)
+		v['LINK'] = link
+
+	if not v['LINK_CC']:
+		v['LINK_CC'] = v['LINK_CXX']
+
+	# staticlib linker
+	if not v['AR']:
+		stliblink = conf.find_program(lib_name, path_list=path, var='AR')
+		if not stliblink: return
+		v['ARFLAGS'] = ['/NOLOGO']
+
+	# manifest tool. Not required for VS 2003 and below. Must have for VS 2005 and later
+	if v.MSVC_MANIFEST:
+		mt = conf.find_program('MT', path_list=path, var='MT')
+		v['MTFLAGS'] = ['/NOLOGO']
+
+	conf.load('winres')
+
+	if not conf.env['WINRC']:
+		warn('Resource compiler not found. Compiling resource file is disabled')
+
+ at conf
+def visual_studio_add_flags(self):
+	"""visual studio flags found in the system environment"""
+	v = self.env
+	try: v.prepend_value('INCLUDES', self.environ['INCLUDE'].split(';')) # notice the 'S'
+	except: pass
+	try: v.prepend_value('LIBPATH', self.environ['LIB'].split(';'))
+	except: pass
+
+ at conf
+def msvc_common_flags(conf):
+	"""
+	Setup the flags required for executing the msvc compiler
+
+	The default is to allow a static and a shared library having the same name in the same directory, the static one being prefixed by 'lib'. If you feel that this
+	is incorrect, just change the extension (issue #824)::
+
+		bld.env.STLIB_ST = bld.env.SHLIB_ST = '%s.lib'
+		bld.stlib(..., name='libfoo')
+		bld.shlib(..., name='foo')
+	"""
+	v = conf.env
+
+	v['DEST_BINFMT'] = 'pe'
+	v.append_value('CFLAGS', ['/nologo'])
+	v.append_value('CXXFLAGS', ['/nologo'])
+	v['DEFINES_ST']     = '/D%s'
+
+	v['CC_SRC_F']     = ''
+	v['CC_TGT_F']     = ['/c', '/Fo']
+	if v['MSVC_VERSION'] >= 8:
+		v['CC_TGT_F']= ['/FC'] + v['CC_TGT_F']
+	v['CXX_SRC_F']    = ''
+	v['CXX_TGT_F']    = ['/c', '/Fo']
+	if v['MSVC_VERSION'] >= 8:
+		v['CXX_TGT_F']= ['/FC'] + v['CXX_TGT_F']
+
+	v['CPPPATH_ST']   = '/I%s' # template for adding include paths
+
+	v['AR_TGT_F'] = v['CCLNK_TGT_F'] = v['CXXLNK_TGT_F'] = '/OUT:'
+
+	# Subsystem specific flags
+	v['CFLAGS_CONSOLE']   = v['CXXFLAGS_CONSOLE']   = ['/SUBSYSTEM:CONSOLE']
+	v['CFLAGS_NATIVE']    = v['CXXFLAGS_NATIVE']    = ['/SUBSYSTEM:NATIVE']
+	v['CFLAGS_POSIX']     = v['CXXFLAGS_POSIX']     = ['/SUBSYSTEM:POSIX']
+	v['CFLAGS_WINDOWS']   = v['CXXFLAGS_WINDOWS']   = ['/SUBSYSTEM:WINDOWS']
+	v['CFLAGS_WINDOWSCE'] = v['CXXFLAGS_WINDOWSCE'] = ['/SUBSYSTEM:WINDOWSCE']
+
+	# CRT specific flags
+	v['CFLAGS_CRT_MULTITHREADED']     = v['CXXFLAGS_CRT_MULTITHREADED']     = ['/MT']
+	v['CFLAGS_CRT_MULTITHREADED_DLL'] = v['CXXFLAGS_CRT_MULTITHREADED_DLL'] = ['/MD']
+
+	v['CFLAGS_CRT_MULTITHREADED_DBG']     = v['CXXFLAGS_CRT_MULTITHREADED_DBG']     = ['/MTd']
+	v['CFLAGS_CRT_MULTITHREADED_DLL_DBG'] = v['CXXFLAGS_CRT_MULTITHREADED_DLL_DBG'] = ['/MDd']
+
+	# linker
+	v['LIB_ST']            = '%s.lib' # template for adding shared libs
+	v['LIBPATH_ST']        = '/LIBPATH:%s' # template for adding libpaths
+	v['STLIB_ST']          = 'lib%s.lib'
+	v['STLIBPATH_ST']      = '/LIBPATH:%s'
+
+	v.append_value('LINKFLAGS', ['/NOLOGO'])
+	if v['MSVC_MANIFEST']:
+		v.append_value('LINKFLAGS', ['/MANIFEST'])
+
+	# shared library
+	v['CFLAGS_cshlib']     = []
+	v['CXXFLAGS_cxxshlib'] = []
+	v['LINKFLAGS_cshlib']  = v['LINKFLAGS_cxxshlib'] = ['/DLL']
+	v['cshlib_PATTERN']    = v['cxxshlib_PATTERN'] = '%s.dll'
+	v['implib_PATTERN']    = '%s.lib'
+	v['IMPLIB_ST']         = '/IMPLIB:%s'
+
+	# static library
+	v['LINKFLAGS_cstlib']  = []
+	v['cstlib_PATTERN']    = v['cxxstlib_PATTERN'] = 'lib%s.lib'
+
+	# program
+	v['cprogram_PATTERN']  = v['cxxprogram_PATTERN']    = '%s.exe'
+
+
+#######################################################################################################
+##### conf above, build below
+
+ at after_method('apply_link')
+ at feature('c', 'cxx')
+def apply_flags_msvc(self):
+	"""
+	Add additional flags implied by msvc, such as subsystems and pdb files::
+
+		def build(bld):
+			bld.stlib(source='main.c', target='bar', subsystem='gruik')
+	"""
+	if self.env.CC_NAME != 'msvc' or not getattr(self, 'link_task', None):
+		return
+
+	is_static = isinstance(self.link_task, ccroot.stlink_task)
+
+	subsystem = getattr(self, 'subsystem', '')
+	if subsystem:
+		subsystem = '/subsystem:%s' % subsystem
+		flags = is_static and 'ARFLAGS' or 'LINKFLAGS'
+		self.env.append_value(flags, subsystem)
+
+	if not is_static:
+		for f in self.env.LINKFLAGS:
+			d = f.lower()
+			if d[1:] == 'debug':
+				pdbnode = self.link_task.outputs[0].change_ext('.pdb')
+				self.link_task.outputs.append(pdbnode)
+
+				try:
+					self.install_task.source.append(pdbnode)
+				except AttributeError:
+					pass
+
+				break
+
+# split the manifest file processing from the link task, like for the rc processing
+
+ at feature('cprogram', 'cshlib', 'cxxprogram', 'cxxshlib')
+ at after_method('apply_link')
+def apply_manifest(self):
+	"""
+	Special linker for MSVC with support for embedding manifests into DLL's
+	and executables compiled by Visual Studio 2005 or probably later. Without
+	the manifest file, the binaries are unusable.
+	See: http://msdn2.microsoft.com/en-us/library/ms235542(VS.80).aspx
+	"""
+
+	if self.env.CC_NAME == 'msvc' and self.env.MSVC_MANIFEST and getattr(self, 'link_task', None):
+		out_node = self.link_task.outputs[0]
+		man_node = out_node.parent.find_or_declare(out_node.name + '.manifest')
+		self.link_task.outputs.append(man_node)
+		self.link_task.do_manifest = True
+
+def exec_mf(self):
+	"""
+	Create the manifest file
+	"""
+	env = self.env
+	mtool = env['MT']
+	if not mtool:
+		return 0
+
+	self.do_manifest = False
+
+	outfile = self.outputs[0].abspath()
+
+	manifest = None
+	for out_node in self.outputs:
+		if out_node.name.endswith('.manifest'):
+			manifest = out_node.abspath()
+			break
+	if manifest is None:
+		# Should never get here.  If we do, it means the manifest file was
+		# never added to the outputs list, thus we don't have a manifest file
+		# to embed, so we just return.
+		return 0
+
+	# embedding mode. Different for EXE's and DLL's.
+	# see: http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx
+	mode = ''
+	if 'cprogram' in self.generator.features or 'cxxprogram' in self.generator.features:
+		mode = '1'
+	elif 'cshlib' in self.generator.features or 'cxxshlib' in self.generator.features:
+		mode = '2'
+
+	debug('msvc: embedding manifest in mode %r' % mode)
+
+	lst = []
+	lst.append(env['MT'])
+	lst.extend(Utils.to_list(env['MTFLAGS']))
+	lst.extend(['-manifest', manifest])
+	lst.append('-outputresource:%s;%s' % (outfile, mode))
+
+	lst = [lst]
+	return self.exec_command(*lst)
+
+def quote_response_command(self, flag):
+	if flag.find(' ') > -1:
+		for x in ('/LIBPATH:', '/IMPLIB:', '/OUT:', '/I'):
+			if flag.startswith(x):
+				flag = '%s"%s"' % (x, flag[len(x):])
+				break
+		else:
+			flag = '"%s"' % flag
+	return flag
+
+def exec_response_command(self, cmd, **kw):
+	# not public yet
+	try:
+		tmp = None
+		if sys.platform.startswith('win') and isinstance(cmd, list) and len(' '.join(cmd)) >= 8192:
+			program = cmd[0] #unquoted program name, otherwise exec_command will fail
+			cmd = [self.quote_response_command(x) for x in cmd]
+			(fd, tmp) = tempfile.mkstemp()
+			os.write(fd, '\r\n'.join(i.replace('\\', '\\\\') for i in cmd[1:]).encode())
+			os.close(fd)
+			cmd = [program, '@' + tmp]
+		# no return here, that's on purpose
+		ret = self.generator.bld.exec_command(cmd, **kw)
+	finally:
+		if tmp:
+			try:
+				os.remove(tmp)
+			except:
+				pass # anti-virus and indexers can keep the files open -_-
+	return ret
+
+########## stupid evil command modification: concatenate the tokens /Fx, /doc, and /x: with the next token
+
+def exec_command_msvc(self, *k, **kw):
+	"""
+	Change the command-line execution for msvc programs.
+	Instead of quoting all the paths and keep using the shell, we can just join the options msvc is interested in
+	"""
+	if self.env['CC_NAME'] == 'msvc':
+		if isinstance(k[0], list):
+			lst = []
+			carry = ''
+			for a in k[0]:
+				if a == '/Fo' or a == '/doc' or a[-1] == ':':
+					carry = a
+				else:
+					lst.append(carry + a)
+					carry = ''
+			k = [lst]
+
+		if self.env['PATH']:
+			env = dict(os.environ)
+			env.update(PATH = ';'.join(self.env['PATH']))
+			kw['env'] = env
+
+	bld = self.generator.bld
+	try:
+		if not kw.get('cwd', None):
+			kw['cwd'] = bld.cwd
+	except AttributeError:
+		bld.cwd = kw['cwd'] = bld.variant_dir
+
+	ret = self.exec_response_command(k[0], **kw)
+	if not ret and getattr(self, 'do_manifest', None):
+		ret = self.exec_mf()
+	return ret
+
+for k in 'c cxx cprogram cxxprogram cshlib cxxshlib cstlib cxxstlib'.split():
+	cls = Task.classes.get(k, None)
+	if cls:
+		cls.exec_command = exec_command_msvc
+		cls.exec_response_command = exec_response_command
+		cls.quote_response_command = quote_response_command
+		cls.exec_mf = exec_mf
+
diff --git a/xpdeint/waf/waflib/Tools/nasm.py b/xpdeint/waf/waflib/Tools/nasm.py
new file mode 100644
index 0000000..7fc3277
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/nasm.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2008-2010 (ita)
+
+"""
+Nasm tool (asm processing)
+"""
+
+import waflib.Tools.asm # leave this
+from waflib.TaskGen import feature
+
+ at feature('asm')
+def apply_nasm_vars(self):
+	"""provided for compatibility"""
+	self.env.append_value('ASFLAGS', self.to_list(getattr(self, 'nasm_flags', [])))
+
+def configure(conf):
+	"""
+	Detect nasm/yasm and set the variable *AS*
+	"""
+	nasm = conf.find_program(['nasm', 'yasm'], var='AS')
+	conf.env.AS_TGT_F = ['-o']
+	conf.env.ASLNK_TGT_F = ['-o']
diff --git a/xpdeint/waf/waflib/Tools/perl.py b/xpdeint/waf/waflib/Tools/perl.py
new file mode 100644
index 0000000..a75e14e
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/perl.py
@@ -0,0 +1,157 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# andersg at 0x63.nu 2007
+# Thomas Nagy 2010 (ita)
+
+"""
+Support for Perl extensions. A C/C++ compiler is required::
+
+	def options(opt):
+		opt.load('compiler_c perl')
+	def configure(conf):
+		conf.load('compiler_c perl')
+		conf.check_perl_version((5,6,0))
+		conf.check_perl_ext_devel()
+		conf.check_perl_module('Cairo')
+		conf.check_perl_module('Devel::PPPort 4.89')
+	def build(bld):
+		bld(
+			features     = 'c cshlib perlext',
+			source       = 'Mytest.xs',
+			target       = 'Mytest',
+			install_path = '${ARCHDIR_PERL}/auto')
+		bld.install_files('${ARCHDIR_PERL}', 'Mytest.pm')
+"""
+
+import os
+from waflib import Task, Options, Utils
+from waflib.Configure import conf
+from waflib.TaskGen import extension, feature, before_method
+
+ at before_method('apply_incpaths', 'apply_link', 'propagate_uselib_vars')
+ at feature('perlext')
+def init_perlext(self):
+	"""
+	Change the values of *cshlib_PATTERN* and *cxxshlib_PATTERN* to remove the
+	*lib* prefix from library names.
+	"""
+	self.uselib = self.to_list(getattr(self, 'uselib', []))
+	if not 'PERLEXT' in self.uselib: self.uselib.append('PERLEXT')
+	self.env['cshlib_PATTERN'] = self.env['cxxshlib_PATTERN'] = self.env['perlext_PATTERN']
+
+ at extension('.xs')
+def xsubpp_file(self, node):
+	"""
+	Create :py:class:`waflib.Tools.perl.xsubpp` tasks to process *.xs* files
+	"""
+	outnode = node.change_ext('.c')
+	self.create_task('xsubpp', node, outnode)
+	self.source.append(outnode)
+
+class xsubpp(Task.Task):
+	"""
+	Process *.xs* files
+	"""
+	run_str = '${PERL} ${XSUBPP} -noprototypes -typemap ${EXTUTILS_TYPEMAP} ${SRC} > ${TGT}'
+	color   = 'BLUE'
+	ext_out = ['.h']
+
+ at conf
+def check_perl_version(self, minver=None):
+	"""
+	Check if Perl is installed, and set the variable PERL.
+	minver is supposed to be a tuple
+	"""
+	res = True
+	
+	if minver:
+		cver = '.'.join(map(str,minver))
+	else:
+		cver = ''
+
+	self.start_msg('Checking for minimum perl version %s' % cver)
+
+	perl = getattr(Options.options, 'perlbinary', None)
+
+	if not perl:
+		perl = self.find_program('perl', var='PERL')
+	
+	if not perl:
+		self.end_msg("Perl not found", color="YELLOW")
+		return False
+	
+	self.env['PERL'] = perl
+
+	version = self.cmd_and_log([perl, "-e", 'printf \"%vd\", $^V'])
+	if not version:
+		res = False
+		version = "Unknown"
+	elif not minver is None:
+		ver = tuple(map(int, version.split(".")))
+		if ver < minver:
+			res = False
+
+	self.end_msg(version, color=res and "GREEN" or "YELLOW")
+	return res
+
+ at conf
+def check_perl_module(self, module):
+	"""
+	Check if specified perlmodule is installed.
+
+	The minimum version can be specified by specifying it after modulename
+	like this::
+
+		def configure(conf):
+			conf.check_perl_module("Some::Module 2.92")
+	"""
+	cmd = [self.env['PERL'], '-e', 'use %s' % module]
+	self.start_msg('perl module %s' % module)
+	try:
+		r = self.cmd_and_log(cmd)
+	except:
+		self.end_msg(False)
+		return None
+	self.end_msg(r or True)
+	return r
+
+ at conf
+def check_perl_ext_devel(self):
+	"""
+	Check for configuration needed to build perl extensions.
+
+	Sets different xxx_PERLEXT variables in the environment.
+
+	Also sets the ARCHDIR_PERL variable useful as installation path,
+	which can be overridden by ``--with-perl-archdir`` option.
+	"""
+
+	env = self.env
+	perl = env.PERL
+	if not perl:
+		self.fatal('find perl first')
+
+	def read_out(cmd):
+		return Utils.to_list(self.cmd_and_log(perl + cmd))
+
+	env['LINKFLAGS_PERLEXT'] = read_out(" -MConfig -e'print $Config{lddlflags}'")
+	env['INCLUDES_PERLEXT'] = read_out(" -MConfig -e'print \"$Config{archlib}/CORE\"'")
+	env['CFLAGS_PERLEXT'] = read_out(" -MConfig -e'print \"$Config{ccflags} $Config{cccdlflags}\"'")
+
+	env['XSUBPP'] = read_out(" -MConfig -e'print \"$Config{privlib}/ExtUtils/xsubpp$Config{exe_ext}\"'")
+	env['EXTUTILS_TYPEMAP'] = read_out(" -MConfig -e'print \"$Config{privlib}/ExtUtils/typemap\"'")
+
+	if not getattr(Options.options, 'perlarchdir', None):
+		env['ARCHDIR_PERL'] = self.cmd_and_log(perl + " -MConfig -e'print $Config{sitearch}'")
+	else:
+		env['ARCHDIR_PERL'] = getattr(Options.options, 'perlarchdir')
+
+	env['perlext_PATTERN'] = '%s.' + self.cmd_and_log(perl + " -MConfig -e'print $Config{dlext}'")
+
+def options(opt):
+	"""
+	Add the ``--with-perl-archdir`` and ``--with-perl-binary`` command-line options.
+	"""
+	opt.add_option('--with-perl-binary', type='string', dest='perlbinary', help = 'Specify alternate perl binary', default=None)
+	opt.add_option('--with-perl-archdir', type='string', dest='perlarchdir', help = 'Specify directory where to install arch specific files', default=None)
+
diff --git a/xpdeint/waf/waflib/Tools/python.py b/xpdeint/waf/waflib/Tools/python.py
new file mode 100644
index 0000000..66ddf22
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/python.py
@@ -0,0 +1,494 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2007-2010 (ita)
+# Gustavo Carneiro (gjc), 2007
+
+"""
+Support for Python, detect the headers and libraries and provide
+*use* variables to link C/C++ programs against them::
+
+	def options(opt):
+		opt.load('compiler_c python')
+	def configure(conf):
+		conf.load('compiler_c python')
+		conf.check_python_version((2,4,2))
+		conf.check_python_headers()
+	def build(bld):
+		bld.program(features='pyembed', source='a.c', target='myprog')
+		bld.shlib(features='pyext', source='b.c', target='mylib')
+"""
+
+import os, sys
+from waflib import Utils, Options, Errors
+from waflib.Logs import debug, warn, info, error
+from waflib.TaskGen import extension, before_method, after_method, feature
+from waflib.Configure import conf
+
+FRAG = '''
+#include <Python.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+	void Py_Initialize(void);
+	void Py_Finalize(void);
+#ifdef __cplusplus
+}
+#endif
+int main()
+{
+   Py_Initialize();
+   Py_Finalize();
+   return 0;
+}
+'''
+"""
+Piece of C/C++ code used in :py:func:`waflib.Tools.python.check_python_headers`
+"""
+
+INST = '''
+import sys, py_compile
+py_compile.compile(sys.argv[1], sys.argv[2], sys.argv[3])
+'''
+"""
+Piece of Python code used in :py:func:`waflib.Tools.python.install_pyfile` for installing python files
+"""
+
+ at extension('.py')
+def process_py(self, node):
+	"""
+	Add a callback using :py:func:`waflib.Tools.python.install_pyfile` to install a python file
+	"""
+	try:
+		if not self.bld.is_install:
+			return
+	except:
+		return
+
+	try:
+		if not self.install_path:
+			return
+	except AttributeError:
+		self.install_path = '${PYTHONDIR}'
+
+	# i wonder now why we wanted to do this after the build is over
+	# issue #901: people want to preserve the structure of installed files
+	def inst_py(ctx):
+		install_from = getattr(self, 'install_from', None)
+		if install_from:
+			install_from = self.path.find_dir(install_from)
+		install_pyfile(self, node, install_from)
+	self.bld.add_post_fun(inst_py)
+
+def install_pyfile(self, node, install_from=None):
+	"""
+	Execute the installation of a python file
+
+	:param node: python file
+	:type node: :py:class:`waflib.Node.Node`
+	"""
+
+	from_node = install_from or node.parent
+	tsk = self.bld.install_as(self.install_path + '/' + node.path_from(from_node), node, postpone=False)
+	path = tsk.get_install_path()
+
+	if self.bld.is_install < 0:
+		info("+ removing byte compiled python files")
+		for x in 'co':
+			try:
+				os.remove(path + x)
+			except OSError:
+				pass
+
+	if self.bld.is_install > 0:
+		try:
+			st1 = os.stat(path)
+		except:
+			error('The python file is missing, this should not happen')
+
+		for x in ['c', 'o']:
+			do_inst = self.env['PY' + x.upper()]
+			try:
+				st2 = os.stat(path + x)
+			except OSError:
+				pass
+			else:
+				if st1.st_mtime <= st2.st_mtime:
+					do_inst = False
+
+			if do_inst:
+				lst = (x == 'o') and [self.env['PYFLAGS_OPT']] or []
+				(a, b, c) = (path, path + x, tsk.get_install_path(destdir=False) + x)
+				argv = self.env['PYTHON'] + lst + ['-c', INST, a, b, c]
+				info('+ byte compiling %r' % (path + x))
+				ret = Utils.subprocess.Popen(argv).wait()
+				if ret:
+					raise Errors.WafError('py%s compilation failed %r' % (x, path))
+
+ at feature('py')
+def feature_py(self):
+	"""
+	Dummy feature which does nothing
+	"""
+	pass
+
+ at feature('pyext')
+ at before_method('propagate_uselib_vars', 'apply_link')
+ at after_method('apply_bundle')
+def init_pyext(self):
+	"""
+	Change the values of *cshlib_PATTERN* and *cxxshlib_PATTERN* to remove the
+	*lib* prefix from library names.
+	"""
+	try:
+		if not self.install_path:
+			return
+	except AttributeError:
+		self.install_path = '${PYTHONARCHDIR}'
+	self.uselib = self.to_list(getattr(self, 'uselib', []))
+	if not 'PYEXT' in self.uselib:
+		self.uselib.append('PYEXT')
+	# override shlib_PATTERN set by the osx module
+	self.env['cshlib_PATTERN'] = self.env['cxxshlib_PATTERN'] = self.env['macbundle_PATTERN'] = self.env['pyext_PATTERN']
+
+ at feature('pyext')
+ at before_method('apply_link', 'apply_bundle')
+def set_bundle(self):
+	if Utils.unversioned_sys_platform == 'darwin':
+		self.mac_bundle = True
+
+ at before_method('propagate_uselib_vars')
+ at feature('pyembed')
+def init_pyembed(self):
+	"""
+	Add the PYEMBED variable.
+	"""
+	self.uselib = self.to_list(getattr(self, 'uselib', []))
+	if not 'PYEMBED' in self.uselib:
+		self.uselib.append('PYEMBED')
+
+ at conf
+def get_python_variables(conf, variables, imports=['import sys']):
+	"""
+	Execute a python interpreter to dump configuration variables
+
+	:param variables: variables to print
+	:type variables: list of string
+	:param imports: one import by element
+	:type imports: list of string
+	:return: the variable values
+	:rtype: list of string
+	"""
+	program = list(imports)
+	program.append('')
+	for v in variables:
+		program.append("print(repr(%s))" % v)
+	os_env = dict(os.environ)
+	try:
+		del os_env['MACOSX_DEPLOYMENT_TARGET'] # see comments in the OSX tool
+	except KeyError:
+		pass
+
+	try:
+		out = conf.cmd_and_log(conf.env.PYTHON + ['-c', '\n'.join(program)], env=os_env)
+	except Errors.WafError:
+		conf.fatal('The distutils module is unusable: install "python-devel"?')
+	return_values = []
+	for s in out.split('\n'):
+		s = s.strip()
+		if not s:
+			continue
+		if s == 'None':
+			return_values.append(None)
+		elif s[0] == "'" and s[-1] == "'":
+			return_values.append(s[1:-1])
+		elif s[0].isdigit():
+			return_values.append(int(s))
+		else: break
+	return return_values
+
+ at conf
+def check_python_headers(conf):
+	"""
+	Check for headers and libraries necessary to extend or embed python by using the module *distutils*.
+	On success the environment variables xxx_PYEXT and xxx_PYEMBED are added:
+
+	* PYEXT: for compiling python extensions
+	* PYEMBED: for embedding a python interpreter
+	"""
+
+	# FIXME rewrite
+
+	if not conf.env['CC_NAME'] and not conf.env['CXX_NAME']:
+		conf.fatal('load a compiler first (gcc, g++, ..)')
+
+	if not conf.env['PYTHON_VERSION']:
+		conf.check_python_version()
+
+	env = conf.env
+	pybin = conf.env.PYTHON
+	if not pybin:
+		conf.fatal('could not find the python executable')
+
+	v = 'prefix SO LDFLAGS LIBDIR LIBPL INCLUDEPY Py_ENABLE_SHARED MACOSX_DEPLOYMENT_TARGET LDSHARED CFLAGS'.split()
+	try:
+		lst = conf.get_python_variables(["get_config_var('%s') or ''" % x for x in v],
+			['from distutils.sysconfig import get_config_var'])
+	except RuntimeError:
+		conf.fatal("Python development headers not found (-v for details).")
+
+	vals = ['%s = %r' % (x, y) for (x, y) in zip(v, lst)]
+	conf.to_log("Configuration returned from %r:\n%r\n" % (pybin, '\n'.join(vals)))
+
+	dct = dict(zip(v, lst))
+	x = 'MACOSX_DEPLOYMENT_TARGET'
+	if dct[x]:
+		conf.env[x] = conf.environ[x] = dct[x]
+
+	env['pyext_PATTERN'] = '%s' + dct['SO'] # not a mistake
+
+	# Check for python libraries for embedding
+
+	all_flags = dct['LDFLAGS'] + ' ' + dct['CFLAGS']
+	conf.parse_flags(all_flags, 'PYEMBED')
+
+	all_flags = dct['LDFLAGS'] + ' ' + dct['LDSHARED'] + ' ' + dct['CFLAGS']
+	conf.parse_flags(all_flags, 'PYEXT')
+
+	result = None
+	#name = 'python' + env['PYTHON_VERSION']
+
+	# TODO simplify this
+	for name in ('python' + env['PYTHON_VERSION'], 'python' + env['PYTHON_VERSION'].replace('.', '')):
+
+		# LIBPATH_PYEMBED is already set; see if it works.
+		if not result and env['LIBPATH_PYEMBED']:
+			path = env['LIBPATH_PYEMBED']
+			conf.to_log("\n\n# Trying default LIBPATH_PYEMBED: %r\n" % path)
+			result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in LIBPATH_PYEMBED' % name)
+
+		if not result and dct['LIBDIR']:
+			path = [dct['LIBDIR']]
+			conf.to_log("\n\n# try again with -L$python_LIBDIR: %r\n" % path)
+			result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in LIBDIR' % name)
+
+		if not result and dct['LIBPL']:
+			path = [dct['LIBPL']]
+			conf.to_log("\n\n# try again with -L$python_LIBPL (some systems don't install the python library in $prefix/lib)\n")
+			result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in python_LIBPL' % name)
+
+		if not result:
+			path = [os.path.join(dct['prefix'], "libs")]
+			conf.to_log("\n\n# try again with -L$prefix/libs, and pythonXY name rather than pythonX.Y (win32)\n")
+			result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in $prefix/libs' % name)
+
+		if result:
+			break # do not forget to set LIBPATH_PYEMBED
+
+	if result:
+		env['LIBPATH_PYEMBED'] = path
+		env.append_value('LIB_PYEMBED', [name])
+	else:
+		conf.to_log("\n\n### LIB NOT FOUND\n")
+
+	# under certain conditions, python extensions must link to
+	# python libraries, not just python embedding programs.
+	if (Utils.is_win32 or sys.platform.startswith('os2')
+		or dct['Py_ENABLE_SHARED']):
+		env['LIBPATH_PYEXT'] = env['LIBPATH_PYEMBED']
+		env['LIB_PYEXT'] = env['LIB_PYEMBED']
+
+	# We check that pythonX.Y-config exists, and if it exists we
+	# use it to get only the includes, else fall back to distutils.
+	num = '.'.join(env['PYTHON_VERSION'].split('.')[:2])
+	conf.find_program(['python%s-config' % num, 'python-config-%s' % num, 'python%sm-config' % num], var='PYTHON_CONFIG', mandatory=False)
+
+	includes = []
+	if conf.env.PYTHON_CONFIG:
+		for incstr in conf.cmd_and_log([ conf.env.PYTHON_CONFIG, '--includes']).strip().split():
+			# strip the -I or /I
+			if (incstr.startswith('-I') or incstr.startswith('/I')):
+				incstr = incstr[2:]
+			# append include path, unless already given
+			if incstr not in includes:
+				includes.append(incstr)
+		conf.to_log("Include path for Python extensions (found via python-config --includes): %r\n" % (includes,))
+		env['INCLUDES_PYEXT'] = includes
+		env['INCLUDES_PYEMBED'] = includes
+	else:
+		conf.to_log("Include path for Python extensions "
+			       "(found via distutils module): %r\n" % (dct['INCLUDEPY'],))
+		env['INCLUDES_PYEXT'] = [dct['INCLUDEPY']]
+		env['INCLUDES_PYEMBED'] = [dct['INCLUDEPY']]
+
+	# Code using the Python API needs to be compiled with -fno-strict-aliasing
+	if env['CC_NAME'] == 'gcc':
+		env.append_value('CFLAGS_PYEMBED', ['-fno-strict-aliasing'])
+		env.append_value('CFLAGS_PYEXT', ['-fno-strict-aliasing'])
+	if env['CXX_NAME'] == 'gcc':
+		env.append_value('CXXFLAGS_PYEMBED', ['-fno-strict-aliasing'])
+		env.append_value('CXXFLAGS_PYEXT', ['-fno-strict-aliasing'])
+
+	if env.CC_NAME == "msvc":
+		from distutils.msvccompiler import MSVCCompiler
+		dist_compiler = MSVCCompiler()
+		dist_compiler.initialize()
+		env.append_value('CFLAGS_PYEXT', dist_compiler.compile_options)
+		env.append_value('CXXFLAGS_PYEXT', dist_compiler.compile_options)
+		env.append_value('LINKFLAGS_PYEXT', dist_compiler.ldflags_shared)
+
+	# See if it compiles
+	try:
+		conf.check(header_name='Python.h', define_name='HAVE_PYTHON_H',
+		   uselib='PYEMBED', fragment=FRAG,
+		   errmsg='Could not find the python development headers')
+	except conf.errors.ConfigurationError:
+		# python3.2, oh yeah
+		conf.check_cfg(path=conf.env.PYTHON_CONFIG, package='', uselib_store='PYEMBED', args=['--cflags', '--libs'])
+		conf.check(header_name='Python.h', define_name='HAVE_PYTHON_H', msg='Getting the python flags from python-config',
+			uselib='PYEMBED', fragment=FRAG, errmsg='Could not find the python development headers elsewhere')
+
+ at conf
+def check_python_version(conf, minver=None):
+	"""
+	Check if the python interpreter is found matching a given minimum version.
+	minver should be a tuple, eg. to check for python >= 2.4.2 pass (2,4,2) as minver.
+
+	If successful, PYTHON_VERSION is defined as 'MAJOR.MINOR'
+	(eg. '2.4') of the actual python version found, and PYTHONDIR is
+	defined, pointing to the site-packages directory appropriate for
+	this python version, where modules/packages/extensions should be
+	installed.
+
+	:param minver: minimum version
+	:type minver: tuple of int
+	"""
+	assert minver is None or isinstance(minver, tuple)
+	pybin = conf.env['PYTHON']
+	if not pybin:
+		conf.fatal('could not find the python executable')
+
+	# Get python version string
+	cmd = pybin + ['-c', 'import sys\nfor x in sys.version_info: print(str(x))']
+	debug('python: Running python command %r' % cmd)
+	lines = conf.cmd_and_log(cmd).split()
+	assert len(lines) == 5, "found %i lines, expected 5: %r" % (len(lines), lines)
+	pyver_tuple = (int(lines[0]), int(lines[1]), int(lines[2]), lines[3], int(lines[4]))
+
+	# compare python version with the minimum required
+	result = (minver is None) or (pyver_tuple >= minver)
+
+	if result:
+		# define useful environment variables
+		pyver = '.'.join([str(x) for x in pyver_tuple[:2]])
+		conf.env['PYTHON_VERSION'] = pyver
+
+		if 'PYTHONDIR' in conf.environ:
+			pydir = conf.environ['PYTHONDIR']
+		else:
+			if Utils.is_win32:
+				(python_LIBDEST, pydir) = \
+						conf.get_python_variables(
+											  ["get_config_var('LIBDEST') or ''",
+											   "get_python_lib(standard_lib=0, prefix=%r) or ''" % conf.env['PREFIX']],
+											  ['from distutils.sysconfig import get_config_var, get_python_lib'])
+			else:
+				python_LIBDEST = None
+				(pydir,) = \
+						conf.get_python_variables(
+											  ["get_python_lib(standard_lib=0, prefix=%r) or ''" % conf.env['PREFIX']],
+											  ['from distutils.sysconfig import get_python_lib'])
+			if python_LIBDEST is None:
+				if conf.env['LIBDIR']:
+					python_LIBDEST = os.path.join(conf.env['LIBDIR'], "python" + pyver)
+				else:
+					python_LIBDEST = os.path.join(conf.env['PREFIX'], "lib", "python" + pyver)
+
+
+		if 'PYTHONARCHDIR' in conf.environ:
+			pyarchdir = conf.environ['PYTHONARCHDIR']
+		else:
+			(pyarchdir, ) = conf.get_python_variables(
+											["get_python_lib(plat_specific=1, standard_lib=0, prefix=%r) or ''" % conf.env['PREFIX']],
+											['from distutils.sysconfig import get_python_lib'])
+			if not pyarchdir:
+				pyarchdir = pydir
+
+		if hasattr(conf, 'define'): # conf.define is added by the C tool, so may not exist
+			conf.define('PYTHONDIR', pydir)
+			conf.define('PYTHONARCHDIR', pyarchdir)
+
+		conf.env['PYTHONDIR'] = pydir
+		conf.env['PYTHONARCHDIR'] = pyarchdir
+
+	# Feedback
+	pyver_full = '.'.join(map(str, pyver_tuple[:3]))
+	if minver is None:
+		conf.msg('Checking for python version', pyver_full)
+	else:
+		minver_str = '.'.join(map(str, minver))
+		conf.msg('Checking for python version', pyver_tuple, ">= %s" % (minver_str,) and 'GREEN' or 'YELLOW')
+
+	if not result:
+		conf.fatal('The python version is too old, expecting %r' % (minver,))
+
+PYTHON_MODULE_TEMPLATE = '''
+import %s
+print(1)
+'''
+
+ at conf
+def check_python_module(conf, module_name):
+	"""
+	Check if the selected python interpreter can import the given python module::
+
+		def configure(conf):
+			conf.check_python_module('pygccxml')
+
+	:param module_name: module
+	:type module_name: string
+	"""
+	conf.start_msg('Python module %s' % module_name)
+	try:
+		conf.cmd_and_log(conf.env['PYTHON'] + ['-c', PYTHON_MODULE_TEMPLATE % module_name])
+	except:
+		conf.end_msg(False)
+		conf.fatal('Could not find the python module %r' % module_name)
+	conf.end_msg(True)
+
+def configure(conf):
+	"""
+	Detect the python interpreter
+	"""
+	try:
+		conf.find_program('python', var='PYTHON')
+	except conf.errors.ConfigurationError:
+		warn("could not find a python executable, setting to sys.executable '%s'" % sys.executable)
+		conf.env.PYTHON = sys.executable
+
+	if conf.env.PYTHON != sys.executable:
+		warn("python executable '%s' different from sys.executable '%s'" % (conf.env.PYTHON, sys.executable))
+	conf.env.PYTHON = conf.cmd_to_list(conf.env.PYTHON)
+
+	v = conf.env
+	v['PYCMD'] = '"import sys, py_compile;py_compile.compile(sys.argv[1], sys.argv[2])"'
+	v['PYFLAGS'] = ''
+	v['PYFLAGS_OPT'] = '-O'
+
+	v['PYC'] = getattr(Options.options, 'pyc', 1)
+	v['PYO'] = getattr(Options.options, 'pyo', 1)
+
+def options(opt):
+	"""
+	Add the options ``--nopyc`` and ``--nopyo``
+	"""
+	opt.add_option('--nopyc',
+			action='store_false',
+			default=1,
+			help = 'Do not install bytecode compiled .pyc files (configuration) [Default:install]',
+			dest = 'pyc')
+	opt.add_option('--nopyo',
+			action='store_false',
+			default=1,
+			help='Do not install optimised compiled .pyo files (configuration) [Default:install]',
+			dest='pyo')
+
diff --git a/xpdeint/waf/waflib/Tools/qt4.py b/xpdeint/waf/waflib/Tools/qt4.py
new file mode 100644
index 0000000..f6f823b
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/qt4.py
@@ -0,0 +1,639 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+
+"""
+Support for the Qt4 libraries and tools::
+
+	def options(opt):
+		opt.load('compiler_cxx qt4')
+	def configure(conf):
+		conf.load('compiler_cxx qt4')
+		conf.env.append_value('CXXFLAGS', ['-g']) # test
+	def build(bld):
+		bld(
+			features = 'qt4 cxx cxxprogram',
+			uselib   = 'QTCORE QTGUI QTOPENGL QTSVG',
+			source   = 'main.cpp textures.qrc aboutDialog.ui',
+			target   = 'window',
+		)
+
+The C++ files must include the .moc files, which is regarded as the
+best practice (much faster compilations). This also implies that the
+include paths have to be set properly. To have the include paths added
+automatically, use the following::
+
+	from waflib.TaskGen import feature, before_method, after_method
+	@feature('cxx')
+	@after_method('process_source')
+	@before_method('apply_incpaths')
+	def add_includes_paths(self):
+		incs = set(self.to_list(getattr(self, 'includes', '')))
+		for x in self.compiled_tasks:
+			incs.add(x.inputs[0].parent.path_from(self.path))
+		self.includes = list(incs)
+
+Another tool provides a Qt processing that does not require the moc
+includes. See http://code.google.com/p/waf/source/browse/trunk/playground/slow_qt/
+"""
+
+try:
+	from xml.sax import make_parser
+	from xml.sax.handler import ContentHandler
+except ImportError:
+	has_xml = False
+	ContentHandler = object
+else:
+	has_xml = True
+
+import os, sys
+from waflib.Tools import c_preproc, cxx
+from waflib import Task, Utils, Options, Errors
+from waflib.TaskGen import feature, after_method, extension
+from waflib.Configure import conf
+from waflib.Logs import error
+
+MOC_H = ['.h', '.hpp', '.hxx', '.hh']
+"""
+File extensions associated to the .moc files
+"""
+
+EXT_RCC = ['.qrc']
+"""
+File extension for the resource (.qrc) files
+"""
+
+EXT_UI  = ['.ui']
+"""
+File extension for the user interface (.ui) files
+"""
+
+EXT_QT4 = ['.cpp', '.cc', '.cxx', '.C']
+"""
+File extensions of C++ files that may require a .moc processing
+"""
+
+QT4_LIBS = "QtCore QtGui QtUiTools QtNetwork QtOpenGL QtSql QtSvg QtTest QtXml QtXmlPatterns QtWebKit Qt3Support QtHelp QtScript QtDeclarative"
+
+class qxx(cxx.cxx):
+	"""
+	Each C++ file can have zero or several .moc files to create.
+	They are known only when the files are scanned (preprocessor)
+	To avoid scanning the c++ files each time (parsing C/C++), the results
+	are retrieved from the task cache (bld.node_deps/bld.raw_deps).
+	The moc tasks are also created *dynamically* during the build.
+	"""
+
+	def __init__(self, *k, **kw):
+		Task.Task.__init__(self, *k, **kw)
+		self.moc_done = 0
+
+	def scan(self):
+		"""Re-use the C/C++ scanner, but remove the moc files from the dependencies"""
+		(nodes, names) = c_preproc.scan(self)
+		# for some reasons (variants) the moc node may end in the list of node deps
+		for x in nodes:
+			if x.name.endswith('.moc'):
+				nodes.remove(x)
+				names.append(x.path_from(self.inputs[0].parent.get_bld()))
+		return (nodes, names)
+
+	def runnable_status(self):
+		"""
+		Compute the task signature to make sure the scanner was executed. Create the
+		moc tasks by using :py:meth:`waflib.Tools.qt4.qxx.add_moc_tasks` (if necessary),
+		then postpone the task execution (there is no need to recompute the task signature).
+		"""
+		if self.moc_done:
+			return Task.Task.runnable_status(self)
+		else:
+			for t in self.run_after:
+				if not t.hasrun:
+					return Task.ASK_LATER
+			self.add_moc_tasks()
+			return Task.Task.runnable_status(self)
+
+	def add_moc_tasks(self):
+		"""
+		Create the moc tasks by looking in ``bld.raw_deps[self.uid()]``
+		"""
+		node = self.inputs[0]
+		bld = self.generator.bld
+
+		try:
+			# compute the signature once to know if there is a moc file to create
+			self.signature()
+		except KeyError:
+			# the moc file may be referenced somewhere else
+			pass
+		else:
+			# remove the signature, it must be recomputed with the moc task
+			delattr(self, 'cache_sig')
+
+		moctasks=[]
+		mocfiles=[]
+		try:
+			tmp_lst = bld.raw_deps[self.uid()]
+			bld.raw_deps[self.uid()] = []
+		except KeyError:
+			tmp_lst = []
+		for d in tmp_lst:
+			if not d.endswith('.moc'):
+				continue
+			# paranoid check
+			if d in mocfiles:
+				error("paranoia owns")
+				continue
+			# process that base.moc only once
+			mocfiles.append(d)
+
+			# find the extension - this search is done only once
+
+			h_node = None
+			try: ext = Options.options.qt_header_ext.split()
+			except AttributeError: pass
+			if not ext: ext = MOC_H
+
+			base2 = d[:-4]
+			for x in [node.parent] + self.generator.includes_nodes:
+				for e in ext:
+					h_node = x.find_node(base2 + e)
+					if h_node:
+						break
+				else:
+					continue
+				break
+			else:
+				raise Errors.WafError('no header found for %r which is a moc file' % d)
+
+			# next time we will not search for the extension (look at the 'for' loop below)
+			m_node = h_node.change_ext('.moc')
+			bld.node_deps[(self.inputs[0].parent.abspath(), m_node.name)] = h_node
+
+			# create the task
+			task = Task.classes['moc'](env=self.env, generator=self.generator)
+			task.set_inputs(h_node)
+			task.set_outputs(m_node)
+
+			# direct injection in the build phase (safe because called from the main thread)
+			gen = bld.producer
+			gen.outstanding.insert(0, task)
+			gen.total += 1
+
+			moctasks.append(task)
+
+		# remove raw deps except the moc files to save space (optimization)
+		tmp_lst = bld.raw_deps[self.uid()] = mocfiles
+
+		# look at the file inputs, it is set right above
+		lst = bld.node_deps.get(self.uid(), ())
+		for d in lst:
+			name = d.name
+			if name.endswith('.moc'):
+				task = Task.classes['moc'](env=self.env, generator=self.generator)
+				task.set_inputs(bld.node_deps[(self.inputs[0].parent.abspath(), name)]) # 1st element in a tuple
+				task.set_outputs(d)
+
+				gen = bld.producer
+				gen.outstanding.insert(0, task)
+				gen.total += 1
+
+				moctasks.append(task)
+
+		# simple scheduler dependency: run the moc task before others
+		self.run_after.update(set(moctasks))
+		self.moc_done = 1
+
+	run = Task.classes['cxx'].__dict__['run']
+
+class trans_update(Task.Task):
+	"""Update a .ts files from a list of C++ files"""
+	run_str = '${QT_LUPDATE} ${SRC} -ts ${TGT}'
+	color   = 'BLUE'
+Task.update_outputs(trans_update)
+
+class XMLHandler(ContentHandler):
+	"""
+	Parser for *.qrc* files
+	"""
+	def __init__(self):
+		self.buf = []
+		self.files = []
+	def startElement(self, name, attrs):
+		if name == 'file':
+			self.buf = []
+	def endElement(self, name):
+		if name == 'file':
+			self.files.append(str(''.join(self.buf)))
+	def characters(self, cars):
+		self.buf.append(cars)
+
+ at extension(*EXT_RCC)
+def create_rcc_task(self, node):
+	"Create rcc and cxx tasks for *.qrc* files"
+	rcnode = node.change_ext('_rc.cpp')
+	rcctask = self.create_task('rcc', node, rcnode)
+	cpptask = self.create_task('cxx', rcnode, rcnode.change_ext('.o'))
+	try:
+		self.compiled_tasks.append(cpptask)
+	except AttributeError:
+		self.compiled_tasks = [cpptask]
+	return cpptask
+
+ at extension(*EXT_UI)
+def create_uic_task(self, node):
+	"hook for uic tasks"
+	uictask = self.create_task('ui4', node)
+	uictask.outputs = [self.path.find_or_declare(self.env['ui_PATTERN'] % node.name[:-3])]
+
+ at extension('.ts')
+def add_lang(self, node):
+	"""add all the .ts file into self.lang"""
+	self.lang = self.to_list(getattr(self, 'lang', [])) + [node]
+
+ at feature('qt4')
+ at after_method('apply_link')
+def apply_qt4(self):
+	"""
+	Add MOC_FLAGS which may be necessary for moc::
+
+		def build(bld):
+			bld.program(features='qt4', source='main.cpp', target='app', use='QTCORE')
+
+	The additional parameters are:
+
+	:param lang: list of translation files (\*.ts) to process
+	:type lang: list of :py:class:`waflib.Node.Node` or string without the .ts extension
+	:param update: whether to process the C++ files to update the \*.ts files (use **waf --translate**)
+	:type update: bool
+	:param langname: if given, transform the \*.ts files into a .qrc files to include in the binary file
+	:type langname: :py:class:`waflib.Node.Node` or string without the .qrc extension
+	"""
+	if getattr(self, 'lang', None):
+		qmtasks = []
+		for x in self.to_list(self.lang):
+			if isinstance(x, str):
+				x = self.path.find_resource(x + '.ts')
+			qmtasks.append(self.create_task('ts2qm', x, x.change_ext('.qm')))
+
+		if getattr(self, 'update', None) and Options.options.trans_qt4:
+			cxxnodes = [a.inputs[0] for a in self.compiled_tasks] + [
+				a.inputs[0] for a in self.tasks if getattr(a, 'inputs', None) and a.inputs[0].name.endswith('.ui')]
+			for x in qmtasks:
+				self.create_task('trans_update', cxxnodes, x.inputs)
+
+		if getattr(self, 'langname', None):
+			qmnodes = [x.outputs[0] for x in qmtasks]
+			rcnode = self.langname
+			if isinstance(rcnode, str):
+				rcnode = self.path.find_or_declare(rcnode + '.qrc')
+			t = self.create_task('qm2rcc', qmnodes, rcnode)
+			k = create_rcc_task(self, t.outputs[0])
+			self.link_task.inputs.append(k.outputs[0])
+
+	lst = []
+	for flag in self.to_list(self.env['CXXFLAGS']):
+		if len(flag) < 2: continue
+		f = flag[0:2]
+		if f in ['-D', '-I', '/D', '/I']:
+			if (f[0] == '/'):
+				lst.append('-' + flag[1:])
+			else:
+				lst.append(flag)
+	self.env['MOC_FLAGS'] = lst
+
+ at extension(*EXT_QT4)
+def cxx_hook(self, node):
+	"""
+	Re-map C++ file extensions to the :py:class:`waflib.Tools.qt4.qxx` task.
+	"""
+	return self.create_compiled_task('qxx', node)
+
+class rcc(Task.Task):
+	"""
+	Process *.qrc* files
+	"""
+	color   = 'BLUE'
+	run_str = '${QT_RCC} -name ${SRC[0].name} ${SRC[0].abspath()} ${RCC_ST} -o ${TGT}'
+	ext_out = ['.h']
+
+	def scan(self):
+		"""Parse the *.qrc* files"""
+		node = self.inputs[0]
+		parser = make_parser()
+		curHandler = XMLHandler()
+		parser.setContentHandler(curHandler)
+		fi = open(self.inputs[0].abspath())
+		parser.parse(fi)
+		fi.close()
+
+		nodes = []
+		names = []
+		root = self.inputs[0].parent
+		for x in curHandler.files:
+			nd = root.find_resource(x)
+			if nd: nodes.append(nd)
+			else: names.append(x)
+		return (nodes, names)
+
+class moc(Task.Task):
+	"""
+	Create *.moc* files
+	"""
+	color   = 'BLUE'
+	run_str = '${QT_MOC} ${MOC_FLAGS} ${MOCCPPPATH_ST:INCPATHS} ${MOCDEFINES_ST:DEFINES} ${SRC} ${MOC_ST} ${TGT}'
+
+class ui4(Task.Task):
+	"""
+	Process *.ui* files
+	"""
+	color   = 'BLUE'
+	run_str = '${QT_UIC} ${SRC} -o ${TGT}'
+	ext_out = ['.h']
+
+class ts2qm(Task.Task):
+	"""
+	Create *.qm* files from *.ts* files
+	"""
+	color   = 'BLUE'
+	run_str = '${QT_LRELEASE} ${QT_LRELEASE_FLAGS} ${SRC} -qm ${TGT}'
+
+class qm2rcc(Task.Task):
+	"""
+	Transform *.qm* files into *.rc* files
+	"""
+	color = 'BLUE'
+	after = 'ts2qm'
+
+	def run(self):
+		"""Create a qrc file including the inputs"""
+		txt = '\n'.join(['<file>%s</file>' % k.path_from(self.outputs[0].parent) for k in self.inputs])
+		code = '<!DOCTYPE RCC><RCC version="1.0">\n<qresource>\n%s\n</qresource>\n</RCC>' % txt
+		self.outputs[0].write(code)
+
+def configure(self):
+	"""
+	Besides the configuration options, the environment variable QT4_ROOT may be used
+	to give the location of the qt4 libraries (absolute path).
+
+	The detection will use the program *pkg-config* through :py:func:`waflib.Tools.config_c.check_cfg`
+	"""
+	self.find_qt4_binaries()
+	self.set_qt4_libs_to_check()
+	self.find_qt4_libraries()
+	self.add_qt4_rpath()
+	self.simplify_qt4_libs()
+
+ at conf
+def find_qt4_binaries(self):
+	env = self.env
+	opt = Options.options
+
+	qtdir = getattr(opt, 'qtdir', '')
+	qtbin = getattr(opt, 'qtbin', '')
+
+	paths = []
+
+	if qtdir:
+		qtbin = os.path.join(qtdir, 'bin')
+
+	# the qt directory has been given from QT4_ROOT - deduce the qt binary path
+	if not qtdir:
+		qtdir = self.environ.get('QT4_ROOT', '')
+		qtbin = os.path.join(qtdir, 'bin')
+
+	if qtbin:
+		paths = [qtbin]
+
+	# no qtdir, look in the path and in /usr/local/Trolltech
+	if not qtdir:
+		paths = os.environ.get('PATH', '').split(os.pathsep)
+		paths.append('/usr/share/qt4/bin/')
+		try:
+			lst = Utils.listdir('/usr/local/Trolltech/')
+		except OSError:
+			pass
+		else:
+			if lst:
+				lst.sort()
+				lst.reverse()
+
+				# keep the highest version
+				qtdir = '/usr/local/Trolltech/%s/' % lst[0]
+				qtbin = os.path.join(qtdir, 'bin')
+				paths.append(qtbin)
+
+	# at the end, try to find qmake in the paths given
+	# keep the one with the highest version
+	cand = None
+	prev_ver = ['4', '0', '0']
+	for qmk in ['qmake-qt4', 'qmake4', 'qmake']:
+		try:
+			qmake = self.find_program(qmk, path_list=paths)
+		except self.errors.ConfigurationError:
+			pass
+		else:
+			try:
+				version = self.cmd_and_log([qmake, '-query', 'QT_VERSION']).strip()
+			except self.errors.ConfigurationError:
+				pass
+			else:
+				if version:
+					new_ver = version.split('.')
+					if new_ver > prev_ver:
+						cand = qmake
+						prev_ver = new_ver
+	if cand:
+		self.env.QMAKE = cand
+	else:
+		self.fatal('Could not find qmake for qt4')
+
+	qtbin = self.cmd_and_log([self.env.QMAKE, '-query', 'QT_INSTALL_BINS']).strip() + os.sep
+
+	def find_bin(lst, var):
+		for f in lst:
+			try:
+				ret = self.find_program(f, path_list=paths)
+			except self.errors.ConfigurationError:
+				pass
+			else:
+				env[var]=ret
+				break
+
+	find_bin(['uic-qt3', 'uic3'], 'QT_UIC3')
+	find_bin(['uic-qt4', 'uic'], 'QT_UIC')
+	if not env['QT_UIC']:
+		self.fatal('cannot find the uic compiler for qt4')
+
+	try:
+		uicver = self.cmd_and_log(env['QT_UIC'] + " -version 2>&1").strip()
+	except self.errors.ConfigurationError:
+		self.fatal('this uic compiler is for qt3, add uic for qt4 to your path')
+	uicver = uicver.replace('Qt User Interface Compiler ','').replace('User Interface Compiler for Qt', '')
+	self.msg('Checking for uic version', '%s' % uicver)
+	if uicver.find(' 3.') != -1:
+		self.fatal('this uic compiler is for qt3, add uic for qt4 to your path')
+
+	find_bin(['moc-qt4', 'moc'], 'QT_MOC')
+	find_bin(['rcc'], 'QT_RCC')
+	find_bin(['lrelease-qt4', 'lrelease'], 'QT_LRELEASE')
+	find_bin(['lupdate-qt4', 'lupdate'], 'QT_LUPDATE')
+
+	env['UIC3_ST']= '%s -o %s'
+	env['UIC_ST'] = '%s -o %s'
+	env['MOC_ST'] = '-o'
+	env['ui_PATTERN'] = 'ui_%s.h'
+	env['QT_LRELEASE_FLAGS'] = ['-silent']
+	env.MOCCPPPATH_ST = '-I%s'
+	env.MOCDEFINES_ST = '-D%s'
+
+ at conf
+def find_qt4_libraries(self):
+	qtlibs = getattr(Options.options, 'qtlibs', '')
+	if not qtlibs:
+		try:
+			qtlibs = self.cmd_and_log([self.env.QMAKE, '-query', 'QT_INSTALL_LIBS']).strip()
+		except Errors.WafError:
+			qtdir = self.cmd_and_log([self.env.QMAKE, '-query', 'QT_INSTALL_PREFIX']).strip() + os.sep
+			qtlibs = os.path.join(qtdir, 'lib')
+	self.msg('Found the Qt4 libraries in', qtlibs)
+
+	qtincludes = self.cmd_and_log([self.env.QMAKE, '-query', 'QT_INSTALL_HEADERS']).strip()
+	env = self.env
+	if not 'PKG_CONFIG_PATH' in os.environ:
+		os.environ['PKG_CONFIG_PATH'] = '%s:%s/pkgconfig:/usr/lib/qt4/lib/pkgconfig:/opt/qt4/lib/pkgconfig:/usr/lib/qt4/lib:/opt/qt4/lib' % (qtlibs, qtlibs)
+
+	try:
+		self.check_cfg(atleast_pkgconfig_version='0.1')
+	except self.errors.ConfigurationError:
+		for i in self.qt4_vars:
+			uselib = i.upper()
+			if Utils.unversioned_sys_platform == "darwin":
+				# Since at least qt 4.7.3 each library locates in separate directory
+				frameworkName = i + ".framework"
+				qtDynamicLib = os.path.join(qtlibs, frameworkName, i)
+				if os.path.exists(qtDynamicLib):
+					env.append_unique('FRAMEWORK_' + uselib, i)
+					self.msg('Checking for %s' % i, qtDynamicLib, 'GREEN')
+				else:
+					self.msg('Checking for %s' % i, False, 'YELLOW')
+				env.append_unique('INCLUDES_' + uselib, os.path.join(qtlibs, frameworkName, 'Headers'))
+			elif sys.platform != "win32":
+				qtDynamicLib = os.path.join(qtlibs, "lib" + i + ".so")
+				qtStaticLib = os.path.join(qtlibs, "lib" + i + ".a")
+				if os.path.exists(qtDynamicLib):
+					env.append_unique('LIB_' + uselib, i)
+					self.msg('Checking for %s' % i, qtDynamicLib, 'GREEN')
+				elif os.path.exists(qtStaticLib):
+					env.append_unique('LIB_' + uselib, i)
+					self.msg('Checking for %s' % i, qtStaticLib, 'GREEN')
+				else:
+					self.msg('Checking for %s' % i, False, 'YELLOW')
+
+				env.append_unique('LIBPATH_' + uselib, qtlibs)
+				env.append_unique('INCLUDES_' + uselib, qtincludes)
+				env.append_unique('INCLUDES_' + uselib, os.path.join(qtincludes, i))
+			else:
+				# Release library names are like QtCore4
+				for k in ("lib%s.a", "lib%s4.a", "%s.lib", "%s4.lib"):
+					lib = os.path.join(qtlibs, k % i)
+					if os.path.exists(lib):
+						env.append_unique('LIB_' + uselib, i + k[k.find("%s") + 2 : k.find('.')])
+						self.msg('Checking for %s' % i, lib, 'GREEN')
+						break
+				else:
+					self.msg('Checking for %s' % i, False, 'YELLOW')
+
+				env.append_unique('LIBPATH_' + uselib, qtlibs)
+				env.append_unique('INCLUDES_' + uselib, qtincludes)
+				env.append_unique('INCLUDES_' + uselib, os.path.join(qtincludes, i))
+
+				# Debug library names are like QtCore4d
+				uselib = i.upper() + "_debug"
+				for k in ("lib%sd.a", "lib%sd4.a", "%sd.lib", "%sd4.lib"):
+					lib = os.path.join(qtlibs, k % i)
+					if os.path.exists(lib):
+						env.append_unique('LIB_' + uselib, i + k[k.find("%s") + 2 : k.find('.')])
+						self.msg('Checking for %s' % i, lib, 'GREEN')
+						break
+				else:
+					self.msg('Checking for %s' % i, False, 'YELLOW')
+
+				env.append_unique('LIBPATH_' + uselib, qtlibs)
+				env.append_unique('INCLUDES_' + uselib, qtincludes)
+				env.append_unique('INCLUDES_' + uselib, os.path.join(qtincludes, i))
+	else:
+		for i in self.qt4_vars_debug + self.qt4_vars:
+			self.check_cfg(package=i, args='--cflags --libs', mandatory=False)
+
+ at conf
+def simplify_qt4_libs(self):
+	# the libpaths make really long command-lines
+	# remove the qtcore ones from qtgui, etc
+	env = self.env
+	def process_lib(vars_, coreval):
+		for d in vars_:
+			var = d.upper()
+			if var == 'QTCORE':
+				continue
+
+			value = env['LIBPATH_'+var]
+			if value:
+				core = env[coreval]
+				accu = []
+				for lib in value:
+					if lib in core:
+						continue
+					accu.append(lib)
+				env['LIBPATH_'+var] = accu
+
+	process_lib(self.qt4_vars,       'LIBPATH_QTCORE')
+	process_lib(self.qt4_vars_debug, 'LIBPATH_QTCORE_DEBUG')
+
+ at conf
+def add_qt4_rpath(self):
+	# rpath if wanted
+	env = self.env
+	if Options.options.want_rpath:
+		def process_rpath(vars_, coreval):
+			for d in vars_:
+				var = d.upper()
+				value = env['LIBPATH_'+var]
+				if value:
+					core = env[coreval]
+					accu = []
+					for lib in value:
+						if var != 'QTCORE':
+							if lib in core:
+								continue
+						accu.append('-Wl,--rpath='+lib)
+					env['RPATH_'+var] = accu
+		process_rpath(self.qt4_vars,       'LIBPATH_QTCORE')
+		process_rpath(self.qt4_vars_debug, 'LIBPATH_QTCORE_DEBUG')
+
+ at conf
+def set_qt4_libs_to_check(self):
+	if not hasattr(self, 'qt4_vars'):
+		self.qt4_vars = QT4_LIBS
+	self.qt4_vars = Utils.to_list(self.qt4_vars)
+	if not hasattr(self, 'qt4_vars_debug'):
+		self.qt4_vars_debug = [a + '_debug' for a in self.qt4_vars]
+	self.qt4_vars_debug = Utils.to_list(self.qt4_vars_debug)
+
+def options(opt):
+	"""
+	Command-line options
+	"""
+	opt.add_option('--want-rpath', action='store_true', default=False, dest='want_rpath', help='enable the rpath for qt libraries')
+
+	opt.add_option('--header-ext',
+		type='string',
+		default='',
+		help='header extension for moc files',
+		dest='qt_header_ext')
+
+	for i in 'qtdir qtbin qtlibs'.split():
+		opt.add_option('--'+i, type='string', default='', dest=i)
+
+	opt.add_option('--translate', action="store_true", help="collect translation strings", dest="trans_qt4", default=False)
+
diff --git a/xpdeint/waf/waflib/Tools/ruby.py b/xpdeint/waf/waflib/Tools/ruby.py
new file mode 100644
index 0000000..4965b01
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/ruby.py
@@ -0,0 +1,193 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# daniel.svensson at purplescout.se 2008
+# Thomas Nagy 2010 (ita)
+
+"""
+Support for Ruby extensions. A C/C++ compiler is required::
+
+	def options(opt):
+		opt.load('compiler_c ruby')
+	def configure(conf):
+		conf.load('compiler_c ruby')
+		conf.check_ruby_version((1,8,0))
+		conf.check_ruby_ext_devel()
+		conf.check_ruby_module('libxml')
+	def build(bld):
+		bld(
+			features = 'c cshlib rubyext',
+			source = 'rb_mytest.c',
+			target = 'mytest_ext',
+			install_path = '${ARCHDIR_RUBY}')
+		bld.install_files('${LIBDIR_RUBY}', 'Mytest.rb')
+"""
+
+import os
+from waflib import Task, Options, Utils
+from waflib.TaskGen import before_method, feature, after_method, Task, extension
+from waflib.Configure import conf
+
+ at feature('rubyext')
+ at before_method('apply_incpaths', 'apply_lib_vars', 'apply_bundle', 'apply_link')
+def init_rubyext(self):
+	"""
+	Add required variables for ruby extensions
+	"""
+	self.install_path = '${ARCHDIR_RUBY}'
+	self.uselib = self.to_list(getattr(self, 'uselib', ''))
+	if not 'RUBY' in self.uselib:
+		self.uselib.append('RUBY')
+	if not 'RUBYEXT' in self.uselib:
+		self.uselib.append('RUBYEXT')
+
+ at feature('rubyext')
+ at before_method('apply_link', 'propagate_uselib')
+def apply_ruby_so_name(self):
+	"""
+	Strip the *lib* prefix from ruby extensions
+	"""
+	self.env['cshlib_PATTERN'] = self.env['cxxshlib_PATTERN'] = self.env['rubyext_PATTERN']
+
+ at conf
+def check_ruby_version(self, minver=()):
+	"""
+	Checks if ruby is installed.
+	If installed the variable RUBY will be set in environment.
+	The ruby binary can be overridden by ``--with-ruby-binary`` command-line option.
+	"""
+
+	if Options.options.rubybinary:
+		self.env.RUBY = Options.options.rubybinary
+	else:
+		self.find_program('ruby', var='RUBY')
+
+	ruby = self.env.RUBY
+
+	try:
+		version = self.cmd_and_log([ruby, '-e', 'puts defined?(VERSION) ? VERSION : RUBY_VERSION']).strip()
+	except:
+		self.fatal('could not determine ruby version')
+	self.env.RUBY_VERSION = version
+
+	try:
+		ver = tuple(map(int, version.split(".")))
+	except:
+		self.fatal('unsupported ruby version %r' % version)
+
+	cver = ''
+	if minver:
+		if ver < minver:
+			self.fatal('ruby is too old %r' % ver)
+		cver = '.'.join([str(x) for x in minver])
+	else:
+		cver = ver
+
+	self.msg('Checking for ruby version %s' % str(minver or ''), cver)
+
+ at conf
+def check_ruby_ext_devel(self):
+	"""
+	Check if a ruby extension can be created
+	"""
+	if not self.env.RUBY:
+		self.fatal('ruby detection is required first')
+
+	if not self.env.CC_NAME and not self.env.CXX_NAME:
+		self.fatal('load a c/c++ compiler first')
+
+	version = tuple(map(int, self.env.RUBY_VERSION.split(".")))
+
+	def read_out(cmd):
+		return Utils.to_list(self.cmd_and_log([self.env.RUBY, '-rrbconfig', '-e', cmd]))
+
+	def read_config(key):
+		return read_out('puts Config::CONFIG[%r]' % key)
+
+	ruby = self.env['RUBY']
+	archdir = read_config('archdir')
+	cpppath = archdir
+
+	if version >= (1, 9, 0):
+		ruby_hdrdir = read_config('rubyhdrdir')
+		cpppath += ruby_hdrdir
+		cpppath += [os.path.join(ruby_hdrdir[0], read_config('arch')[0])]
+
+	self.check(header_name='ruby.h', includes=cpppath, errmsg='could not find ruby header file')
+
+	self.env.LIBPATH_RUBYEXT = read_config('libdir')
+	self.env.LIBPATH_RUBYEXT += archdir
+	self.env.INCLUDES_RUBYEXT = cpppath
+	self.env.CFLAGS_RUBYEXT = read_config('CCDLFLAGS')
+	self.env.rubyext_PATTERN = '%s.' + read_config('DLEXT')[0]
+
+	# ok this is really stupid, but the command and flags are combined.
+	# so we try to find the first argument...
+	flags = read_config('LDSHARED')
+	while flags and flags[0][0] != '-':
+		flags = flags[1:]
+
+	# we also want to strip out the deprecated ppc flags
+	if len(flags) > 1 and flags[1] == "ppc":
+		flags = flags[2:]
+
+	self.env.LINKFLAGS_RUBYEXT = flags
+	self.env.LINKFLAGS_RUBYEXT += read_config('LIBS')
+	self.env.LINKFLAGS_RUBYEXT += read_config('LIBRUBYARG_SHARED')
+
+	if Options.options.rubyarchdir:
+		self.env.ARCHDIR_RUBY = Options.options.rubyarchdir
+	else:
+		self.env.ARCHDIR_RUBY = read_config('sitearchdir')[0]
+
+	if Options.options.rubylibdir:
+		self.env.LIBDIR_RUBY = Options.options.rubylibdir
+	else:
+		self.env.LIBDIR_RUBY = read_config('sitelibdir')[0]
+
+ at conf
+def check_ruby_module(self, module_name):
+	"""
+	Check if the selected ruby interpreter can require the given ruby module::
+
+		def configure(conf):
+			conf.check_ruby_module('libxml')
+
+	:param module_name: module
+	:type  module_name: string
+	"""
+	self.start_msg('Ruby module %s' % module_name)
+	try:
+		self.cmd_and_log([self.env['RUBY'], '-e', 'require \'%s\';puts 1' % module_name])
+	except:
+		self.end_msg(False)
+		self.fatal('Could not find the ruby module %r' % module_name)
+	self.end_msg(True)
+
+ at extension('.rb')
+def process(self, node):
+	tsk = self.create_task('run_ruby', node)
+
+class run_ruby(Task.Task):
+	"""
+	Task to run ruby files detected by file extension .rb::
+	
+		def options(opt):
+			opt.load('ruby')
+		
+		def configure(ctx):
+			ctx.check_ruby_version()
+		
+		def build(bld):
+			bld.env['RBFLAGS'] = '-e puts "hello world"'
+			bld(source='a_ruby_file.rb')
+	"""
+	run_str = '${RUBY} ${RBFLAGS} -I ${SRC[0].parent.abspath()} ${SRC}'
+
+def options(opt):
+	"""
+	Add the ``--with-ruby-archdir``, ``--with-ruby-libdir`` and ``--with-ruby-binary`` options
+	"""
+	opt.add_option('--with-ruby-archdir', type='string', dest='rubyarchdir', help='Specify directory where to install arch specific files')
+	opt.add_option('--with-ruby-libdir', type='string', dest='rubylibdir', help='Specify alternate ruby library path')
+	opt.add_option('--with-ruby-binary', type='string', dest='rubybinary', help='Specify alternate ruby binary')
+
diff --git a/xpdeint/waf/waflib/Tools/suncc.py b/xpdeint/waf/waflib/Tools/suncc.py
new file mode 100644
index 0000000..be5b151
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/suncc.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+# Ralf Habacker, 2006 (rh)
+
+import os
+from waflib import Utils
+from waflib.Tools import ccroot, ar
+from waflib.Configure import conf
+
+ at conf
+def find_scc(conf):
+	"""
+	Detect the Sun C compiler
+	"""
+	v = conf.env
+	cc = None
+	if v['CC']: cc = v['CC']
+	elif 'CC' in conf.environ: cc = conf.environ['CC']
+	if not cc: cc = conf.find_program('cc', var='CC')
+	if not cc: conf.fatal('Could not find a Sun C compiler')
+	cc = conf.cmd_to_list(cc)
+
+	try:
+		conf.cmd_and_log(cc + ['-flags'])
+	except:
+		conf.fatal('%r is not a Sun compiler' % cc)
+
+	v['CC']  = cc
+	v['CC_NAME'] = 'sun'
+
+ at conf
+def scc_common_flags(conf):
+	"""
+	Flags required for executing the sun C compiler
+	"""
+	v = conf.env
+
+	v['CC_SRC_F']            = []
+	v['CC_TGT_F']            = ['-c', '-o']
+
+	# linker
+	if not v['LINK_CC']: v['LINK_CC'] = v['CC']
+	v['CCLNK_SRC_F']         = ''
+	v['CCLNK_TGT_F']         = ['-o']
+	v['CPPPATH_ST']          = '-I%s'
+	v['DEFINES_ST']          = '-D%s'
+
+	v['LIB_ST']              = '-l%s' # template for adding libs
+	v['LIBPATH_ST']          = '-L%s' # template for adding libpaths
+	v['STLIB_ST']            = '-l%s'
+	v['STLIBPATH_ST']        = '-L%s'
+
+	v['SONAME_ST']           = '-Wl,-h,%s'
+	v['SHLIB_MARKER']        = '-Bdynamic'
+	v['STLIB_MARKER']        = '-Bstatic'
+
+	# program
+	v['cprogram_PATTERN']    = '%s'
+
+	# shared library
+	v['CFLAGS_cshlib']       = ['-Kpic', '-DPIC']
+	v['LINKFLAGS_cshlib']    = ['-G']
+	v['cshlib_PATTERN']      = 'lib%s.so'
+
+	# static lib
+	v['LINKFLAGS_cstlib']    = ['-Bstatic']
+	v['cstlib_PATTERN']      = 'lib%s.a'
+
+def configure(conf):
+	conf.find_scc()
+	conf.find_ar()
+	conf.scc_common_flags()
+	conf.cc_load_tools()
+	conf.cc_add_flags()
+	conf.link_add_flags()
+
diff --git a/xpdeint/waf/waflib/Tools/suncxx.py b/xpdeint/waf/waflib/Tools/suncxx.py
new file mode 100644
index 0000000..2b967b3
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/suncxx.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+# Ralf Habacker, 2006 (rh)
+
+import os
+from waflib import Utils
+from waflib.Tools import ccroot, ar
+from waflib.Configure import conf
+
+ at conf
+def find_sxx(conf):
+	"""
+	Detect the sun C++ compiler
+	"""
+	v = conf.env
+	cc = None
+	if v['CXX']: cc = v['CXX']
+	elif 'CXX' in conf.environ: cc = conf.environ['CXX']
+	if not cc: cc = conf.find_program('CC', var='CXX') #studio
+	if not cc: cc = conf.find_program('c++', var='CXX')
+	if not cc: conf.fatal('Could not find a Sun C++ compiler')
+	cc = conf.cmd_to_list(cc)
+
+	try:
+		conf.cmd_and_log(cc + ['-flags'])
+	except:
+		conf.fatal('%r is not a Sun compiler' % cc)
+
+	v['CXX']  = cc
+	v['CXX_NAME'] = 'sun'
+
+ at conf
+def sxx_common_flags(conf):
+	"""
+	Flags required for executing the sun C++ compiler
+	"""
+	v = conf.env
+
+	v['CXX_SRC_F']           = []
+	v['CXX_TGT_F']           = ['-c', '-o']
+
+	# linker
+	if not v['LINK_CXX']: v['LINK_CXX'] = v['CXX']
+	v['CXXLNK_SRC_F']        = []
+	v['CXXLNK_TGT_F']        = ['-o']
+	v['CPPPATH_ST']          = '-I%s'
+	v['DEFINES_ST']          = '-D%s'
+
+	v['LIB_ST']              = '-l%s' # template for adding libs
+	v['LIBPATH_ST']          = '-L%s' # template for adding libpaths
+	v['STLIB_ST']            = '-l%s'
+	v['STLIBPATH_ST']        = '-L%s'
+
+	v['SONAME_ST']           = '-Wl,-h,%s'
+	v['SHLIB_MARKER']        = '-Bdynamic'
+	v['STLIB_MARKER']        = '-Bstatic'
+
+	# program
+	v['cxxprogram_PATTERN']  = '%s'
+
+	# shared library
+	v['CXXFLAGS_cxxshlib']   = ['-Kpic', '-DPIC']
+	v['LINKFLAGS_cxxshlib']  = ['-G']
+	v['cxxshlib_PATTERN']    = 'lib%s.so'
+
+	# static lib
+	v['LINKFLAGS_cxxstlib']  = ['-Bstatic']
+	v['cxxstlib_PATTERN']    = 'lib%s.a'
+
+def configure(conf):
+	conf.find_sxx()
+	conf.find_ar()
+	conf.sxx_common_flags()
+	conf.cxx_load_tools()
+	conf.cxx_add_flags()
+	conf.link_add_flags()
+
diff --git a/xpdeint/waf/waflib/Tools/tex.py b/xpdeint/waf/waflib/Tools/tex.py
new file mode 100644
index 0000000..bec109d
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/tex.py
@@ -0,0 +1,403 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+
+"""
+TeX/LaTeX/PDFLaTeX/XeLaTeX support
+
+Example::
+
+	def configure(conf):
+		conf.load('tex')
+		if not conf.env.LATEX:
+			conf.fatal('The program LaTex is required')
+
+	def build(bld):
+		bld(
+			features = 'tex',
+			type     = 'latex', # pdflatex or xelatex
+			source   = 'document.ltx', # mandatory, the source
+			outs     = 'ps', # 'pdf' or 'ps pdf'
+			deps     = 'crossreferencing.lst', # to give dependencies directly
+			prompt   = 1, # 0 for the batch mode
+			)
+
+To configure with a special program use::
+
+	$ PDFLATEX=luatex waf configure
+"""
+
+import os, re
+from waflib import Utils, Task, Errors
+from waflib.TaskGen import feature, before_method
+from waflib.Logs import error, warn, debug
+
+re_bibunit = re.compile(r'\\(?P<type>putbib)\[(?P<file>[^\[\]]*)\]',re.M)
+def bibunitscan(self):
+	"""
+	Parse the inputs and try to find the *bibunit* dependencies
+
+	:return: list of bibunit files
+	:rtype: list of :py:class:`waflib.Node.Node`
+	"""
+	node = self.inputs[0]
+
+	nodes = []
+	if not node: return nodes
+
+	code = Utils.readf(node.abspath())
+
+	for match in re_bibunit.finditer(code):
+		path = match.group('file')
+		if path:
+			for k in ['', '.bib']:
+				# add another loop for the tex include paths?
+				debug('tex: trying %s%s' % (path, k))
+				fi = node.parent.find_resource(path + k)
+				if fi:
+					nodes.append(fi)
+					# no break, people are crazy
+			else:
+				debug('tex: could not find %s' % path)
+
+	debug("tex: found the following bibunit files: %s" % nodes)
+	return nodes
+
+exts_deps_tex = ['', '.ltx', '.tex', '.bib', '.pdf', '.png', '.eps', '.ps']
+"""List of typical file extensions included in latex files"""
+
+exts_tex = ['.ltx', '.tex']
+"""List of typical file extensions that contain latex"""
+
+re_tex = re.compile(r'\\(?P<type>include|bibliography|putbib|includegraphics|input|import|bringin|lstinputlisting)(\[[^\[\]]*\])?{(?P<file>[^{}]*)}',re.M)
+"""Regexp for expressions that may include latex files"""
+
+g_bibtex_re = re.compile('bibdata', re.M)
+"""Regexp for bibtex files"""
+
+class tex(Task.Task):
+	"""
+	Compile a tex/latex file.
+
+	.. inheritance-diagram:: waflib.Tools.tex.latex waflib.Tools.tex.xelatex waflib.Tools.tex.pdflatex
+	"""
+
+	bibtex_fun, _ = Task.compile_fun('${BIBTEX} ${BIBTEXFLAGS} ${SRCFILE}', shell=False)
+	bibtex_fun.__doc__ = """
+	Execute the program **bibtex**
+	"""
+
+	makeindex_fun, _ = Task.compile_fun('${MAKEINDEX} ${MAKEINDEXFLAGS} ${SRCFILE}', shell=False)
+	makeindex_fun.__doc__ = """
+	Execute the program **makeindex**
+	"""
+
+	def scan_aux(self, node):
+		"""
+		A recursive regex-based scanner that finds included auxiliary files.
+		"""
+		nodes = [node]
+		re_aux = re.compile(r'\\@input{(?P<file>[^{}]*)}', re.M)
+
+		def parse_node(node):
+			code = node.read()
+			for match in re_aux.finditer(code):
+				path = match.group('file')
+				found = node.parent.find_or_declare(path)
+				if found and found not in nodes:
+					debug('tex: found aux node ' + found.abspath())
+					nodes.append(found)
+					parse_node(found)
+
+		parse_node(node)
+		return nodes
+
+	def scan(self):
+		"""
+		A recursive regex-based scanner that finds latex dependencies. It uses :py:attr:`waflib.Tools.tex.re_tex`
+
+		Depending on your needs you might want:
+
+		* to change re_tex::
+
+			from waflib.Tools import tex
+			tex.re_tex = myregex
+
+		* or to change the method scan from the latex tasks::
+
+			from waflib.Task import classes
+			classes['latex'].scan = myscanfunction
+		"""
+		node = self.inputs[0]
+
+		nodes = []
+		names = []
+		seen = []
+		if not node: return (nodes, names)
+
+		def parse_node(node):
+			if node in seen:
+				return
+			seen.append(node)
+			code = node.read()
+			global re_tex
+			for match in re_tex.finditer(code):
+				for path in match.group('file').split(','):
+					if path:
+						add_name = True
+						found = None
+						for k in exts_deps_tex:
+							debug('tex: trying %s%s' % (path, k))
+							found = node.parent.find_resource(path + k)
+							if found and not found in self.outputs:
+								nodes.append(found)
+								add_name = False
+								for ext in exts_tex:
+									if found.name.endswith(ext):
+										parse_node(found)
+										break
+							# no break, people are crazy
+						if add_name:
+							names.append(path)
+		parse_node(node)
+
+		for x in nodes:
+			x.parent.get_bld().mkdir()
+
+		debug("tex: found the following : %s and names %s" % (nodes, names))
+		return (nodes, names)
+
+	def check_status(self, msg, retcode):
+		"""
+		Check an exit status and raise an error with a particular message
+
+		:param msg: message to display if the code is non-zero
+		:type msg: string
+		:param retcode: condition
+		:type retcode: boolean
+		"""
+		if retcode != 0:
+			raise Errors.WafError("%r command exit status %r" % (msg, retcode))
+
+	def bibfile(self):
+		"""
+		Parse the *.aux* files to find a bibfile to process.
+		If yes, execute :py:meth:`waflib.Tools.tex.tex.bibtex_fun`
+		"""
+		need_bibtex = False
+		try:
+			for aux_node in self.aux_nodes:
+				ct = aux_node.read()
+				if g_bibtex_re.findall(ct):
+					need_bibtex = True
+					break
+		except (OSError, IOError):
+			error('error bibtex scan')
+		else:
+			# only the main .aux file needs to be processed
+			if need_bibtex:
+				warn('calling bibtex')
+
+				self.env.env = {}
+				self.env.env.update(os.environ)
+				self.env.env.update({'BIBINPUTS': self.TEXINPUTS, 'BSTINPUTS': self.TEXINPUTS})
+				self.env.SRCFILE = self.aux_nodes[0].name[:-4]
+				self.check_status('error when calling bibtex', self.bibtex_fun())
+
+	def bibunits(self):
+		"""
+		Parse the *.aux* file to find bibunit files. If there are bibunit files,
+		execute :py:meth:`waflib.Tools.tex.tex.bibtex_fun`.
+		"""
+		try:
+			bibunits = bibunitscan(self)
+		except FSError:
+			error('error bibunitscan')
+		else:
+			if bibunits:
+				fn  = ['bu' + str(i) for i in xrange(1, len(bibunits) + 1)]
+				if fn:
+					warn('calling bibtex on bibunits')
+
+				for f in fn:
+					self.env.env = {'BIBINPUTS': self.TEXINPUTS, 'BSTINPUTS': self.TEXINPUTS}
+					self.env.SRCFILE = f
+					self.check_status('error when calling bibtex', self.bibtex_fun())
+
+	def makeindex(self):
+		"""
+		Look on the filesystem if there is a *.idx* file to process. If yes, execute
+		:py:meth:`waflib.Tools.tex.tex.makeindex_fun`
+		"""
+		try:
+			idx_path = self.idx_node.abspath()
+			os.stat(idx_path)
+		except OSError:
+			warn('index file %s absent, not calling makeindex' % idx_path)
+		else:
+			warn('calling makeindex')
+
+			self.env.SRCFILE = self.idx_node.name
+			self.env.env = {}
+			self.check_status('error when calling makeindex %s' % idx_path, self.makeindex_fun())
+
+	def run(self):
+		"""
+		Runs the TeX build process.
+
+		It may require multiple passes, depending on the usage of cross-references,
+		bibliographies, content susceptible of needing such passes.
+		The appropriate TeX compiler is called until the *.aux* files stop changing.
+
+		Makeindex and bibtex are called if necessary.
+		"""
+		env = self.env
+
+		if not env['PROMPT_LATEX']:
+			env.append_value('LATEXFLAGS', '-interaction=batchmode')
+			env.append_value('PDFLATEXFLAGS', '-interaction=batchmode')
+			env.append_value('XELATEXFLAGS', '-interaction=batchmode')
+
+		fun = self.texfun
+
+		node = self.inputs[0]
+		srcfile = node.abspath()
+
+		texinputs = self.env.TEXINPUTS or ''
+		self.TEXINPUTS = node.parent.get_bld().abspath() + os.pathsep + node.parent.get_src().abspath() + os.pathsep + texinputs + os.pathsep
+
+		self.aux_node = node.change_ext('.aux') # TODO waf 1.7 remove (left for compatibility)
+
+		# important, set the cwd for everybody
+		self.cwd = self.inputs[0].parent.get_bld().abspath()
+
+		warn('first pass on %s' % self.__class__.__name__)
+
+		self.env.env = {}
+		self.env.env.update(os.environ)
+		self.env.env.update({'TEXINPUTS': self.TEXINPUTS})
+		self.env.SRCFILE = srcfile
+		self.check_status('error when calling latex', fun())
+
+		self.aux_nodes = self.scan_aux(node.change_ext('.aux'))
+		self.idx_node = node.change_ext('.idx')
+
+		self.bibfile()
+		self.bibunits()
+		self.makeindex()
+
+		hash = ''
+		for i in range(10):
+			# prevent against infinite loops - one never knows
+
+			# watch the contents of file.aux and stop if file.aux does not change anymore
+			prev_hash = hash
+			try:
+				hashes = [Utils.h_file(x.abspath()) for x in self.aux_nodes]
+				hash = Utils.h_list(hashes)
+			except (OSError, IOError):
+				error('could not read aux.h')
+				pass
+			if hash and hash == prev_hash:
+				break
+
+			# run the command
+			warn('calling %s' % self.__class__.__name__)
+
+			self.env.env = {}
+			self.env.env.update(os.environ)
+			self.env.env.update({'TEXINPUTS': self.TEXINPUTS})
+			self.env.SRCFILE = srcfile
+			self.check_status('error when calling %s' % self.__class__.__name__, fun())
+
+class latex(tex):
+	texfun, vars = Task.compile_fun('${LATEX} ${LATEXFLAGS} ${SRCFILE}', shell=False)
+class pdflatex(tex):
+	texfun, vars =  Task.compile_fun('${PDFLATEX} ${PDFLATEXFLAGS} ${SRCFILE}', shell=False)
+class xelatex(tex):
+	texfun, vars = Task.compile_fun('${XELATEX} ${XELATEXFLAGS} ${SRCFILE}', shell=False)
+
+class dvips(Task.Task):
+	run_str = '${DVIPS} ${DVIPSFLAGS} ${SRC} -o ${TGT}'
+	color   = 'BLUE'
+	after   = ['latex', 'pdflatex', 'xelatex']
+
+class dvipdf(Task.Task):
+	run_str = '${DVIPDF} ${DVIPDFFLAGS} ${SRC} ${TGT}'
+	color   = 'BLUE'
+	after   = ['latex', 'pdflatex', 'xelatex']
+
+class pdf2ps(Task.Task):
+	run_str = '${PDF2PS} ${PDF2PSFLAGS} ${SRC} ${TGT}'
+	color   = 'BLUE'
+	after   = ['latex', 'pdflatex', 'xelatex']
+
+ at feature('tex')
+ at before_method('process_source')
+def apply_tex(self):
+	"""
+	Create :py:class:`waflib.Tools.tex.tex` objects, and dvips/dvipdf/pdf2ps tasks if necessary (outs='ps', etc).
+	"""
+	if not getattr(self, 'type', None) in ['latex', 'pdflatex', 'xelatex']:
+		self.type = 'pdflatex'
+
+	tree = self.bld
+	outs = Utils.to_list(getattr(self, 'outs', []))
+
+	# prompt for incomplete files (else the batchmode is used)
+	self.env['PROMPT_LATEX'] = getattr(self, 'prompt', 1)
+
+	deps_lst = []
+
+	if getattr(self, 'deps', None):
+		deps = self.to_list(self.deps)
+		for filename in deps:
+			n = self.path.find_resource(filename)
+			if not n in deps_lst: deps_lst.append(n)
+
+	for node in self.to_nodes(self.source):
+
+		if self.type == 'latex':
+			task = self.create_task('latex', node, node.change_ext('.dvi'))
+		elif self.type == 'pdflatex':
+			task = self.create_task('pdflatex', node, node.change_ext('.pdf'))
+		elif self.type == 'xelatex':
+			task = self.create_task('xelatex', node, node.change_ext('.pdf'))
+
+		task.env = self.env
+
+		# add the manual dependencies
+		if deps_lst:
+			try:
+				lst = tree.node_deps[task.uid()]
+				for n in deps_lst:
+					if not n in lst:
+						lst.append(n)
+			except KeyError:
+				tree.node_deps[task.uid()] = deps_lst
+
+		if self.type == 'latex':
+			if 'ps' in outs:
+				tsk = self.create_task('dvips', task.outputs, node.change_ext('.ps'))
+				tsk.env.env = {'TEXINPUTS' : node.parent.abspath() + os.pathsep + self.path.abspath() + os.pathsep + self.path.get_bld().abspath()}
+			if 'pdf' in outs:
+				tsk = self.create_task('dvipdf', task.outputs, node.change_ext('.pdf'))
+				tsk.env.env = {'TEXINPUTS' : node.parent.abspath() + os.pathsep + self.path.abspath() + os.pathsep + self.path.get_bld().abspath()}
+		elif self.type == 'pdflatex':
+			if 'ps' in outs:
+				self.create_task('pdf2ps', task.outputs, node.change_ext('.ps'))
+	self.source = []
+
+def configure(self):
+	"""
+	Try to find the programs tex, latex and others. Do not raise any error if they
+	are not found.
+	"""
+	v = self.env
+	for p in 'tex latex pdflatex xelatex bibtex dvips dvipdf ps2pdf makeindex pdf2ps'.split():
+		try:
+			self.find_program(p, var=p.upper())
+		except self.errors.ConfigurationError:
+			pass
+	v['DVIPSFLAGS'] = '-Ppdf'
+
diff --git a/xpdeint/waf/waflib/Tools/vala.py b/xpdeint/waf/waflib/Tools/vala.py
new file mode 100644
index 0000000..a4e4dfa
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/vala.py
@@ -0,0 +1,339 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Ali Sabil, 2007
+# Radosław Szkodziński, 2010
+
+"""
+At this point, vala is still unstable, so do not expect
+this tool to be too stable either (apis, etc)
+"""
+
+import os.path, shutil, re
+from waflib import Context, Task, Utils, Logs, Options, Errors
+from waflib.TaskGen import extension
+from waflib.Configure import conf
+
+class valac(Task.Task):
+	"""
+	Task to compile vala files.
+	"""
+	vars = ["VALAC", "VALAC_VERSION", "VALAFLAGS"]
+	ext_out = ['.h']
+
+	def run(self):
+		env = self.env
+
+		cmd = [env['VALAC'], '-C', '--quiet']
+		cmd.extend(Utils.to_list(env['VALAFLAGS']))
+
+		if self.threading:
+			cmd.append('--thread')
+
+		if self.profile:
+			cmd.append('--profile=%s' % self.profile)
+
+		if self.target_glib:
+			cmd.append('--target-glib=%s' % self.target_glib)
+
+		if self.is_lib:
+			cmd.append('--library=' + self.target)
+			for x in self.outputs:
+				if x.name.endswith('.h'):
+					cmd.append('--header=' + x.name)
+			if self.gir:
+				cmd.append('--gir=%s.gir' % self.gir)
+
+		for vapi_dir in self.vapi_dirs:
+			cmd.append('--vapidir=%s' % vapi_dir)
+
+		for package in self.packages:
+			cmd.append('--pkg=%s' % package)
+
+		for package in self.packages_private:
+			cmd.append('--pkg=%s' % package)
+
+		for define in self.vala_defines:
+			cmd.append('--define=%s' % define)
+
+		cmd.extend([a.abspath() for a in self.inputs])
+		ret = self.exec_command(cmd, cwd=self.outputs[0].parent.abspath())
+
+		if ret:
+			return ret
+
+		for x in self.outputs:
+			if id(x.parent) != id(self.outputs[0].parent):
+				shutil.move(self.outputs[0].parent.abspath() + os.sep + x.name, x.abspath())
+
+		if self.packages and getattr(self, 'deps_node', None):
+			self.deps_node.write('\n'.join(self.packages))
+
+		return ret
+
+ at extension('.vala', '.gs')
+def vala_file(self, node):
+	"""
+	Compile a vala file and bind the task to *self.valatask*. If an existing vala task is already set, add the node
+	to its inputs. The typical example is::
+
+		def build(bld):
+			bld.program(
+				packages      = 'gtk+-2.0',
+				target        = 'vala-gtk-example',
+				uselib        = 'GTK GLIB',
+				source        = 'vala-gtk-example.vala foo.vala',
+				vala_defines  = ['DEBUG']
+				# the following arguments are for libraries
+				#gir          = 'hello-1.0',
+				#gir_path     = '/tmp',
+				#vapi_path = '/tmp',
+				#pkg_name = 'hello'
+				# disable installing of gir, vapi and header
+				#install_binding = False
+			)
+
+
+	:param node: vala file
+	:type node: :py:class:`waflib.Node.Node`
+	"""
+	# TODO: the vala task should use self.generator.attribute instead of copying attributes from self to the task
+	valatask = getattr(self, "valatask", None)
+	# there is only one vala task and it compiles all vala files .. :-/
+	if not valatask:
+		def _get_api_version():
+			api_version = '1.0'
+			if hasattr(Context.g_module, 'API_VERSION'):
+				version = Context.g_module.API_VERSION.split(".")
+				if version[0] == "0":
+					api_version = "0." + version[1]
+				else:
+					api_version = version[0] + ".0"
+			return api_version
+
+		valatask = self.create_task('valac')
+		self.valatask = valatask # this assumes one vala task by task generator
+		self.includes = Utils.to_list(getattr(self, 'includes', []))
+		self.uselib = self.to_list(getattr(self, 'uselib', []))
+		valatask.packages = []
+		valatask.packages_private = Utils.to_list(getattr(self, 'packages_private', []))
+		valatask.vapi_dirs = []
+		valatask.target = self.target
+		valatask.threading = False
+		valatask.install_path = getattr(self, 'install_path', '')
+		valatask.profile = getattr(self, 'profile', 'gobject')
+		valatask.vala_defines = getattr(self, 'vala_defines', [])
+		valatask.target_glib = None
+		valatask.gir = getattr(self, 'gir', None)
+		valatask.gir_path = getattr(self, 'gir_path', '${DATAROOTDIR}/gir-1.0')
+		valatask.vapi_path = getattr(self, 'vapi_path', '${DATAROOTDIR}/vala/vapi')
+		valatask.pkg_name = getattr(self, 'pkg_name', self.env['PACKAGE'])
+		valatask.header_path = getattr(self, 'header_path', '${INCLUDEDIR}/%s-%s' % (valatask.pkg_name, _get_api_version()))
+		valatask.install_binding = getattr(self, 'install_binding', True)
+
+		valatask.is_lib = False
+		if not 'cprogram' in self.features:
+			valatask.is_lib = True
+
+		packages = Utils.to_list(getattr(self, 'packages', []))
+		vapi_dirs = Utils.to_list(getattr(self, 'vapi_dirs', []))
+		includes =  []
+
+		if hasattr(self, 'use'):
+			local_packages = Utils.to_list(self.use)[:] # make sure to have a copy
+			seen = []
+			while len(local_packages) > 0:
+				package = local_packages.pop()
+				if package in seen:
+					continue
+				seen.append(package)
+
+				# check if the package exists
+				try:
+					package_obj = self.bld.get_tgen_by_name(package)
+				except Errors.WafError:
+					continue
+				package_name = package_obj.target
+				package_node = package_obj.path
+				package_dir = package_node.path_from(self.path)
+
+				for task in package_obj.tasks:
+					for output in task.outputs:
+						if output.name == package_name + ".vapi":
+							valatask.set_run_after(task)
+							if package_name not in packages:
+								packages.append(package_name)
+							if package_dir not in vapi_dirs:
+								vapi_dirs.append(package_dir)
+							if package_dir not in includes:
+								includes.append(package_dir)
+
+				if hasattr(package_obj, 'use'):
+					lst = self.to_list(package_obj.use)
+					lst.reverse()
+					local_packages = [pkg for pkg in lst if pkg not in seen] + local_packages
+
+		valatask.packages = packages
+		for vapi_dir in vapi_dirs:
+			try:
+				valatask.vapi_dirs.append(self.path.find_dir(vapi_dir).abspath())
+				valatask.vapi_dirs.append(self.path.find_dir(vapi_dir).get_bld().abspath())
+			except AttributeError:
+				Logs.warn("Unable to locate Vala API directory: '%s'" % vapi_dir)
+
+		self.includes.append(self.bld.srcnode.abspath())
+		self.includes.append(self.bld.bldnode.abspath())
+		for include in includes:
+			try:
+				self.includes.append(self.path.find_dir(include).abspath())
+				self.includes.append(self.path.find_dir(include).get_bld().abspath())
+			except AttributeError:
+				Logs.warn("Unable to locate include directory: '%s'" % include)
+
+
+		if valatask.profile == 'gobject':
+			if hasattr(self, 'target_glib'):
+				Logs.warn('target_glib on vala tasks is not supported --vala-target-glib=MAJOR.MINOR from the vala tool options')
+
+			if getattr(Options.options, 'vala_target_glib', None):
+				valatask.target_glib = Options.options.vala_target_glib
+
+			if not 'GOBJECT' in self.uselib:
+				self.uselib.append('GOBJECT')
+
+		if hasattr(self, 'threading'):
+			if valatask.profile == 'gobject':
+				valatask.threading = self.threading
+				if not 'GTHREAD' in self.uselib:
+					self.uselib.append('GTHREAD')
+			else:
+				#Vala doesn't have threading support for dova nor posix
+				Logs.warn("Profile %s does not have threading support" % valatask.profile)
+
+		if valatask.is_lib:
+			valatask.outputs.append(self.path.find_or_declare('%s.h' % self.target))
+			valatask.outputs.append(self.path.find_or_declare('%s.vapi' % self.target))
+
+			if valatask.gir:
+				valatask.outputs.append(self.path.find_or_declare('%s.gir' % self.gir))
+
+			if valatask.packages:
+				d = self.path.find_or_declare('%s.deps' % self.target)
+				valatask.outputs.append(d)
+				valatask.deps_node = d
+
+	valatask.inputs.append(node)
+	c_node = node.change_ext('.c')
+
+	valatask.outputs.append(c_node)
+	self.source.append(c_node)
+
+	if valatask.is_lib and valatask.install_binding:
+		headers_list = [o for o in valatask.outputs if o.suffix() == ".h"]
+		try:
+			self.install_vheader.source = headers_list
+		except AttributeError:
+			self.install_vheader = self.bld.install_files(valatask.header_path, headers_list, self.env)
+
+		vapi_list = [o for o in valatask.outputs if (o.suffix() in (".vapi", ".deps"))]
+		try:
+			self.install_vapi.source = vapi_list
+		except AttributeError:
+			self.install_vapi = self.bld.install_files(valatask.vapi_path, vapi_list, self.env)
+
+		gir_list = [o for o in valatask.outputs if o.suffix() == ".gir"]
+		try:
+			self.install_gir.source = gir_list
+		except AttributeError:
+			self.install_gir = self.bld.install_files(valatask.gir_path, gir_list, self.env)
+
+valac = Task.update_outputs(valac) # no decorators for python2 classes
+
+ at conf
+def find_valac(self, valac_name, min_version):
+	"""
+	Find the valac program, and execute it to store the version
+	number in *conf.env.VALAC_VERSION*
+
+	:param valac_name: program name
+	:type valac_name: string or list of string
+	:param min_version: minimum version acceptable
+	:type min_version: tuple of int
+	"""
+	valac = self.find_program(valac_name, var='VALAC')
+	try:
+		output = self.cmd_and_log(valac + ' --version')
+	except Exception:
+		valac_version = None
+	else:
+		ver = re.search(r'\d+.\d+.\d+', output).group(0).split('.')
+		valac_version = tuple([int(x) for x in ver])
+
+	self.msg('Checking for %s version >= %r' % (valac_name, min_version),
+	         valac_version, valac_version and valac_version >= min_version)
+	if valac and valac_version < min_version:
+		self.fatal("%s version %r is too old, need >= %r" % (valac_name, valac_version, min_version))
+
+	self.env['VALAC_VERSION'] = valac_version
+	return valac
+
+ at conf
+def check_vala(self, min_version=(0,8,0), branch=None):
+	"""
+	Check if vala compiler from a given branch exists of at least a given
+	version.
+
+	:param min_version: minimum version acceptable (0.8.0)
+	:type min_version: tuple
+	:param branch: first part of the version number, in case a snapshot is used (0, 8)
+	:type branch: tuple of int
+	"""
+	if not branch:
+		branch = min_version[:2]
+	try:
+		find_valac(self, 'valac-%d.%d' % (branch[0], branch[1]), min_version)
+	except self.errors.ConfigurationError:
+		find_valac(self, 'valac', min_version)
+
+ at conf
+def check_vala_deps(self):
+	"""
+	Load the gobject and gthread packages if they are missing.
+	"""
+	if not self.env['HAVE_GOBJECT']:
+		pkg_args = {'package':      'gobject-2.0',
+		            'uselib_store': 'GOBJECT',
+		            'args':         '--cflags --libs'}
+		if getattr(Options.options, 'vala_target_glib', None):
+			pkg_args['atleast_version'] = Options.options.vala_target_glib
+		self.check_cfg(**pkg_args)
+
+	if not self.env['HAVE_GTHREAD']:
+		pkg_args = {'package':      'gthread-2.0',
+		            'uselib_store': 'GTHREAD',
+		            'args':         '--cflags --libs'}
+		if getattr(Options.options, 'vala_target_glib', None):
+			pkg_args['atleast_version'] = Options.options.vala_target_glib
+		self.check_cfg(**pkg_args)
+
+def configure(self):
+	"""
+	Use the following to enforce minimum vala version::
+
+		def configure(conf):
+			conf.load('vala', funs='')
+			conf.check_vala(min_version=(0,10,0))
+	"""
+	self.load('gnu_dirs')
+	self.check_vala_deps()
+	self.check_vala()
+
+def options(opt):
+	"""
+	Load the :py:mod:`waflib.Tools.gnu_dirs` tool and add the ``--vala-target-glib`` command-line option
+	"""
+	opt.load('gnu_dirs')
+	valaopts = opt.add_option_group('Vala Compiler Options')
+	valaopts.add_option ('--vala-target-glib', default=None,
+		dest='vala_target_glib', metavar='MAJOR.MINOR',
+		help='Target version of glib for Vala GObject code generation')
+
diff --git a/xpdeint/waf/waflib/Tools/waf_unit_test.py b/xpdeint/waf/waflib/Tools/waf_unit_test.py
new file mode 100644
index 0000000..7771e57
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/waf_unit_test.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Carlos Rafael Giani, 2006
+# Thomas Nagy, 2010
+
+"""
+Unit testing system for C/C++/D providing test execution:
+
+* in parallel, by using ``waf -j``
+* partial (only the tests that have changed) or full (by using ``waf --alltests``)
+
+The tests are declared by adding the **test** feature to programs::
+
+	def options(opt):
+		opt.load('compiler_cxx waf_unit_test')
+	def configure(conf):
+		conf.load('compiler_cxx waf_unit_test')
+	def build(bld):
+		bld(features='cxx cxxprogram test', source='main.cpp', target='app')
+		# or
+		bld.program(features='test', source='main2.cpp', target='app2')
+
+When the build is executed, the program 'test' will be built and executed without arguments.
+The success/failure is detected by looking at the return code. The status and the standard output/error
+are stored on the build context.
+
+The results can be displayed by registering a callback function. Here is how to call
+the predefined callback::
+
+	def build(bld):
+		bld(features='cxx cxxprogram test', source='main.c', target='app')
+		from waflib.Tools import waf_unit_test
+		bld.add_post_fun(waf_unit_test.summary)
+"""
+
+import os, sys
+from waflib.TaskGen import feature, after_method
+from waflib import Utils, Task, Logs, Options
+testlock = Utils.threading.Lock()
+
+ at feature('test')
+ at after_method('apply_link')
+def make_test(self):
+	"""Create the unit test task. There can be only one unit test task by task generator."""
+	if getattr(self, 'link_task', None):
+		self.create_task('utest', self.link_task.outputs)
+
+class utest(Task.Task):
+	"""
+	Execute a unit test
+	"""
+	color = 'PINK'
+	after = ['vnum', 'inst']
+	vars = []
+	def runnable_status(self):
+		"""
+		Always execute the task if `waf --alltests` was used
+		"""
+		ret = super(utest, self).runnable_status()
+		if ret == Task.SKIP_ME:
+			if getattr(Options.options, 'all_tests', False):
+				return Task.RUN_ME
+		return ret
+
+	def run(self):
+		"""
+		Execute the test. The execution is always successful, but the results
+		are stored on ``self.generator.bld.utest_results`` for postprocessing.
+		"""
+
+		filename = self.inputs[0].abspath()
+		self.ut_exec = getattr(self, 'ut_exec', [filename])
+		if getattr(self.generator, 'ut_fun', None):
+			self.generator.ut_fun(self)
+
+		try:
+			fu = getattr(self.generator.bld, 'all_test_paths')
+		except AttributeError:
+			fu = os.environ.copy()
+			self.generator.bld.all_test_paths = fu
+
+			lst = []
+			for g in self.generator.bld.groups:
+				for tg in g:
+					if getattr(tg, 'link_task', None):
+						lst.append(tg.link_task.outputs[0].parent.abspath())
+
+			def add_path(dct, path, var):
+				dct[var] = os.pathsep.join(Utils.to_list(path) + [os.environ.get(var, '')])
+
+			if Utils.is_win32:
+				add_path(fu, lst, 'PATH')
+			elif Utils.unversioned_sys_platform() == 'darwin':
+				add_path(fu, lst, 'DYLD_LIBRARY_PATH')
+				add_path(fu, lst, 'LD_LIBRARY_PATH')
+			else:
+				add_path(fu, lst, 'LD_LIBRARY_PATH')
+
+
+		cwd = getattr(self.generator, 'ut_cwd', '') or self.inputs[0].parent.abspath()
+		proc = Utils.subprocess.Popen(self.ut_exec, cwd=cwd, env=fu, stderr=Utils.subprocess.PIPE, stdout=Utils.subprocess.PIPE)
+		(stdout, stderr) = proc.communicate()
+
+		tup = (filename, proc.returncode, stdout, stderr)
+		self.generator.utest_result = tup
+
+		testlock.acquire()
+		try:
+			bld = self.generator.bld
+			Logs.debug("ut: %r", tup)
+			try:
+				bld.utest_results.append(tup)
+			except AttributeError:
+				bld.utest_results = [tup]
+		finally:
+			testlock.release()
+
+def summary(bld):
+	"""
+	Display an execution summary::
+
+		def build(bld):
+			bld(features='cxx cxxprogram test', source='main.c', target='app')
+			from waflib.Tools import waf_unit_test
+			bld.add_post_fun(waf_unit_test.summary)
+	"""
+	lst = getattr(bld, 'utest_results', [])
+	if lst:
+		Logs.pprint('CYAN', 'execution summary')
+
+		total = len(lst)
+		tfail = len([x for x in lst if x[1]])
+
+		Logs.pprint('CYAN', '  tests that pass %d/%d' % (total-tfail, total))
+		for (f, code, out, err) in lst:
+			if not code:
+				Logs.pprint('CYAN', '    %s' % f)
+
+		Logs.pprint('CYAN', '  tests that fail %d/%d' % (tfail, total))
+		for (f, code, out, err) in lst:
+			if code:
+				Logs.pprint('CYAN', '    %s' % f)
+
+def options(opt):
+	"""
+	Provide the ``--alltests`` command-line option.
+	"""
+	opt.add_option('--alltests', action='store_true', default=False, help='Exec all unit tests', dest='all_tests')
+
diff --git a/xpdeint/waf/waflib/Tools/winres.py b/xpdeint/waf/waflib/Tools/winres.py
new file mode 100644
index 0000000..f54c090
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/winres.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Brant Young, 2007
+
+"Process *.rc* files for C/C++: X{.rc -> [.res|.rc.o]}"
+
+from waflib import Task
+from waflib.TaskGen import extension
+
+ at extension('.rc')
+def rc_file(self, node):
+	"""
+	Bind the .rc extension to a winrc task
+	"""
+	obj_ext = '.rc.o'
+	if self.env['WINRC_TGT_F'] == '/fo':
+		obj_ext = '.res'
+	rctask = self.create_task('winrc', node, node.change_ext(obj_ext))
+	try:
+		self.compiled_tasks.append(rctask)
+	except AttributeError:
+		self.compiled_tasks = [rctask]
+
+class winrc(Task.Task):
+	"""
+	Task for compiling resource files
+	"""
+	run_str = '${WINRC} ${WINRCFLAGS} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${WINRC_TGT_F} ${TGT} ${WINRC_SRC_F} ${SRC}'
+	color   = 'BLUE'
+
+def configure(conf):
+	"""
+	Detect the programs RC or windres, depending on the C/C++ compiler in use
+	"""
+	v = conf.env
+	v['WINRC_TGT_F'] = '-o'
+	v['WINRC_SRC_F'] = '-i'
+
+	# find rc.exe
+	if not conf.env.WINRC:
+		if v.CC_NAME == 'msvc':
+			conf.find_program('RC', var='WINRC', path_list = v['PATH'])
+			v['WINRC_TGT_F'] = '/fo'
+			v['WINRC_SRC_F'] = ''
+		else:
+			conf.find_program('windres', var='WINRC', path_list = v['PATH'])
+	if not conf.env.WINRC:
+		conf.fatal('winrc was not found!')
+
+	v['WINRCFLAGS'] = []
+
diff --git a/xpdeint/waf/waflib/Tools/xlc.py b/xpdeint/waf/waflib/Tools/xlc.py
new file mode 100644
index 0000000..0c232dc
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/xlc.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+# Ralf Habacker, 2006 (rh)
+# Yinon Ehrlich, 2009
+# Michael Kuhn, 2009
+
+from waflib.Tools import ccroot, ar
+from waflib.Configure import conf
+
+ at conf
+def find_xlc(conf):
+	"""
+	Detect the Aix C compiler
+	"""
+	cc = conf.find_program(['xlc_r', 'xlc'], var='CC')
+	cc = conf.cmd_to_list(cc)
+	conf.get_xlc_version(cc)
+	conf.env.CC_NAME = 'xlc'
+	conf.env.CC      = cc
+
+ at conf
+def xlc_common_flags(conf):
+	"""
+	Flags required for executing the Aix C compiler
+	"""
+	v = conf.env
+
+	v['CC_SRC_F']            = []
+	v['CC_TGT_F']            = ['-c', '-o']
+
+	# linker
+	if not v['LINK_CC']: v['LINK_CC'] = v['CC']
+	v['CCLNK_SRC_F']         = []
+	v['CCLNK_TGT_F']         = ['-o']
+	v['CPPPATH_ST']          = '-I%s'
+	v['DEFINES_ST']          = '-D%s'
+
+	v['LIB_ST']              = '-l%s' # template for adding libs
+	v['LIBPATH_ST']          = '-L%s' # template for adding libpaths
+	v['STLIB_ST']            = '-l%s'
+	v['STLIBPATH_ST']        = '-L%s'
+	v['RPATH_ST']            = '-Wl,-rpath,%s'
+
+	v['SONAME_ST']           = []
+	v['SHLIB_MARKER']        = []
+	v['STLIB_MARKER']        = []
+
+	# program
+	v['LINKFLAGS_cprogram']  = ['-Wl,-brtl']
+	v['cprogram_PATTERN']    = '%s'
+
+	# shared library
+	v['CFLAGS_cshlib']       = ['-fPIC']
+	v['LINKFLAGS_cshlib']    = ['-G', '-Wl,-brtl,-bexpfull']
+	v['cshlib_PATTERN']      = 'lib%s.so'
+
+	# static lib
+	v['LINKFLAGS_cstlib']    = []
+	v['cstlib_PATTERN']      = 'lib%s.a'
+
+def configure(conf):
+	conf.find_xlc()
+	conf.find_ar()
+	conf.xlc_common_flags()
+	conf.cc_load_tools()
+	conf.cc_add_flags()
+	conf.link_add_flags()
+
diff --git a/xpdeint/waf/waflib/Tools/xlcxx.py b/xpdeint/waf/waflib/Tools/xlcxx.py
new file mode 100644
index 0000000..75b8f9b
--- /dev/null
+++ b/xpdeint/waf/waflib/Tools/xlcxx.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+# Ralf Habacker, 2006 (rh)
+# Yinon Ehrlich, 2009
+# Michael Kuhn, 2009
+
+from waflib.Tools import ccroot, ar
+from waflib.Configure import conf
+
+ at conf
+def find_xlcxx(conf):
+	"""
+	Detect the Aix C++ compiler
+	"""
+	cxx = conf.find_program(['xlc++_r', 'xlc++'], var='CXX')
+	cxx = conf.cmd_to_list(cxx)
+	conf.get_xlc_version(cxx)
+	conf.env.CXX_NAME = 'xlc++'
+	conf.env.CXX      = cxx
+
+ at conf
+def xlcxx_common_flags(conf):
+	"""
+	Flags required for executing the Aix C++ compiler
+	"""
+	v = conf.env
+
+	v['CXX_SRC_F']           = []
+	v['CXX_TGT_F']           = ['-c', '-o']
+
+	# linker
+	if not v['LINK_CXX']: v['LINK_CXX'] = v['CXX']
+	v['CXXLNK_SRC_F']        = []
+	v['CXXLNK_TGT_F']        = ['-o']
+	v['CPPPATH_ST']          = '-I%s'
+	v['DEFINES_ST']          = '-D%s'
+
+	v['LIB_ST']              = '-l%s' # template for adding libs
+	v['LIBPATH_ST']          = '-L%s' # template for adding libpaths
+	v['STLIB_ST']            = '-l%s'
+	v['STLIBPATH_ST']        = '-L%s'
+	v['RPATH_ST']            = '-Wl,-rpath,%s'
+
+	v['SONAME_ST']           = []
+	v['SHLIB_MARKER']        = []
+	v['STLIB_MARKER']        = []
+
+	# program
+	v['LINKFLAGS_cxxprogram']= ['-Wl,-brtl']
+	v['cxxprogram_PATTERN']  = '%s'
+
+	# shared library
+	v['CXXFLAGS_cxxshlib']   = ['-fPIC']
+	v['LINKFLAGS_cxxshlib']  = ['-G', '-Wl,-brtl,-bexpfull']
+	v['cxxshlib_PATTERN']    = 'lib%s.so'
+
+	# static lib
+	v['LINKFLAGS_cxxstlib']  = []
+	v['cxxstlib_PATTERN']    = 'lib%s.a'
+
+def configure(conf):
+	conf.find_xlcxx()
+	conf.find_ar()
+	conf.xlcxx_common_flags()
+	conf.cxx_load_tools()
+	conf.cxx_add_flags()
+	conf.link_add_flags()
+
diff --git a/xpdeint/waf/waflib/Utils.py b/xpdeint/waf/waflib/Utils.py
new file mode 100644
index 0000000..7f4eb26
--- /dev/null
+++ b/xpdeint/waf/waflib/Utils.py
@@ -0,0 +1,601 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005-2010 (ita)
+
+"""
+Utilities and platform-specific fixes
+
+The portability fixes try to provide a consistent behavior of the Waf API
+through Python versions 2.3 to 3.X and across different platforms (win32, linux, etc)
+"""
+
+import os, sys, errno, traceback, inspect, re, shutil, datetime, gc
+try:
+	import subprocess
+except:
+	try:
+		import waflib.extras.subprocess as subprocess
+	except:
+		print("The subprocess module is missing (python2.3?):\n try calling 'waf update --files=subprocess'\n or add a copy of subprocess.py to the python libraries")
+
+try:
+	from collections import deque
+except ImportError:
+	class deque(list):
+		"""A deque for Python 2.3 which does not have one"""
+		def popleft(self):
+			return self.pop(0)
+try:
+	import _winreg as winreg
+except:
+	try:
+		import winreg
+	except:
+		winreg = None
+
+from waflib import Errors
+
+try:
+	from collections import UserDict
+except:
+	from UserDict import UserDict
+
+try:
+	from hashlib import md5
+except:
+	try:
+		from md5 import md5
+	except:
+		# never fail to enable fixes from another module
+		pass
+
+try:
+	import threading
+except:
+	class threading(object):
+		"""
+			A fake threading class for platforms lacking the threading module.
+			Use ``waf -j1`` on those platforms
+		"""
+		pass
+	class Lock(object):
+		"""Fake Lock class"""
+		def acquire(self):
+			pass
+		def release(self):
+			pass
+	threading.Lock = threading.Thread = Lock
+else:
+	run_old = threading.Thread.run
+	def run(*args, **kwargs):
+		try:
+			run_old(*args, **kwargs)
+		except (KeyboardInterrupt, SystemExit):
+			raise
+		except:
+			sys.excepthook(*sys.exc_info())
+	threading.Thread.run = run
+
+SIG_NIL = 'iluvcuteoverload'.encode()
+"""Arbitrary null value for a md5 hash. This value must be changed when the hash value is replaced (size)"""
+
+O644 = 420
+"""Constant representing the permissions for regular files (0644 raises a syntax error on python 3)"""
+
+O755 = 493
+"""Constant representing the permissions for executable files (0755 raises a syntax error on python 3)"""
+
+rot_chr = ['\\', '|', '/', '-']
+"List of characters to use when displaying the throbber (progress bar)"
+
+rot_idx = 0
+"Index of the current throbber character (progress bar)"
+
+try:
+	from collections import defaultdict
+except ImportError:
+	class defaultdict(dict):
+		"""
+		defaultdict was introduced in python 2.5, so we leave it for python 2.4 and 2.3
+		"""
+		def __init__(self, default_factory):
+			super(defaultdict, self).__init__()
+			self.default_factory = default_factory
+		def __getitem__(self, key):
+			try:
+				return super(defaultdict, self).__getitem__(key)
+			except KeyError:
+				value = self.default_factory()
+				self[key] = value
+				return value
+
+is_win32 = sys.platform in ('win32', 'cli')
+
+# we should have put this in the Logs.py file instead :-/
+indicator = '\x1b[K%s%s%s\r'
+if is_win32 and 'NOCOLOR' in os.environ:
+	indicator = '%s%s%s\r'
+
+def readf(fname, m='r'):
+	"""
+	Read an entire file into a string, in practice the wrapper
+	node.read(..) should be used instead of this method::
+
+		def build(ctx):
+			from waflib import Utils
+			txt = Utils.readf(self.path.find_node('wscript').abspath())
+			txt = ctx.path.find_node('wscript').read()
+
+	:type  fname: string
+	:param fname: Path to file
+	:type  m: string
+	:param m: Open mode
+	:rtype: string
+	:return: Content of the file
+	"""
+	f = open(fname, m)
+	try:
+		txt = f.read()
+	finally:
+		f.close()
+	return txt
+
+def h_file(filename):
+	"""
+	Compute a hash value for a file by using md5. This method may be replaced by
+	a faster version if necessary. The following uses the file size and the timestamp value::
+
+		import stat
+		from waflib import Utils
+		def h_file(filename):
+			st = os.stat(filename)
+			if stat.S_ISDIR(st[stat.ST_MODE]): raise IOError('not a file')
+			m = Utils.md5()
+			m.update(str(st.st_mtime))
+			m.update(str(st.st_size))
+			m.update(filename)
+			return m.digest()
+		Utils.h_file = h_file
+
+	:type filename: string
+	:param filename: path to the file to hash
+	:return: hash of the file contents
+	"""
+	f = open(filename, 'rb')
+	m = md5()
+	try:
+		while filename:
+			filename = f.read(100000)
+			m.update(filename)
+	finally:
+		f.close()
+	return m.digest()
+
+try:
+	x = ''.encode('hex')
+except:
+	import binascii
+	def to_hex(s):
+		ret = binascii.hexlify(s)
+		if not isinstance(ret, str):
+			ret = ret.decode('utf-8')
+		return ret
+else:
+	def to_hex(s):
+		return s.encode('hex')
+
+to_hex.__doc__ = """
+Return the hexadecimal representation of a string
+
+:param s: string to convert
+:type s: string
+"""
+
+listdir = os.listdir
+if is_win32:
+	def listdir_win32(s):
+		"""
+		List the contents of a folder in a portable manner.
+
+		:type s: string
+		:param s: a string, which can be empty on Windows for listing the drive letters
+		"""
+		if not s:
+			try:
+				import ctypes
+			except:
+				# there is nothing much we can do
+				return [x + ':\\' for x in list('ABCDEFGHIJKLMNOPQRSTUVWXYZ')]
+			else:
+				dlen = 4 # length of "?:\\x00"
+				maxdrives = 26
+				buf = ctypes.create_string_buffer(maxdrives * dlen)
+				ndrives = ctypes.windll.kernel32.GetLogicalDriveStringsA(maxdrives, ctypes.byref(buf))
+				return [ buf.raw[4*i:4*i+3].decode('ascii') for i in range(int(ndrives/dlen)) ]
+
+		if len(s) == 2 and s[1] == ":":
+			s += os.sep
+
+		if not os.path.isdir(s):
+			e = OSError()
+			e.errno = errno.ENOENT
+			raise e
+		return os.listdir(s)
+	listdir = listdir_win32
+
+def num2ver(ver):
+	"""
+	Convert a string, tuple or version number into an integer. The number is supposed to have at most 4 digits::
+
+		from waflib.Utils import num2ver
+		num2ver('1.3.2') == num2ver((1,3,2)) == num2ver((1,3,2,0))
+
+	:type ver: string or tuple of numbers
+	:param ver: a version number
+	"""
+	if isinstance(ver, str):
+		ver = tuple(ver.split('.'))
+	if isinstance(ver, tuple):
+		ret = 0
+		for i in range(4):
+			if i < len(ver):
+				ret += 256**(3 - i) * int(ver[i])
+		return ret
+	return ver
+
+def ex_stack():
+	"""
+	Extract the stack to display exceptions
+
+	:return: a string represening the last exception
+	"""
+	exc_type, exc_value, tb = sys.exc_info()
+	exc_lines = traceback.format_exception(exc_type, exc_value, tb)
+	return ''.join(exc_lines)
+
+def to_list(sth):
+	"""
+	Convert a string argument to a list by splitting on spaces, and pass
+	through a list argument unchanged::
+
+		from waflib.Utils import to_list
+		lst = to_list("a b c d")
+
+	:param sth: List or a string of items separated by spaces
+	:rtype: list
+	:return: Argument converted to list
+
+	"""
+	if isinstance(sth, str):
+		return sth.split()
+	else:
+		return sth
+
+re_nl = re.compile('\r*\n', re.M)
+def str_to_dict(txt):
+	"""
+	Parse a string with key = value pairs into a dictionary::
+
+		from waflib import Utils
+		x = Utils.str_to_dict('''
+			a = 1
+			b = test
+		''')
+
+	:type  s: string
+	:param s: String to parse
+	:rtype: dict
+	:return: Dictionary containing parsed key-value pairs
+	"""
+	tbl = {}
+
+	lines = re_nl.split(txt)
+	for x in lines:
+		x = x.strip()
+		if not x or x.startswith('#') or x.find('=') < 0:
+			continue
+		tmp = x.split('=')
+		tbl[tmp[0].strip()] = '='.join(tmp[1:]).strip()
+	return tbl
+
+def split_path(path):
+	return path.split('/')
+
+def split_path_cygwin(path):
+	if path.startswith('//'):
+		ret = path.split('/')[2:]
+		ret[0] = '/' + ret[0]
+		return ret
+	return path.split('/')
+
+re_sp = re.compile('[/\\\\]')
+def split_path_win32(path):
+	if path.startswith('\\\\'):
+		ret = re.split(re_sp, path)[2:]
+		ret[0] = '\\' + ret[0]
+		return ret
+	return re.split(re_sp, path)
+
+if sys.platform == 'cygwin':
+	split_path = split_path_cygwin
+elif is_win32:
+	split_path = split_path_win32
+
+split_path.__doc__ = """
+Split a path by / or \\. This function is not like os.path.split
+
+:type  path: string
+:param path: path to split
+:return:     list of strings
+"""
+
+def check_dir(path):
+	"""
+	Ensure that a directory exists (similar to ``mkdir -p``).
+
+	:type  dir: string
+	:param dir: Path to directory
+	"""
+	if not os.path.isdir(path):
+		try:
+			os.makedirs(path)
+		except OSError as e:
+			if not os.path.isdir(path):
+				raise Errors.WafError('Cannot create the folder %r' % path, ex=e)
+
+def def_attrs(cls, **kw):
+	"""
+	Set default attributes on a class instance
+
+	:type cls: class
+	:param cls: the class to update the given attributes in.
+	:type kw: dict
+	:param kw: dictionary of attributes names and values.
+	"""
+	for k, v in kw.items():
+		if not hasattr(cls, k):
+			setattr(cls, k, v)
+
+def quote_define_name(s):
+	"""
+	Convert a string to an identifier suitable for C defines.
+
+	:type  s: string
+	:param s: String to convert
+	:rtype: string
+	:return: Identifier suitable for C defines
+	"""
+	fu = re.compile("[^a-zA-Z0-9]").sub("_", s)
+	fu = fu.upper()
+	return fu
+
+def h_list(lst):
+	"""
+	Hash lists. For tuples, using hash(tup) is much more efficient
+
+	:param lst: list to hash
+	:type lst: list of strings
+	:return: hash of the list
+	"""
+	m = md5()
+	m.update(str(lst).encode())
+	return m.digest()
+
+def h_fun(fun):
+	"""
+	Hash functions
+
+	:param fun: function to hash
+	:type  fun: function
+	:return: hash of the function
+	"""
+	try:
+		return fun.code
+	except AttributeError:
+		try:
+			h = inspect.getsource(fun)
+		except IOError:
+			h = "nocode"
+		try:
+			fun.code = h
+		except AttributeError:
+			pass
+		return h
+
+reg_subst = re.compile(r"(\\\\)|(\$\$)|\$\{([^}]+)\}")
+def subst_vars(expr, params):
+	"""
+	Replace ${VAR} with the value of VAR taken from a dict or a config set::
+
+		from waflib import Utils
+		s = Utils.subst_vars('${PREFIX}/bin', env)
+
+	:type  expr: string
+	:param expr: String to perform substitution on
+	:param params: Dictionary or config set to look up variable values.
+	"""
+	def repl_var(m):
+		if m.group(1):
+			return '\\'
+		if m.group(2):
+			return '$'
+		try:
+			# ConfigSet instances may contain lists
+			return params.get_flat(m.group(3))
+		except AttributeError:
+			return params[m.group(3)]
+	return reg_subst.sub(repl_var, expr)
+
+def destos_to_binfmt(key):
+	"""
+	Return the binary format based on the unversioned platform name.
+
+	:param key: platform name
+	:type  key: string
+	:return: string representing the binary format
+	"""
+	if key == 'darwin':
+		return 'mac-o'
+	elif key in ('win32', 'cygwin', 'uwin', 'msys'):
+		return 'pe'
+	return 'elf'
+
+def unversioned_sys_platform():
+	"""
+	Return the unversioned platform name.
+	Some Python platform names contain versions, that depend on
+	the build environment, e.g. linux2, freebsd6, etc.
+	This returns the name without the version number. Exceptions are
+	os2 and win32, which are returned verbatim.
+
+	:rtype: string
+	:return: Unversioned platform name
+	"""
+	s = sys.platform
+	if s == 'java':
+		# The real OS is hidden under the JVM.
+		from java.lang import System
+		s = System.getProperty('os.name')
+		# see http://lopica.sourceforge.net/os.html for a list of possible values
+		if s == 'Mac OS X':
+			return 'darwin'
+		elif s.startswith('Windows '):
+			return 'win32'
+		elif s == 'OS/2':
+			return 'os2'
+		elif s == 'HP-UX':
+			return 'hpux'
+		elif s in ('SunOS', 'Solaris'):
+			return 'sunos'
+		else: s = s.lower()
+
+	if s == 'powerpc':
+		s = 'darwin'
+	if s == 'win32' or s.endswith('os2') and s != 'sunos2': return s
+	return re.split('\d+$', s)[0]
+
+def nada(*k, **kw):
+	"""
+	A function that does nothing
+
+	:return: None
+	"""
+	pass
+
+class Timer(object):
+	"""
+	Simple object for timing the execution of commands.
+	Its string representation is the current time::
+
+		from waflib.Utils import Timer
+		timer = Timer()
+		a_few_operations()
+		s = str(timer)
+	"""
+	def __init__(self):
+		self.start_time = datetime.datetime.utcnow()
+
+	def __str__(self):
+		delta = datetime.datetime.utcnow() - self.start_time
+		days = int(delta.days)
+		hours = delta.seconds // 3600
+		minutes = (delta.seconds - hours * 3600) // 60
+		seconds = delta.seconds - hours * 3600 - minutes * 60 + float(delta.microseconds) / 1000 / 1000
+		result = ''
+		if days:
+			result += '%dd' % days
+		if days or hours:
+			result += '%dh' % hours
+		if days or hours or minutes:
+			result += '%dm' % minutes
+		return '%s%.3fs' % (result, seconds)
+
+if is_win32:
+	old = shutil.copy2
+	def copy2(src, dst):
+		"""
+		shutil.copy2 does not copy the file attributes on windows, so we
+		hack into the shutil module to fix the problem
+		"""
+		old(src, dst)
+		shutil.copystat(src, dst)
+	setattr(shutil, 'copy2', copy2)
+
+if os.name == 'java':
+	# Jython cannot disable the gc but they can enable it ... wtf?
+	try:
+		gc.disable()
+		gc.enable()
+	except NotImplementedError:
+		gc.disable = gc.enable
+
+def read_la_file(path):
+	"""
+	Read property files, used by msvc.py
+
+	:param path: file to read
+	:type path: string
+	"""
+	sp = re.compile(r'^([^=]+)=\'(.*)\'$')
+	dc = {}
+	for line in readf(path).splitlines():
+		try:
+			_, left, right, _ = sp.split(line.strip())
+			dc[left] = right
+		except ValueError:
+			pass
+	return dc
+
+def nogc(fun):
+	"""
+	Decorator: let a function disable the garbage collector during its execution.
+	It is used in the build context when storing/loading the build cache file (pickle)
+
+	:param fun: function to execute
+	:type fun: function
+	:return: the return value of the function executed
+	"""
+	def f(*k, **kw):
+		try:
+			gc.disable()
+			ret = fun(*k, **kw)
+		finally:
+			gc.enable()
+		return ret
+	f.__doc__ = fun.__doc__
+	return f
+
+def run_once(fun):
+	"""
+	Decorator: let a function cache its results, use like this::
+
+		@run_once
+		def foo(k):
+			return 345*2343
+
+	:param fun: function to execute
+	:type fun: function
+	:return: the return value of the function executed
+	"""
+	cache = {}
+	def wrap(k):
+		try:
+			return cache[k]
+		except KeyError:
+			ret = fun(k)
+			cache[k] = ret
+			return ret
+	wrap.__cache__ = cache
+	return wrap
+
+def get_registry_app_path(key, filename):
+	if not winreg:
+		return None
+	try:
+		result = winreg.QueryValue(key, "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s.exe" % filename[0])
+	except WindowsError:
+		pass
+	else:
+		if os.path.isfile(result):
+			return result
+
diff --git a/xpdeint/waf/waflib/Utils.pyc b/xpdeint/waf/waflib/Utils.pyc
new file mode 100644
index 0000000..0c6c9ad
Binary files /dev/null and b/xpdeint/waf/waflib/Utils.pyc differ
diff --git a/xpdeint/waf/waflib/__init__.py b/xpdeint/waf/waflib/__init__.py
new file mode 100644
index 0000000..c8a3c34
--- /dev/null
+++ b/xpdeint/waf/waflib/__init__.py
@@ -0,0 +1,3 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005-2010 (ita)
diff --git a/xpdeint/waf/waflib/__init__.pyc b/xpdeint/waf/waflib/__init__.pyc
new file mode 100644
index 0000000..a86c047
Binary files /dev/null and b/xpdeint/waf/waflib/__init__.pyc differ
diff --git a/xpdeint/waf/waflib/ansiterm.py b/xpdeint/waf/waflib/ansiterm.py
new file mode 100644
index 0000000..1663ffb
--- /dev/null
+++ b/xpdeint/waf/waflib/ansiterm.py
@@ -0,0 +1,241 @@
+import sys, os
+try:
+	if not (sys.stderr.isatty() and sys.stdout.isatty()):
+		raise ValueError('not a tty')
+
+	from ctypes import *
+
+	class COORD(Structure):
+		_fields_ = [("X", c_short), ("Y", c_short)]
+
+	class SMALL_RECT(Structure):
+		_fields_ = [("Left", c_short), ("Top", c_short), ("Right", c_short), ("Bottom", c_short)]
+
+	class CONSOLE_SCREEN_BUFFER_INFO(Structure):
+		_fields_ = [("Size", COORD), ("CursorPosition", COORD), ("Attributes", c_short), ("Window", SMALL_RECT), ("MaximumWindowSize", COORD)]
+
+	class CONSOLE_CURSOR_INFO(Structure):
+		_fields_ = [('dwSize',c_ulong), ('bVisible', c_int)]
+
+	sbinfo = CONSOLE_SCREEN_BUFFER_INFO()
+	csinfo = CONSOLE_CURSOR_INFO()
+	hconsole = windll.kernel32.GetStdHandle(-11)
+	windll.kernel32.GetConsoleScreenBufferInfo(hconsole, byref(sbinfo))
+	if sbinfo.Size.X < 9 or sbinfo.Size.Y < 9: raise ValueError('small console')
+	windll.kernel32.GetConsoleCursorInfo(hconsole, byref(csinfo))
+except Exception:
+	pass
+else:
+	import re, threading
+
+	try:
+		_type = unicode
+	except:
+		_type = str
+
+	to_int = lambda number, default: number and int(number) or default
+	wlock = threading.Lock()
+
+	STD_OUTPUT_HANDLE = -11
+	STD_ERROR_HANDLE = -12
+
+	class AnsiTerm(object):
+		"""
+		emulate a vt100 terminal in cmd.exe
+		"""
+		def __init__(self):
+			self.encoding = sys.stdout.encoding
+			self.hconsole = windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
+			self.cursor_history = []
+			self.orig_sbinfo = CONSOLE_SCREEN_BUFFER_INFO()
+			self.orig_csinfo = CONSOLE_CURSOR_INFO()
+			windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole, byref(self.orig_sbinfo))
+			windll.kernel32.GetConsoleCursorInfo(hconsole, byref(self.orig_csinfo))
+
+		def screen_buffer_info(self):
+			sbinfo = CONSOLE_SCREEN_BUFFER_INFO()
+			windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole, byref(sbinfo))
+			return sbinfo
+
+		def clear_line(self, param):
+			mode = param and int(param) or 0
+			sbinfo = self.screen_buffer_info()
+			if mode == 1: # Clear from begining of line to cursor position
+				line_start = COORD(0, sbinfo.CursorPosition.Y)
+				line_length = sbinfo.Size.X
+			elif mode == 2: # Clear entire line
+				line_start = COORD(sbinfo.CursorPosition.X, sbinfo.CursorPosition.Y)
+				line_length = sbinfo.Size.X - sbinfo.CursorPosition.X
+			else: # Clear from cursor position to end of line
+				line_start = sbinfo.CursorPosition
+				line_length = sbinfo.Size.X - sbinfo.CursorPosition.X
+			chars_written = c_int()
+			windll.kernel32.FillConsoleOutputCharacterA(self.hconsole, c_wchar(' '), line_length, line_start, byref(chars_written))
+			windll.kernel32.FillConsoleOutputAttribute(self.hconsole, sbinfo.Attributes, line_length, line_start, byref(chars_written))
+
+		def clear_screen(self, param):
+			mode = to_int(param, 0)
+			sbinfo = self.screen_buffer_info()
+			if mode == 1: # Clear from begining of screen to cursor position
+				clear_start = COORD(0, 0)
+				clear_length = sbinfo.CursorPosition.X * sbinfo.CursorPosition.Y
+			elif mode == 2: # Clear entire screen and return cursor to home
+				clear_start = COORD(0, 0)
+				clear_length = sbinfo.Size.X * sbinfo.Size.Y
+				windll.kernel32.SetConsoleCursorPosition(self.hconsole, clear_start)
+			else: # Clear from cursor position to end of screen
+				clear_start = sbinfo.CursorPosition
+				clear_length = ((sbinfo.Size.X - sbinfo.CursorPosition.X) + sbinfo.Size.X * (sbinfo.Size.Y - sbinfo.CursorPosition.Y))
+			chars_written = c_int()
+			windll.kernel32.FillConsoleOutputCharacterA(self.hconsole, c_wchar(' '), clear_length, clear_start, byref(chars_written))
+			windll.kernel32.FillConsoleOutputAttribute(self.hconsole, sbinfo.Attributes, clear_length, clear_start, byref(chars_written))
+
+		def push_cursor(self, param):
+			sbinfo = self.screen_buffer_info()
+			self.cursor_history.append(sbinfo.CursorPosition)
+
+		def pop_cursor(self, param):
+			if self.cursor_history:
+				old_pos = self.cursor_history.pop()
+				windll.kernel32.SetConsoleCursorPosition(self.hconsole, old_pos)
+
+		def set_cursor(self, param):
+			y, sep, x = param.partition(';')
+			x = to_int(x, 1) - 1
+			y = to_int(y, 1) - 1
+			sbinfo = self.screen_buffer_info()
+			new_pos = COORD(
+				min(max(0, x), sbinfo.Size.X),
+				min(max(0, y), sbinfo.Size.Y)
+			)
+			windll.kernel32.SetConsoleCursorPosition(self.hconsole, new_pos)
+
+		def set_column(self, param):
+			x = to_int(param, 1) - 1
+			sbinfo = self.screen_buffer_info()
+			new_pos = COORD(
+				min(max(0, x), sbinfo.Size.X),
+				sbinfo.CursorPosition.Y
+			)
+			windll.kernel32.SetConsoleCursorPosition(self.hconsole, new_pos)
+
+		def move_cursor(self, x_offset=0, y_offset=0):
+			sbinfo = self.screen_buffer_info()
+			new_pos = COORD(
+				min(max(0, sbinfo.CursorPosition.X + x_offset), sbinfo.Size.X),
+				min(max(0, sbinfo.CursorPosition.Y + y_offset), sbinfo.Size.Y)
+			)
+			windll.kernel32.SetConsoleCursorPosition(self.hconsole, new_pos)
+
+		def move_up(self, param):
+			self.move_cursor(y_offset = -to_int(param, 1))
+
+		def move_down(self, param):
+			self.move_cursor(y_offset = to_int(param, 1))
+
+		def move_left(self, param):
+			self.move_cursor(x_offset = -to_int(param, 1))
+
+		def move_right(self, param):
+			self.move_cursor(x_offset = to_int(param, 1))
+
+		def next_line(self, param):
+			sbinfo = self.screen_buffer_info()
+			self.move_cursor(
+				x_offset = -sbinfo.CursorPosition.X,
+				y_offset = to_int(param, 1)
+			)
+
+		def prev_line(self, param):
+			sbinfo = self.screen_buffer_info()
+			self.move_cursor(
+				x_offset = -sbinfo.CursorPosition.X,
+				y_offset = -to_int(param, 1)
+			)
+
+		def rgb2bgr(self, c):
+			return ((c&1) << 2) | (c&2) | ((c&4)>>2)
+
+		def set_color(self, param):
+			cols = param.split(';')
+			sbinfo = CONSOLE_SCREEN_BUFFER_INFO()
+			windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole, byref(sbinfo))
+			attr = sbinfo.Attributes
+			for c in cols:
+				c = to_int(c, 0)
+				if c in range(30,38): # fgcolor
+					attr = (attr & 0xfff0) | self.rgb2bgr(c-30)
+				elif c in range(40,48): # bgcolor
+					attr = (attr & 0xff0f) | (self.rgb2bgr(c-40) << 4)
+				elif c == 0: # reset
+					attr = self.orig_sbinfo.Attributes
+				elif c == 1: # strong
+					attr |= 0x08
+				elif c == 4: # blink not available -> bg intensity
+					attr |= 0x80
+				elif c == 7: # negative
+					attr = (attr & 0xff88) | ((attr & 0x70) >> 4) | ((attr & 0x07) << 4)
+			windll.kernel32.SetConsoleTextAttribute(self.hconsole, attr)
+
+		def show_cursor(self,param):
+			csinfo.bVisible = 1
+			windll.kernel32.SetConsoleCursorInfo(self.hconsole, byref(csinfo))
+
+		def hide_cursor(self,param):
+			csinfo.bVisible = 0
+			windll.kernel32.SetConsoleCursorInfo(self.hconsole, byref(csinfo))
+
+		ansi_command_table = {
+			'A': move_up,
+			'B': move_down,
+			'C': move_right,
+			'D': move_left,
+			'E': next_line,
+			'F': prev_line,
+			'G': set_column,
+			'H': set_cursor,
+			'f': set_cursor,
+			'J': clear_screen,
+			'K': clear_line,
+			'h': show_cursor,
+			'l': hide_cursor,
+			'm': set_color,
+			's': push_cursor,
+			'u': pop_cursor,
+		}
+		# Match either the escape sequence or text not containing escape sequence
+		ansi_tokens = re.compile('(?:\x1b\[([0-9?;]*)([a-zA-Z])|([^\x1b]+))')
+		def write(self, text):
+			try:
+				wlock.acquire()
+				for param, cmd, txt in self.ansi_tokens.findall(text):
+					if cmd:
+						cmd_func = self.ansi_command_table.get(cmd)
+						if cmd_func:
+							cmd_func(self, param)
+					else:
+						self.writeconsole(txt)
+			finally:
+				wlock.release()
+
+		def writeconsole(self, txt):
+			chars_written = c_int()
+			writeconsole = windll.kernel32.WriteConsoleA
+			if isinstance(txt, _type):
+				writeconsole = windll.kernel32.WriteConsoleW
+
+			TINY_STEP = 3000
+			for x in range(0, len(txt), TINY_STEP):
+			    # According MSDN, size should NOT exceed 64 kb (issue #746)
+			    tiny = txt[x : x + TINY_STEP]
+			    writeconsole(self.hconsole, tiny, len(tiny), byref(chars_written), None)
+
+		def flush(self):
+			pass
+
+		def isatty(self):
+			return True
+
+	sys.stderr = sys.stdout = AnsiTerm()
+	os.environ['TERM'] = 'vt100'
+
diff --git a/xpdeint/waf/waflib/ansiterm.pyc b/xpdeint/waf/waflib/ansiterm.pyc
new file mode 100644
index 0000000..e016c68
Binary files /dev/null and b/xpdeint/waf/waflib/ansiterm.pyc differ
diff --git a/xpdeint/waf/waflib/extras/__init__.py b/xpdeint/waf/waflib/extras/__init__.py
new file mode 100644
index 0000000..c8a3c34
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/__init__.py
@@ -0,0 +1,3 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005-2010 (ita)
diff --git a/xpdeint/waf/waflib/extras/__init__.pyc b/xpdeint/waf/waflib/extras/__init__.pyc
new file mode 100644
index 0000000..3e1f153
Binary files /dev/null and b/xpdeint/waf/waflib/extras/__init__.pyc differ
diff --git a/xpdeint/waf/waflib/extras/add_objects.py b/xpdeint/waf/waflib/extras/add_objects.py
new file mode 100644
index 0000000..e383a1c
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/add_objects.py
@@ -0,0 +1,7 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2011 (ita)
+
+from waflib import Logs
+Logs.warn('This tool has been merged to the main library, remove the references to "add_objects"')
+
diff --git a/xpdeint/waf/waflib/extras/batched_cc.py b/xpdeint/waf/waflib/extras/batched_cc.py
new file mode 100644
index 0000000..39ba6e3
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/batched_cc.py
@@ -0,0 +1,161 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+
+"""
+Batched builds - compile faster
+instead of compiling object files one by one, c/c++ compilers are often able to compile at once:
+cc -c ../file1.c ../file2.c ../file3.c
+
+Files are output on the directory where the compiler is called, and dependencies are more difficult
+to track (do not run the command on all source files if only one file changes)
+
+As such, we do as if the files were compiled one by one, but no command is actually run:
+replace each cc/cpp Task by a TaskSlave. A new task called TaskMaster collects the
+signatures from each slave and finds out the command-line to run.
+
+It is only necessary to import this module in the configuration (no other change required)
+"""
+
+import os
+from waflib import TaskGen, Task, Build, Logs
+from waflib.TaskGen import extension, feature, before_method, after_method
+
+MAX_BATCH = 50
+
+c_str = '${CC} ${CFLAGS} ${CPPFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} -c ${SRCLST}'
+#c_str = '${CC} ${CCFLAGS} ${CPPFLAGS} ${_CCINCFLAGS} ${_CCDEFFLAGS} -c ${SRCLST}'
+c_fun, _ = Task.compile_fun_noshell(c_str)
+
+cxx_str = '${CXX} ${CXXFLAGS} ${CPPFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} -c ${SRCLST}'
+#cxx_str = '${CXX} ${CXXFLAGS} ${CPPFLAGS} ${_CXXINCFLAGS} ${_CXXDEFFLAGS} -c ${SRCLST}'
+cxx_fun, _ = Task.compile_fun_noshell(cxx_str)
+
+count = 70000
+class batch_task(Task.Task):
+	color = 'RED'
+
+	after = ['c', 'cxx']
+	before = ['cprogram', 'cshlib', 'cstlib', 'cxxprogram', 'cxxshlib', 'cxxstlib']
+
+	def __str__(self):
+		return '(batch compilation for %d slaves)\n' % len(self.slaves)
+
+	def __init__(self, *k, **kw):
+		Task.Task.__init__(self, *k, **kw)
+		self.slaves = []
+		self.inputs = []
+		self.hasrun = 0
+
+		global count
+		count += 1
+		self.idx = count
+
+	def add_slave(self, slave):
+		self.slaves.append(slave)
+		self.set_run_after(slave)
+
+	def runnable_status(self):
+		for t in self.run_after:
+			if not t.hasrun:
+				return Task.ASK_LATER
+
+		for t in self.slaves:
+			#if t.executed:
+			if t.hasrun != Task.SKIPPED:
+				return Task.RUN_ME
+
+		return Task.SKIP_ME
+
+	def run(self):
+		outputs = []
+		self.outputs = []
+
+		srclst = []
+		slaves = []
+		for t in self.slaves:
+			if t.hasrun != Task.SKIPPED:
+				slaves.append(t)
+				srclst.append(t.inputs[0].abspath())
+
+		self.env.SRCLST = srclst
+		self.cwd = slaves[0].inputs[0].parent.get_bld().abspath()
+
+		if self.slaves[0].__class__.__name__ == 'c':
+			ret = c_fun(self)
+		else:
+			ret = cxx_fun(self)
+
+		if ret:
+			return ret
+
+		for t in slaves:
+			t.old_post_run()
+
+from waflib.Tools import c, cxx
+
+def hook(name):
+	def n_hook(self, node):
+		task = self.create_task(name, node, node.change_ext('.o'))
+		try:
+			self.compiled_tasks.append(task)
+		except AttributeError:
+			self.compiled_tasks = [task]
+
+		if not getattr(self, 'masters', None):
+			self.masters = {}
+			self.allmasters = []
+
+		if not node.parent in self.masters:
+			m = self.masters[node.parent] = self.master = self.create_task('batch')
+			self.allmasters.append(m)
+		else:
+			m = self.masters[node.parent]
+			if len(m.slaves) > MAX_BATCH:
+				m = self.masters[node.parent] = self.master = self.create_task('batch')
+				self.allmasters.append(m)
+
+		m.add_slave(task)
+		return task
+	return n_hook
+
+extension('.c')(hook('c'))
+extension('.cpp','.cc','.cxx','.C','.c++')(hook('cxx'))
+
+ at feature('cprogram', 'cshlib', 'cstaticlib', 'cxxprogram', 'cxxshlib', 'cxxstlib')
+ at after_method('apply_link')
+def link_after_masters(self):
+	if getattr(self, 'allmasters', None):
+		for m in self.allmasters:
+			self.link_task.set_run_after(m)
+
+# Modify the c and cxx task classes - in theory it would be better to
+# create subclasses and to re-map the c/c++ extensions
+#
+for x in ['c', 'cxx']:
+	t = Task.classes[x]
+	def run(self):
+		pass
+
+	def post_run(self):
+		#self.executed=1
+		pass
+
+	def can_retrieve_cache(self):
+		if self.old_can_retrieve_cache():
+			for m in self.generator.allmasters:
+				try:
+					m.slaves.remove(self)
+				except ValueError:
+					pass #this task wasn't included in that master
+			return 1
+		else:
+			return None
+
+	setattr(t, 'oldrun', t.__dict__['run'])
+	setattr(t, 'run', run)
+	setattr(t, 'old_post_run', t.post_run)
+	setattr(t, 'post_run', post_run)
+	setattr(t, 'old_can_retrieve_cache', t.can_retrieve_cache)
+	setattr(t, 'can_retrieve_cache', can_retrieve_cache)
+
diff --git a/xpdeint/waf/waflib/extras/biber.py b/xpdeint/waf/waflib/extras/biber.py
new file mode 100644
index 0000000..df42416
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/biber.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2011 (ita)
+
+"""
+Latex processing using "biber"
+"""
+
+import os
+from waflib import Task
+from waflib.Logs import warn
+
+from waflib.Tools import tex as texmodule
+
+class tex(texmodule.tex):
+	biber_fun, _ = Task.compile_fun('${BIBER} ${BIBERFLAGS} ${SRCFILE}',shell=False)
+	biber_fun.__doc__ = """
+	Execute the program **biber**
+	"""
+
+	def bibfile(self):
+		return None
+
+	def bibunits(self):
+		self.env.env = {}
+		self.env.env.update(os.environ)
+		self.env.env.update({'BIBINPUTS': self.TEXINPUTS, 'BSTINPUTS': self.TEXINPUTS})
+		self.env.SRCFILE = self.aux_node.name[:-4]
+
+		if not self.env['PROMPT_LATEX']:
+			self.env.append_unique('BIBERFLAGS', '--quiet')
+
+		path = self.aux_node.abspath()[:-4] + '.bcf'
+		if os.path.isfile(path):
+			warn('calling biber')
+			self.check_status('error when calling biber, check %s.blg for errors' % (self.env.SRCFILE), self.biber_fun())
+		else:
+			super(tex, self).bibfile()
+			super(tex, self).bibunits()
+
+class latex(tex):
+	texfun, vars = Task.compile_fun('${LATEX} ${LATEXFLAGS} ${SRCFILE}', shell=False)
+class pdflatex(tex):
+	texfun, vars =  Task.compile_fun('${PDFLATEX} ${PDFLATEXFLAGS} ${SRCFILE}', shell=False)
+class xelatex(tex):
+	texfun, vars = Task.compile_fun('${XELATEX} ${XELATEXFLAGS} ${SRCFILE}', shell=False)
+
+def configure(self):
+	"""
+	Almost the same as in tex.py, but try to detect 'biber'
+	"""
+	v = self.env
+	for p in ' biber tex latex pdflatex xelatex bibtex dvips dvipdf ps2pdf makeindex pdf2ps'.split():
+		try:
+			self.find_program(p, var=p.upper())
+		except self.errors.ConfigurationError:
+			pass
+	v['DVIPSFLAGS'] = '-Ppdf'
+
diff --git a/xpdeint/waf/waflib/extras/bjam.py b/xpdeint/waf/waflib/extras/bjam.py
new file mode 100644
index 0000000..2666263
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/bjam.py
@@ -0,0 +1,131 @@
+#! /usr/bin/env python
+# per rosengren 2011
+
+from waflib.Logs import error,warn,info,debug
+from waflib.TaskGen import feature, after_method
+from waflib.Task import Task, always_run
+from os import sep, readlink
+from os.path import abspath
+
+def options(opt):
+	grp = opt.add_option_group('Bjam Options')
+	grp.add_option('--bjam_src', default=None, help='You can find it in <boost root>/tools/jam/src')
+	grp.add_option('--bjam_uname', default='linuxx86_64', help='bjam is built in <src>/bin.<uname>/bjam')
+	grp.add_option('--bjam_config', default=None)
+	grp.add_option('--bjam_toolset', default=None)
+
+def configure(cnf):
+	if not cnf.env.BJAM_SRC:
+		cnf.env.BJAM_SRC = cnf.options.bjam_src
+	if not cnf.env.BJAM_UNAME:
+		cnf.env.BJAM_UNAME = cnf.options.bjam_uname
+	try:
+		cnf.find_program('bjam', path_list=[
+			cnf.env.BJAM_SRC + sep + 'bin.' + cnf.env.BJAM_UNAME
+		])
+	except Exception as e:
+		cnf.env.BJAM = None
+	if not cnf.env.BJAM_CONFIG:
+		cnf.env.BJAM_CONFIG = cnf.options.bjam_config
+	if not cnf.env.BJAM_TOOLSET:
+		cnf.env.BJAM_TOOLSET = cnf.options.bjam_toolset
+
+ at feature('bjam')
+ at after_method('process_rule')
+def process_bjam(self):
+	if not self.bld.env.BJAM:
+		self.create_task('bjam_creator')
+	self.create_task('bjam_build')
+	self.create_task('bjam_installer')
+	if getattr(self, 'always', False):
+		always_run(bjam_creator)
+		always_run(bjam_build)
+	always_run(bjam_installer)
+
+class bjam_creator(Task):
+	ext_out = 'bjam_exe'
+	vars=['BJAM_SRC', 'BJAM_UNAME']
+	def run(self):
+		env = self.env
+		gen = self.generator
+		path = gen.path
+		bld = gen.bld
+		bjam = gen.bld.root.find_dir(env.BJAM_SRC)
+		if not bjam:
+			error('Can not find bjam source')
+			return -1
+		bjam_exe_relpath = 'bin.' + env.BJAM_UNAME + '/bjam'
+		bjam_exe = bjam.find_resource(bjam_exe_relpath)
+		if bjam_exe:
+			env.BJAM = bjam_exe.srcpath()
+			return 0
+		bjam_cmd = ['./build.sh']
+		debug('runner: ' + bjam.srcpath() + '> ' + str(bjam_cmd))
+		result = self.exec_command(bjam_cmd, cwd=bjam.srcpath())
+		if not result == 0:
+			error('bjam failed')
+			return -1
+		bjam_exe = bjam.find_resource(bjam_exe_relpath)
+		if bjam_exe:
+			env.BJAM = bjam_exe.srcpath()
+			return 0
+		error('bjam failed')
+		return -1
+
+class bjam_build(Task):
+	ext_in = 'bjam_exe'
+	ext_out = 'install'
+	vars = ['BJAM_TOOLSET']
+	def run(self):
+		env = self.env
+		gen = self.generator
+		path = gen.path
+		bld = gen.bld
+		if hasattr(gen, 'root'):
+			build_root = path.find_node(gen.root)
+		else:
+			build_root = path
+		jam = bld.srcnode.find_resource(env.BJAM_CONFIG)
+		if jam:
+			debug('bjam: Using jam configuration from ' + jam.srcpath())
+			jam_rel = jam.relpath_gen(build_root)
+		else:
+			warn('No build configuration in build_config/user-config.jam. Using default')
+			jam_rel = None
+		bjam_exe = bld.srcnode.find_node(env.BJAM)
+		if not bjam_exe:
+			error('env.BJAM is not set')
+			return -1
+		bjam_exe_rel = bjam_exe.relpath_gen(build_root)
+		cmd = ([bjam_exe_rel] +
+			(['--user-config=' + jam_rel] if jam_rel else []) +
+			['--stagedir=' + path.get_bld().path_from(build_root)] +
+			['--debug-configuration'] +
+			['--with-' + lib for lib in self.generator.target] +
+			(['toolset=' + env.BJAM_TOOLSET] if env.BJAM_TOOLSET else []) +
+			['link=' + 'shared'] +
+			['variant=' + 'release']
+		)
+		debug('runner: ' + build_root.srcpath() + '> ' + str(cmd))
+		ret = self.exec_command(cmd, cwd=build_root.srcpath())
+		if ret != 0:
+			return ret
+		self.set_outputs(path.get_bld().ant_glob('lib/*') + path.get_bld().ant_glob('bin/*'))
+		return 0
+
+class bjam_installer(Task):
+	ext_in = 'install'
+	def run(self):
+		gen = self.generator
+		path = gen.path
+		for idir, pat in [('${LIBDIR}', 'lib/*'), ('${BINDIR}', 'bin/*')]:
+			files = []
+			for n in path.get_bld().ant_glob(pat):
+				try:
+					t = readlink(n.srcpath())
+					gen.bld.symlink_as(sep.join([idir, n.name]), t, postpone=False)
+				except OSError:
+					files.append(n)
+			gen.bld.install_files(idir, files, postpone=False)
+		return 0
+
diff --git a/xpdeint/waf/waflib/extras/boo.py b/xpdeint/waf/waflib/extras/boo.py
new file mode 100644
index 0000000..e37529e
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/boo.py
@@ -0,0 +1,81 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Yannick LM 2011
+
+"""
+Support for the boo programming language, for example::
+
+	bld(features = "boo",       # necessary feature
+		source   = "src.boo",   # list of boo files
+		gen      = "world.dll", # target
+		type     = "library",   # library/exe ("-target:xyz" flag)
+		name     = "world"      # necessary if the target is referenced by 'use'
+	)
+"""
+
+from waflib import Task
+from waflib.Configure import conf
+from waflib.TaskGen import feature, after, before, extension
+
+ at extension('.boo')
+def boo_hook(self, node):
+	# Nothing here yet ...
+	# TODO filter the non-boo source files in 'apply_booc' and remove this method
+	pass
+
+ at feature('boo')
+ at before('process_source')
+def apply_booc(self):
+	"""Create a booc task """
+	src_nodes = self.to_nodes(self.source)
+	out_node = self.path.find_or_declare(self.gen)
+
+	self.boo_task = self.create_task('booc', src_nodes, [out_node])
+
+	# Set variables used by the 'booc' task
+	self.boo_task.env.OUT = '-o:%s' % out_node.abspath()
+
+	# type is "exe" by default
+	type = getattr(self, "type", "exe")
+	self.boo_task.env.BOO_TARGET_TYPE = "-target:%s" % type
+
+ at feature('boo')
+ at after('apply_boo')
+def use_boo(self):
+	""""
+	boo applications honor the **use** keyword::
+	"""
+	dep_names = self.to_list(getattr(self, 'use', []))
+	for dep_name in dep_names:
+		dep_task_gen = self.bld.get_tgen_by_name(dep_name)
+		if not dep_task_gen:
+			continue
+		dep_task_gen.post()
+		dep_task = getattr(dep_task_gen, 'boo_task', None)
+		if not dep_task:
+			# Try a cs task:
+			dep_task = getattr(dep_task_gen, 'cs_task', None)
+			if not dep_task:
+				# Try a link task:
+				dep_task = getattr(dep_task, 'link_task', None)
+				if not dep_task:
+					# Abort ...
+					continue
+		self.boo_task.set_run_after(dep_task) # order
+		self.boo_task.dep_nodes.extend(dep_task.outputs) # dependency
+		self.boo_task.env.append_value('BOO_FLAGS', '-reference:%s' % dep_task.outputs[0].abspath())
+
+class booc(Task.Task):
+	"""Compiles .boo files """
+	color   = 'YELLOW'
+	run_str = '${BOOC} ${BOO_FLAGS} ${BOO_TARGET_TYPE} ${OUT} ${SRC}'
+
+ at conf
+def check_booc(self):
+	self.find_program('booc', 'BOOC')
+	self.env.BOO_FLAGS = ['-nologo']
+
+def configure(self):
+	"""Check that booc is available """
+	self.check_booc()
+
diff --git a/xpdeint/waf/waflib/extras/boost.py b/xpdeint/waf/waflib/extras/boost.py
new file mode 100644
index 0000000..3b0772c
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/boost.py
@@ -0,0 +1,362 @@
+#!/usr/bin/env python
+# encoding: utf-8
+#
+# partially based on boost.py written by Gernot Vormayr
+# written by Ruediger Sonderfeld <ruediger at c-plusplus.de>, 2008
+# modified by Bjoern Michaelsen, 2008
+# modified by Luca Fossati, 2008
+# rewritten for waf 1.5.1, Thomas Nagy, 2008
+# rewritten for waf 1.6.2, Sylvain Rouquette, 2011
+
+'''
+
+This is an extra tool, not bundled with the default waf binary.
+To add the boost tool to the waf file:
+$ ./waf-light --tools=compat15,boost
+	or, if you have waf >= 1.6.2
+$ ./waf update --files=boost
+
+When using this tool, the wscript will look like:
+
+	def options(opt):
+		opt.load('compiler_cxx boost')
+
+	def configure(conf):
+		conf.load('compiler_cxx boost')
+		conf.check_boost(lib='system filesystem')
+
+	def build(bld):
+		bld(source='main.cpp', target='app', use='BOOST')
+
+Options are generated, in order to specify the location of boost includes/libraries.
+The `check_boost` configuration function allows to specify the used boost libraries.
+It can also provide default arguments to the --boost-static and --boost-mt command-line arguments.
+Everything will be packaged together in a BOOST component that you can use.
+
+When using MSVC, a lot of compilation flags need to match your BOOST build configuration:
+ - you may have to add /EHsc to your CXXFLAGS or define boost::throw_exception if BOOST_NO_EXCEPTIONS is defined.
+   Errors: C4530
+ - boost libraries will try to be smart and use the (pretty but often not useful) auto-linking feature of MSVC
+   So before calling `conf.check_boost` you might want to disabling by adding:
+   	conf.env.DEFINES_BOOST += ['BOOST_ALL_NO_LIB']
+   Errors: 
+ - boost might also be compiled with /MT, which links the runtime statically.
+   If you have problems with redefined symbols, 
+		self.env['DEFINES_%s' % var] += ['BOOST_ALL_NO_LIB']
+		self.env['CXXFLAGS_%s' % var] += ['/MD', '/EHsc']
+Passing `--boost-linkage_autodetect` might help ensuring having a correct linkage in some basic cases.
+
+'''
+
+import sys
+import re
+from waflib import Utils, Logs, Errors
+from waflib.Configure import conf
+
+BOOST_LIBS = ['/usr/lib', '/usr/local/lib', '/opt/local/lib', '/sw/lib', '/lib']
+BOOST_INCLUDES = ['/usr/include', '/usr/local/include', '/opt/local/include', '/sw/include']
+BOOST_VERSION_FILE = 'boost/version.hpp'
+BOOST_VERSION_CODE = '''
+#include <iostream>
+#include <boost/version.hpp>
+int main() { std::cout << BOOST_LIB_VERSION << std::endl; }
+'''
+
+# toolsets from {boost_dir}/tools/build/v2/tools/common.jam
+PLATFORM = Utils.unversioned_sys_platform()
+detect_intel = lambda env: (PLATFORM == 'win32') and 'iw' or 'il'
+detect_clang = lambda env: (PLATFORM == 'darwin') and 'clang-darwin' or 'clang'
+detect_mingw = lambda env: (re.search('MinGW', env.CXX[0])) and 'mgw' or 'gcc'
+BOOST_TOOLSETS = {
+	'borland':  'bcb',
+	'clang':	detect_clang,
+	'como':	 'como',
+	'cw':	   'cw',
+	'darwin':   'xgcc',
+	'edg':	  'edg',
+	'g++':	  detect_mingw,
+	'gcc':	  detect_mingw,
+	'icpc':	 detect_intel,
+	'intel':	detect_intel,
+	'kcc':	  'kcc',
+	'kylix':	'bck',
+	'mipspro':  'mp',
+	'mingw':	'mgw',
+	'msvc':	 'vc',
+	'qcc':	  'qcc',
+	'sun':	  'sw',
+	'sunc++':   'sw',
+	'tru64cxx': 'tru',
+	'vacpp':	'xlc'
+}
+
+
+def options(opt):
+	opt.add_option('--boost-includes', type='string',
+				   default='', dest='boost_includes',
+				   help='''path to the boost includes root (~boost root)
+				   e.g. /path/to/boost_1_47_0''')
+	opt.add_option('--boost-libs', type='string',
+				   default='', dest='boost_libs',
+				   help='''path to the directory where the boost libs are
+				   e.g. /path/to/boost_1_47_0/stage/lib''')
+	opt.add_option('--boost-static', action='store_true',
+				   default=False, dest='boost_static',
+				   help='link with static boost libraries (.lib/.a)')
+	opt.add_option('--boost-mt', action='store_true',
+				   default=False, dest='boost_mt',
+				   help='select multi-threaded libraries')
+	opt.add_option('--boost-abi', type='string', default='', dest='boost_abi',
+				   help='''select libraries with tags (dgsyp, d for debug),
+				   see doc Boost, Getting Started, chapter 6.1''')
+	opt.add_option('--boost-linkage_autodetect', action="store_true", dest='boost_linkage_autodetect',
+				   help="auto-detect boost linkage options (don't get used to it / might break other stuff)")
+	opt.add_option('--boost-toolset', type='string',
+				   default='', dest='boost_toolset',
+				   help='force a toolset e.g. msvc, vc90, \
+						gcc, mingw, mgw45 (default: auto)')
+	py_version = '%d%d' % (sys.version_info[0], sys.version_info[1])
+	opt.add_option('--boost-python', type='string',
+				   default=py_version, dest='boost_python',
+				   help='select the lib python with this version \
+						(default: %s)' % py_version)
+
+
+ at conf
+def __boost_get_version_file(self, dir):
+	try:
+		return self.root.find_dir(dir).find_node(BOOST_VERSION_FILE)
+	except:
+		return None
+
+
+ at conf
+def boost_get_version(self, dir):
+	"""silently retrieve the boost version number"""
+	re_but = re.compile('^#define\\s+BOOST_LIB_VERSION\\s+"(.*)"$', re.M)
+	try:
+		val = re_but.search(self.__boost_get_version_file(dir).read()).group(1)
+	except:
+		val = self.check_cxx(fragment=BOOST_VERSION_CODE, includes=[dir],
+							 execute=True, define_ret=True)
+	return val
+
+
+ at conf
+def boost_get_includes(self, *k, **kw):
+	includes = k and k[0] or kw.get('includes', None)
+	if includes and self.__boost_get_version_file(includes):
+		return includes
+	for dir in BOOST_INCLUDES:
+		if self.__boost_get_version_file(dir):
+			return dir
+	if includes:
+		self.fatal('headers not found in %s' % includes)
+	else:
+		self.fatal('headers not found, please provide a --boost-includes argument (see help)')
+
+
+ at conf
+def boost_get_toolset(self, cc):
+	toolset = cc
+	if not cc:
+		build_platform = Utils.unversioned_sys_platform()
+		if build_platform in BOOST_TOOLSETS:
+			cc = build_platform
+		else:
+			cc = self.env.CXX_NAME
+	if cc in BOOST_TOOLSETS:
+		toolset = BOOST_TOOLSETS[cc]
+	return isinstance(toolset, str) and toolset or toolset(self.env)
+
+
+ at conf
+def __boost_get_libs_path(self, *k, **kw):
+	''' return the lib path and all the files in it '''
+	if 'files' in kw:
+		return self.root.find_dir('.'), Utils.to_list(kw['files'])
+	libs = k and k[0] or kw.get('libs', None)
+	if libs:
+		path = self.root.find_dir(libs)
+		files = path.ant_glob('*boost_*')
+	if not libs or not files:
+		for dir in BOOST_LIBS:
+			try:
+				path = self.root.find_dir(dir)
+				files = path.ant_glob('*boost_*')
+				if files:
+					break
+				path = self.root.find_dir(dir + '64')
+				files = path.ant_glob('*boost_*')
+				if files:
+					break
+			except:
+				path = None
+	if not path:
+		if libs:
+			self.fatal('libs not found in %s' % libs)
+		else:
+			self.fatal('libs not found, please provide a --boost-libs argument (see help)')
+
+	self.to_log('Found the boost path in %r with the libraries:' % path)
+	for x in files:
+		self.to_log('    %r' % x)
+	return path, files
+
+ at conf
+def boost_get_libs(self, *k, **kw):
+	'''
+	return the lib path and the required libs
+	according to the parameters
+	'''
+	path, files = self.__boost_get_libs_path(**kw)
+	t = []
+	if kw.get('mt', False):
+		t.append('mt')
+	if kw.get('abi', None):
+		t.append(kw['abi'])
+	tags = t and '(-%s)+' % '-'.join(t) or ''
+	toolset = self.boost_get_toolset(kw.get('toolset', ''))
+	toolset_pat = '(-%s[0-9]{0,3})+' % toolset
+	version = '(-%s)+' % self.env.BOOST_VERSION
+
+	def find_lib(re_lib, files):
+		for file in files:
+			if re_lib.search(file.name):
+				self.to_log('Found boost lib %s' % file)
+				return file
+		return None
+
+	def format_lib_name(name):
+		if name.startswith('lib'):
+			name = name[3:]
+		return name.split('.')[0]
+
+	libs = []
+	for lib in Utils.to_list(k and k[0] or kw.get('lib', None)):
+		py = (lib == 'python') and '(-py%s)+' % kw['python'] or ''
+		# Trying libraries, from most strict match to least one
+		for pattern in ['boost_%s%s%s%s%s' % (lib, toolset_pat, tags, py, version),
+						'boost_%s%s%s%s' % (lib, tags, py, version),
+						'boost_%s%s%s' % (lib, tags, version),
+						# Give up trying to find the right version
+						'boost_%s%s%s%s' % (lib, toolset_pat, tags, py),
+						'boost_%s%s%s' % (lib, tags, py),
+						'boost_%s%s' % (lib, tags)]:
+			self.to_log('Trying pattern %s' % pattern)
+			file = find_lib(re.compile(pattern), files)
+			if file:
+				libs.append(format_lib_name(file.name))
+				break
+		else:
+			self.fatal('lib %s not found in %s' % (lib, path.abspath()))
+
+	return path.abspath(), libs
+
+
+ at conf
+def check_boost(self, *k, **kw):
+	"""
+	Initialize boost libraries to be used.
+
+	Keywords: you can pass the same parameters as with the command line (without "--boost-").
+	Note that the command line has the priority, and should preferably be used.
+	"""
+	if not self.env['CXX']:
+		self.fatal('load a c++ compiler first, conf.load("compiler_cxx")')
+
+	params = {'lib': k and k[0] or kw.get('lib', None)}
+	for key, value in self.options.__dict__.items():
+		if not key.startswith('boost_'):
+			continue
+		key = key[len('boost_'):]
+		params[key] = value and value or kw.get(key, '')
+
+	var = kw.get('uselib_store', 'BOOST')
+
+	self.start_msg('Checking boost includes')
+	self.env['INCLUDES_%s' % var] = inc = self.boost_get_includes(**params)
+	self.env.BOOST_VERSION = self.boost_get_version(inc)
+	self.end_msg(self.env.BOOST_VERSION)
+	if Logs.verbose:
+		Logs.pprint('CYAN', '	path : %s' % self.env['INCLUDES_%s' % var])
+
+	if not params['lib']:
+		return
+	self.start_msg('Checking boost libs')
+	suffix = params.get('static', None) and 'ST' or ''
+	path, libs = self.boost_get_libs(**params)
+	self.env['%sLIBPATH_%s' % (suffix, var)] = [path]
+	self.env['%sLIB_%s' % (suffix, var)] = libs
+	self.end_msg('ok')
+	if Logs.verbose:
+		Logs.pprint('CYAN', '	path : %s' % path)
+		Logs.pprint('CYAN', '	libs : %s' % libs)
+
+
+	def try_link():
+		if 'system' in params['lib']:
+			self.check_cxx(
+			 fragment="\n".join([
+			  '#include <boost/system/error_code.hpp>',
+			  'int main() { boost::system::error_code c; }',
+			 ]),
+			 use='BOOST',
+			 execute=True,
+			)
+		if 'thread' in params['lib']:
+			self.check_cxx(
+			 fragment="\n".join([
+			  '#include <boost/thread.hpp>',
+			  'int main() { boost::thread t; }',
+			 ]),
+			 use='BOOST',
+			 execute=True,
+			)
+
+	if params.get('linkage_autodetect', False):
+		self.start_msg("Attempting to detect boost linkage flags")
+		toolset = self.boost_get_toolset(kw.get('toolset', ''))
+		if toolset in ['vc']:
+			# disable auto-linking feature, causing error LNK1181
+			# because the code wants to be linked against
+			self.env['DEFINES_%s' % var] += ['BOOST_ALL_NO_LIB']
+
+			# if no dlls are present, we guess the .lib files are not stubs
+			has_dlls = False
+			for x in Utils.listdir(path):
+				if x.endswith(self.env.cxxshlib_PATTERN % ''):
+					has_dlls = True
+					break
+			if not has_dlls:
+				self.env['STLIBPATH_%s' % var] = [path]
+				self.env['STLIB_%s' % var] = libs
+				del self.env['LIB_%s' % var]
+				del self.env['LIBPATH_%s' % var]
+
+			# we attempt to play with some known-to-work CXXFLAGS combinations
+			for cxxflags in (['/MD', '/EHsc'], []):
+				self.env.stash()
+				self.env["CXXFLAGS_%s" % var] += cxxflags
+				try:
+					try_link()
+					self.end_msg("ok: winning cxxflags combination: %s" % (self.env["CXXFLAGS_%s" % var]))
+					e = None
+					break
+				except Errors.ConfigurationError as exc:
+					self.env.revert()
+					e = exc
+
+			if e is not None:
+				self.fatal("Could not auto-detect boost linking flags combination, you may report it to boost.py author", ex=e)
+		else:
+			self.fatal("Boost linkage flags auto-detection not implemented (needed ?) for this toolchain")
+	else:
+		self.start_msg('Checking for boost linkage')
+		try:
+			try_link()
+		except Errors.ConfigurationError as e:
+			self.fatal("Could not link against boost libraries using supplied options")
+		self.end_msg('ok')
+
+
diff --git a/xpdeint/waf/waflib/extras/c_bgxlc.py b/xpdeint/waf/waflib/extras/c_bgxlc.py
new file mode 100644
index 0000000..7998f17
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/c_bgxlc.py
@@ -0,0 +1,30 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# harald at klimachs.de
+
+import os
+from waflib.Tools import ccroot,ar
+from waflib.Configure import conf
+
+from waflib.Tools import xlc # method xlc_common_flags
+from waflib.Tools.compiler_c import c_compiler
+c_compiler['linux'].insert(0, 'c_bgxlc')
+
+ at conf
+def find_bgxlc(conf):
+	cc = conf.find_program(['bgxlc_r','bgxlc'], var='CC')
+	cc = conf.cmd_to_list(cc)
+	conf.get_xlc_version(cc)
+	conf.env.CC = cc
+	conf.env.CC_NAME = 'bgxlc'
+
+def configure(conf):
+	conf.find_bgxlc()
+	conf.find_ar()
+	conf.xlc_common_flags()
+	conf.env.LINKFLAGS_cshlib = ['-G','-Wl,-bexpfull']
+	conf.env.LINKFLAGS_cprogram = []
+	conf.cc_load_tools()
+	conf.cc_add_flags()
+	conf.link_add_flags()
+
diff --git a/xpdeint/waf/waflib/extras/c_dumbpreproc.py b/xpdeint/waf/waflib/extras/c_dumbpreproc.py
new file mode 100644
index 0000000..6246301
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/c_dumbpreproc.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+
+"""
+Dumb C/C++ preprocessor for finding dependencies
+
+It will look at all include files it can find after removing the comments, so the following
+will always add the dependency on both "a.h" and "b.h"::
+
+	#include "a.h"
+	#ifdef B
+		#include "b.h"
+	#endif
+	int main() {
+		return 0;
+	}
+
+To use::
+
+	def configure(conf):
+		conf.load('compiler_c')
+		conf.load('c_dumbpreproc')
+"""
+
+import re, sys, os, string, traceback
+from waflib import Logs, Build, Utils, Errors
+from waflib.Logs import debug, error
+from waflib.Tools import c_preproc
+
+re_inc = re.compile(
+	'^[ \t]*(#|%:)[ \t]*(include)[ \t]*[<"](.*)[>"]\r*$',
+	re.IGNORECASE | re.MULTILINE)
+
+def lines_includes(node):
+	code = node.read()
+	if c_preproc.use_trigraphs:
+		for (a, b) in c_preproc.trig_def: code = code.split(a).join(b)
+	code = c_preproc.re_nl.sub('', code)
+	code = c_preproc.re_cpp.sub(c_preproc.repl, code)
+	return [(m.group(2), m.group(3)) for m in re.finditer(re_inc, code)]
+
+parser = c_preproc.c_parser
+class dumb_parser(parser):
+	def addlines(self, node):
+		if node in self.nodes[:-1]:
+			return
+		self.currentnode_stack.append(node.parent)
+		self.lines = lines_includes(node) + [(c_preproc.POPFILE, '')] +  self.lines
+
+	def start(self, node, env):
+		self.addlines(node)
+		while self.lines:
+			(x, y) = self.lines.pop(0)
+			if x == c_preproc.POPFILE:
+				self.currentnode_stack.pop()
+				continue
+			self.tryfind(y)
+
+c_preproc.c_parser = dumb_parser
+
diff --git a/xpdeint/waf/waflib/extras/compat15.py b/xpdeint/waf/waflib/extras/compat15.py
new file mode 100644
index 0000000..6e3f7fe
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/compat15.py
@@ -0,0 +1,298 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2010 (ita)
+
+"""
+This file is provided to enable compatibility with waf 1.5, it will be removed in waf 1.7
+"""
+
+import sys
+from waflib import ConfigSet, Logs, Options, Scripting, Task, Build, Configure, Node, Runner, TaskGen, Utils, Errors, Context
+
+# the following is to bring some compatibility with waf 1.5 "import waflib.Configure → import Configure"
+sys.modules['Environment'] = ConfigSet
+ConfigSet.Environment = ConfigSet.ConfigSet
+
+sys.modules['Logs'] = Logs
+sys.modules['Options'] = Options
+sys.modules['Scripting'] = Scripting
+sys.modules['Task'] = Task
+sys.modules['Build'] = Build
+sys.modules['Configure'] = Configure
+sys.modules['Node'] = Node
+sys.modules['Runner'] = Runner
+sys.modules['TaskGen'] = TaskGen
+sys.modules['Utils'] = Utils
+
+from waflib.Tools import c_preproc
+sys.modules['preproc'] = c_preproc
+
+from waflib.Tools import c_config
+sys.modules['config_c'] = c_config
+
+ConfigSet.ConfigSet.copy = ConfigSet.ConfigSet.derive
+ConfigSet.ConfigSet.set_variant = Utils.nada
+
+Build.BuildContext.add_subdirs = Build.BuildContext.recurse
+Build.BuildContext.new_task_gen = Build.BuildContext.__call__
+Build.BuildContext.is_install = 0
+Node.Node.relpath_gen = Node.Node.path_from
+
+def name_to_obj(self, s, env=None):
+	Logs.warn('compat: change "name_to_obj(name, env)" by "get_tgen_by_name(name)"')
+	return self.get_tgen_by_name(s)
+Build.BuildContext.name_to_obj = name_to_obj
+
+def env_of_name(self, name):
+	try:
+		return self.all_envs[name]
+	except KeyError:
+		Logs.error('no such environment: '+name)
+		return None
+Build.BuildContext.env_of_name = env_of_name
+
+
+def set_env_name(self, name, env):
+	self.all_envs[name] = env
+	return env
+Configure.ConfigurationContext.set_env_name = set_env_name
+
+def retrieve(self, name, fromenv=None):
+	try:
+		env = self.all_envs[name]
+	except KeyError:
+		env = ConfigSet.ConfigSet()
+		self.prepare_env(env)
+		self.all_envs[name] = env
+	else:
+		if fromenv: Logs.warn("The environment %s may have been configured already" % name)
+	return env
+Configure.ConfigurationContext.retrieve = retrieve
+
+Configure.ConfigurationContext.sub_config = Configure.ConfigurationContext.recurse
+Configure.ConfigurationContext.check_tool = Configure.ConfigurationContext.load
+Configure.conftest = Configure.conf
+Configure.ConfigurationError = Errors.ConfigurationError
+
+Options.OptionsContext.sub_options = Options.OptionsContext.recurse
+Options.OptionsContext.tool_options = Context.Context.load
+Options.Handler = Options.OptionsContext
+
+Task.simple_task_type = Task.task_type_from_func = Task.task_factory
+Task.TaskBase.classes = Task.classes
+
+def setitem(self, key, value):
+	if key.startswith('CCFLAGS'):
+		key = key[1:]
+	self.table[key] = value
+ConfigSet.ConfigSet.__setitem__ = setitem
+
+ at TaskGen.feature('d')
+ at TaskGen.before('apply_incpaths')
+def old_importpaths(self):
+	if getattr(self, 'importpaths', []):
+		self.includes = self.importpaths
+
+from waflib import Context
+eld = Context.load_tool
+def load_tool(*k, **kw):
+	ret = eld(*k, **kw)
+	if 'set_options' in ret.__dict__:
+		Logs.warn('compat: rename "set_options" to options')
+		ret.options = ret.set_options
+	if 'detect' in ret.__dict__:
+		Logs.warn('compat: rename "detect" to "configure"')
+		ret.configure = ret.detect
+	return ret
+Context.load_tool = load_tool
+
+rev = Context.load_module
+def load_module(path):
+	ret = rev(path)
+	if 'set_options' in ret.__dict__:
+		Logs.warn('compat: rename "set_options" to "options" (%r)' % path)
+		ret.options = ret.set_options
+	if 'srcdir' in ret.__dict__:
+		Logs.warn('compat: rename "srcdir" to "top" (%r)' % path)
+		ret.top = ret.srcdir
+	if 'blddir' in ret.__dict__:
+		Logs.warn('compat: rename "blddir" to "out" (%r)' % path)
+		ret.out = ret.blddir
+	return ret
+Context.load_module = load_module
+
+old_post = TaskGen.task_gen.post
+def post(self):
+	self.features = self.to_list(self.features)
+	if 'cc' in self.features:
+		Logs.warn('compat: the feature cc does not exist anymore (use "c")')
+		self.features.remove('cc')
+		self.features.append('c')
+	if 'cstaticlib' in self.features:
+		Logs.warn('compat: the feature cstaticlib does not exist anymore (use "cstlib" or "cxxstlib")')
+		self.features.remove('cstaticlib')
+		self.features.append(('cxx' in self.features) and 'cxxstlib' or 'cstlib')
+	if getattr(self, 'ccflags', None):
+		Logs.warn('compat: "ccflags" was renamed to "cflags"')
+		self.cflags = self.ccflags
+	return old_post(self)
+TaskGen.task_gen.post = post
+
+def waf_version(*k, **kw):
+	Logs.warn('wrong version (waf_version was removed in waf 1.6)')
+Utils.waf_version = waf_version
+
+
+import os
+ at TaskGen.feature('c', 'cxx', 'd')
+ at TaskGen.before('apply_incpaths', 'propagate_uselib_vars')
+ at TaskGen.after('apply_link', 'process_source')
+def apply_uselib_local(self):
+	"""
+	process the uselib_local attribute
+	execute after apply_link because of the execution order set on 'link_task'
+	"""
+	env = self.env
+	from waflib.Tools.ccroot import stlink_task
+
+	# 1. the case of the libs defined in the project (visit ancestors first)
+	# the ancestors external libraries (uselib) will be prepended
+	self.uselib = self.to_list(getattr(self, 'uselib', []))
+	self.includes = self.to_list(getattr(self, 'includes', []))
+	names = self.to_list(getattr(self, 'uselib_local', []))
+	get = self.bld.get_tgen_by_name
+	seen = set([])
+	tmp = Utils.deque(names) # consume a copy of the list of names
+	if tmp:
+		Logs.warn('compat: "uselib_local" is deprecated, replace by "use"')
+	while tmp:
+		lib_name = tmp.popleft()
+		# visit dependencies only once
+		if lib_name in seen:
+			continue
+
+		y = get(lib_name)
+		y.post()
+		seen.add(lib_name)
+
+		# object has ancestors to process (shared libraries): add them to the end of the list
+		if getattr(y, 'uselib_local', None):
+			for x in self.to_list(getattr(y, 'uselib_local', [])):
+				obj = get(x)
+				obj.post()
+				if getattr(obj, 'link_task', None):
+					if not isinstance(obj.link_task, stlink_task):
+						tmp.append(x)
+
+		# link task and flags
+		if getattr(y, 'link_task', None):
+
+			link_name = y.target[y.target.rfind(os.sep) + 1:]
+			if isinstance(y.link_task, stlink_task):
+				env.append_value('STLIB', [link_name])
+			else:
+				# some linkers can link against programs
+				env.append_value('LIB', [link_name])
+
+			# the order
+			self.link_task.set_run_after(y.link_task)
+
+			# for the recompilation
+			self.link_task.dep_nodes += y.link_task.outputs
+
+			# add the link path too
+			tmp_path = y.link_task.outputs[0].parent.bldpath()
+			if not tmp_path in env['LIBPATH']:
+				env.prepend_value('LIBPATH', [tmp_path])
+
+		# add ancestors uselib too - but only propagate those that have no staticlib defined
+		for v in self.to_list(getattr(y, 'uselib', [])):
+			if not env['STLIB_' + v]:
+				if not v in self.uselib:
+					self.uselib.insert(0, v)
+
+		# if the library task generator provides 'export_includes', add to the include path
+		# the export_includes must be a list of paths relative to the other library
+		if getattr(y, 'export_includes', None):
+			self.includes.extend(y.to_incnodes(y.export_includes))
+
+ at TaskGen.feature('cprogram', 'cxxprogram', 'cstlib', 'cxxstlib', 'cshlib', 'cxxshlib', 'dprogram', 'dstlib', 'dshlib')
+ at TaskGen.after('apply_link')
+def apply_objdeps(self):
+	"add the .o files produced by some other object files in the same manner as uselib_local"
+	names = getattr(self, 'add_objects', [])
+	if not names:
+		return
+	names = self.to_list(names)
+
+	get = self.bld.get_tgen_by_name
+	seen = []
+	while names:
+		x = names[0]
+
+		# visit dependencies only once
+		if x in seen:
+			names = names[1:]
+			continue
+
+		# object does not exist ?
+		y = get(x)
+
+		# object has ancestors to process first ? update the list of names
+		if getattr(y, 'add_objects', None):
+			added = 0
+			lst = y.to_list(y.add_objects)
+			lst.reverse()
+			for u in lst:
+				if u in seen: continue
+				added = 1
+				names = [u]+names
+			if added: continue # list of names modified, loop
+
+		# safe to process the current object
+		y.post()
+		seen.append(x)
+
+		for t in getattr(y, 'compiled_tasks', []):
+			self.link_task.inputs.extend(t.outputs)
+
+ at TaskGen.after('apply_link')
+def process_obj_files(self):
+	if not hasattr(self, 'obj_files'):
+		return
+	for x in self.obj_files:
+		node = self.path.find_resource(x)
+		self.link_task.inputs.append(node)
+
+ at TaskGen.taskgen_method
+def add_obj_file(self, file):
+	"""Small example on how to link object files as if they were source
+	obj = bld.create_obj('cc')
+	obj.add_obj_file('foo.o')"""
+	if not hasattr(self, 'obj_files'): self.obj_files = []
+	if not 'process_obj_files' in self.meths: self.meths.append('process_obj_files')
+	self.obj_files.append(file)
+
+
+old_define = Configure.ConfigurationContext.__dict__['define']
+
+ at Configure.conf
+def define(self, key, val, quote=True):
+	old_define(self, key, val, quote)
+	if key.startswith('HAVE_'):
+		self.env[key] = 1
+
+old_undefine = Configure.ConfigurationContext.__dict__['undefine']
+
+ at Configure.conf
+def undefine(self, key):
+	old_undefine(self, key)
+	if key.startswith('HAVE_'):
+		self.env[key] = 0
+
+# some people might want to use export_incdirs, but it was renamed
+def set_incdirs(self, val):
+	Logs.warn('compat: change "export_incdirs" by "export_includes"')
+	self.export_includes = val
+TaskGen.task_gen.export_incdirs = property(None, set_incdirs)
+
diff --git a/xpdeint/waf/waflib/extras/compat15.pyc b/xpdeint/waf/waflib/extras/compat15.pyc
new file mode 100644
index 0000000..c868826
Binary files /dev/null and b/xpdeint/waf/waflib/extras/compat15.pyc differ
diff --git a/xpdeint/waf/waflib/extras/cython.py b/xpdeint/waf/waflib/extras/cython.py
new file mode 100644
index 0000000..6be57ed
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/cython.py
@@ -0,0 +1,120 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2010
+
+import re
+
+import waflib
+import waflib.Logs as _msg
+from waflib import Task
+from waflib.TaskGen import extension, feature, before_method, after_method
+
+cy_api_pat = re.compile(r'\s*?cdef\s*?(public|api)\w*')
+re_cyt = re.compile('import\\s(\\w+)\\s*$', re.M)
+
+ at extension('.pyx')
+def add_cython_file(self, node):
+	"""
+	Process a *.pyx* file given in the list of source files. No additional
+	feature is required::
+
+		def build(bld):
+			bld(features='c cshlib pyext', source='main.c foo.pyx', target='app')
+	"""
+	ext = '.c'
+	if 'cxx' in self.features:
+		self.env.append_unique('CYTHONFLAGS', '--cplus')
+		ext = '.cc'
+	tsk = self.create_task('cython', node, node.change_ext(ext))
+	self.source += tsk.outputs
+
+class cython(Task.Task):
+	run_str = '${CYTHON} ${CYTHONFLAGS} -o ${TGT[0].abspath()} ${SRC}'
+	color   = 'GREEN'
+
+	vars    = ['INCLUDES']
+	"""
+	Rebuild whenever the INCLUDES change. The variables such as CYTHONFLAGS will be appended
+	by the metaclass.
+	"""
+
+	ext_out = ['.h']
+	"""
+	The creation of a .h file is known only after the build has begun, so it is not
+	possible to compute a build order just by looking at the task inputs/outputs.
+	"""
+
+	def runnable_status(self):
+		"""
+		Perform a double-check to add the headers created by cython
+		to the output nodes. The scanner is executed only when the cython task
+		must be executed (optimization).
+		"""
+		ret = super(cython, self).runnable_status()
+		if ret == Task.ASK_LATER:
+			return ret
+		for x in self.generator.bld.raw_deps[self.uid()]:
+			if x.startswith('header:'):
+				self.outputs.append(self.inputs[0].parent.find_or_declare(x.replace('header:', '')))
+		return super(cython, self).runnable_status()
+
+	def scan(self):
+		"""
+		Return the dependent files (.pxd) by looking in the include folders.
+		Put the headers to generate in the custom list "bld.raw_deps".
+		To inspect the scanne results use::
+
+			$ waf clean build --zones=deps
+		"""
+		txt = self.inputs[0].read()
+
+		mods = []
+		for m in re_cyt.finditer(txt):
+			mods.append(m.group(1))
+
+		_msg.debug("cython: mods %r" % mods)
+		incs = getattr(self.generator, 'cython_includes', [])
+		incs = [self.generator.path.find_dir(x) for x in incs]
+		incs.append(self.inputs[0].parent)
+
+		found = []
+		missing = []
+		for x in mods:
+			for y in incs:
+				k = y.find_resource(x + '.pxd')
+				if k:
+					found.append(k)
+					break
+			else:
+				missing.append(x)
+		_msg.debug("cython: found %r" % found)
+
+		# Now the .h created - store them in bld.raw_deps for later use
+		has_api = False
+		has_public = False
+		for l in txt.splitlines():
+			if cy_api_pat.match(l):
+				if ' api ' in l:
+					has_api = True
+				if ' public ' in l:
+					has_public = True
+		name = self.inputs[0].name.replace('.pyx', '')
+		if has_api:
+			missing.append('header:%s_api.h' % name)
+		if has_public:
+			missing.append('header:%s.h' % name)
+
+		return (found, missing)
+
+def options(ctx):
+	ctx.add_option('--cython-flags', action='store', default='', help='space separated list of flags to pass to cython')
+
+def configure(ctx):
+	if not ctx.env.CC and not ctx.env.CXX:
+		ctx.fatal('Load a C/C++ compiler first')
+	if not ctx.env.PYTHON:
+		ctx.fatal('Load the python tool first!')
+	ctx.find_program('cython', var='CYTHON')
+	if ctx.options.cython_flags:
+		ctx.env.CYTHONFLAGS = ctx.options.cython_flags
+
diff --git a/xpdeint/waf/waflib/extras/dcc.py b/xpdeint/waf/waflib/extras/dcc.py
new file mode 100644
index 0000000..93fbf0a
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/dcc.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Jérôme Carretero, 2011 (zougloub)
+
+from waflib import Configure, Options, Utils
+from waflib.Tools import ccroot
+from waflib.Configure import conf
+
+ at conf
+def find_dcc(conf):
+	cc = conf.find_program(['dcc'], var='CC', path_list=getattr(Options.options, 'diabbindir', ""))
+	cc = conf.cmd_to_list(cc)
+	conf.env.CC_NAME = 'dcc'
+	conf.env.CC = cc
+
+ at conf
+def find_dld(conf):
+	ld = conf.find_program(['dld'], var='LINK_CC', path_list=getattr(Options.options, 'diabbindir', ""))
+	ld = conf.cmd_to_list(ld)
+	conf.env.LINK_CC_NAME = 'dld'
+	conf.env.LINK_CC = ld
+
+ at conf
+def find_dar(conf):
+	ar = conf.find_program(['dar'], var='DAR', path_list=getattr(Options.options, 'diabbindir', ""))
+	ar = conf.cmd_to_list(ar)
+	conf.env.AR = ar
+	conf.env.AR_NAME = 'dar'
+	conf.env.ARFLAGS = 'rcs'
+
+ at conf
+def find_ddump(conf):
+	prg = conf.find_program(['ddump'], var='DDUMP', path_list=getattr(Options.options, 'diabbindir', ""))
+	prg = conf.cmd_to_list(prg)
+	conf.env.DDUMP = prg
+
+ at conf
+def dcc_common_flags(conf):
+	v = conf.env
+	v['CC_SRC_F']            = []
+	v['CC_TGT_F']            = ['-c', '-o']
+
+	# linker
+	if not v['LINK_CC']: v['LINK_CC'] = v['CC']
+	v['CCLNK_SRC_F']         = []
+	v['CCLNK_TGT_F']         = ['-o']
+	v['CPPPATH_ST']          = '-I%s'
+	v['DEFINES_ST']          = '-D%s'
+
+	v['LIB_ST']              = '-l:%s' # template for adding libs
+	v['LIBPATH_ST']          = '-L%s' # template for adding libpaths
+	v['STLIB_ST']            = '-l:%s'
+	v['STLIBPATH_ST']        = '-L%s'
+	v['RPATH_ST']            = '-Wl,-rpath,%s'
+	#v['STLIB_MARKER']        = '-Wl,-Bstatic'
+
+	# program
+	v['cprogram_PATTERN']    = '%s.elf'
+
+	# static lib
+	v['LINKFLAGS_cstlib']    = ['-Wl,-Bstatic']
+	v['cstlib_PATTERN']      = 'lib%s.a'
+
+def configure(conf):
+	conf.find_dcc()
+	conf.find_dar()
+	conf.find_dld()
+	conf.find_ddump()
+	conf.dcc_common_flags()
+	conf.cc_load_tools()
+	conf.cc_add_flags()
+	conf.link_add_flags()
+
+def options(opt):
+	"""
+	Add the ``--with-diab-bindir`` command-line options.
+	"""
+	opt.add_option('--with-diab-bindir', type='string', dest='diabbindir', help = 'Specify alternate diab bin folder', default="")
+
diff --git a/xpdeint/waf/waflib/extras/doxygen.py b/xpdeint/waf/waflib/extras/doxygen.py
new file mode 100644
index 0000000..a62c5a8
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/doxygen.py
@@ -0,0 +1,158 @@
+#! /usr/bin/env python
+# encoding: UTF-8
+# Thomas Nagy 2008-2010 (ita)
+
+"""
+
+Doxygen support
+
+Variables passed to bld():
+* doxyfile -- the Doxyfile to use
+
+ported from waf 1.5 (incomplete)
+"""
+
+from fnmatch import fnmatchcase
+import os, os.path, re, stat
+from waflib import Task, Utils, Node, Logs
+from waflib.TaskGen import feature
+
+DOXY_STR = '${DOXYGEN} - '
+DOXY_FMTS = 'html latex man rft xml'.split()
+DOXY_FILE_PATTERNS = '*.' + ' *.'.join('''
+c cc cxx cpp c++ java ii ixx ipp i++ inl h hh hxx hpp h++ idl odl cs php php3
+inc m mm py f90c cc cxx cpp c++ java ii ixx ipp i++ inl h hh hxx
+'''.split())
+
+re_nl = re.compile('\\\\\r*\n', re.MULTILINE)
+
+class doxygen(Task.Task):
+	vars  = ['DOXYGEN', 'DOXYFLAGS']
+	color = 'BLUE'
+
+	def runnable_status(self):
+		'''
+		self.pars are populated in runnable_status - because this function is being
+		run *before* both self.pars "consumers" - scan() and run()
+
+		set output_dir (node) for the output
+		'''
+
+		for x in self.run_after:
+			if not x.hasrun:
+				return Task.ASK_LATER
+
+		if not getattr(self, 'pars', None):
+			txt = self.inputs[0].read()
+			txt = re_nl.sub('', txt)
+			self.pars = Utils.str_to_dict(txt)
+			if not self.pars.get('OUTPUT_DIRECTORY'):
+				self.pars['OUTPUT_DIRECTORY'] = self.inputs[0].parent.get_bld().abspath()
+			if not self.pars.get('INPUT'):
+				self.pars['INPUT'] = self.inputs[0].parent.abspath()
+
+		if not getattr(self, 'output_dir', None):
+			self.output_dir = self.generator.bld.root.find_dir(self.pars['OUTPUT_DIRECTORY'])
+
+		self.signature()
+		return Task.Task.runnable_status(self)
+
+	def scan(self):
+		if self.pars.get('RECURSIVE') == 'YES':
+			Logs.warn("Doxygen RECURSIVE dependencies are not supported")
+
+		inputs = self.pars.get('INPUT').split()
+		exclude_patterns = self.pars.get('EXCLUDE_PATTERNS', '').split()
+		file_patterns = self.pars.get('FILE_PATTERNS', '').split()
+		if not file_patterns:
+			file_patterns = DOXY_FILE_PATTERNS
+
+		nodes = []
+		names = []
+		for i in inputs:
+			node = self.generator.bld.root.make_node(i)
+			if node:
+				if os.path.isdir(node.abspath()):
+					for m in node.ant_glob(file_patterns):
+						nodes.append(self.generator.bld.root.make_node(m.abspath()))
+				else:
+					nodes.append(node)
+			else:
+				names.append(i)
+
+		return (nodes, names)
+
+	def run(self):
+		code = '\n'.join(['%s = %s' % (x, self.pars[x]) for x in self.pars])
+		code = code.encode() # for python 3
+		#fmt = DOXY_STR % (self.inputs[0].parent.abspath())
+		cmd = Utils.subst_vars(DOXY_STR, self.env)
+		proc = Utils.subprocess.Popen(cmd, shell=True, stdin=Utils.subprocess.PIPE)
+		proc.communicate(code)
+		return proc.returncode
+
+	def post_run(self):
+		nodes = self.output_dir.ant_glob('**/*')
+		for x in nodes:
+			x.sig = Utils.h_file(x.abspath())
+		self.outputs += nodes
+		return Task.Task.post_run(self)
+
+	#def install(self):
+	#	if getattr(self.generator, 'install_to', None):
+	#		update_build_dir(self.inputs[0].parent, self.env)
+	#		pattern = getattr(self, 'instype', 'html/*')
+	#		self.generator.bld.install_files(self.generator.install_to, self.generator.path.ant_glob(pattern, dir=0, src=0))
+
+class tar(Task.Task):
+	"quick tar creation"
+	run_str = '${TAR} ${TAROPTS} ${TGT} ${SRC}'
+	color   = 'RED'
+	after   = ['doxygen']
+	def runnable_status(self):
+		for x in getattr(self, 'input_tasks', []):
+			if not x.hasrun:
+				return Task.ASK_LATER
+
+		if not getattr(self, 'tar_done_adding', None):
+			# execute this only once
+			self.tar_done_adding = True
+			for x in getattr(self, 'input_tasks', []):
+				self.set_inputs(x.outputs)
+			if not self.inputs:
+				return Task.SKIP_ME
+		return Task.Task.runnable_status(self)
+
+	def __str__(self):
+		tgt_str = ' '.join([a.nice_path(self.env) for a in self.outputs])
+		return '%s: %s\n' % (self.__class__.__name__, tgt_str)
+
+ at feature('doxygen')
+def process_doxy(self):
+	if not getattr(self, 'doxyfile', None):
+		self.generator.bld.fatal('no doxyfile??')
+
+	node = self.doxyfile
+	if not isinstance(node, Node.Node):
+		node = self.path.find_resource(node)
+	if not node:
+		raise ValueError('doxygen file not found')
+
+	# the task instance
+	dsk = self.create_task('doxygen', node)
+
+	if getattr(self, 'doxy_tar', None):
+		tsk = self.create_task('tar')
+		tsk.input_tasks = [dsk]
+		tsk.set_outputs(self.path.find_or_declare(self.doxy_tar))
+		if self.doxy_tar.endswith('bz2'):
+			tsk.env['TAROPTS'] = ['cjf']
+		elif self.doxy_tar.endswith('gz'):
+			tsk.env['TAROPTS'] = ['czf']
+		else:
+			tsk.env['TAROPTS'] = ['cf']
+
+def configure(conf):
+	conf.find_program('doxygen', var='DOXYGEN')
+	conf.find_program('tar', var='TAR')
+
diff --git a/xpdeint/waf/waflib/extras/dumbpreproc.py b/xpdeint/waf/waflib/extras/dumbpreproc.py
new file mode 100644
index 0000000..6246301
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/dumbpreproc.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+
+"""
+Dumb C/C++ preprocessor for finding dependencies
+
+It will look at all include files it can find after removing the comments, so the following
+will always add the dependency on both "a.h" and "b.h"::
+
+	#include "a.h"
+	#ifdef B
+		#include "b.h"
+	#endif
+	int main() {
+		return 0;
+	}
+
+To use::
+
+	def configure(conf):
+		conf.load('compiler_c')
+		conf.load('c_dumbpreproc')
+"""
+
+import re, sys, os, string, traceback
+from waflib import Logs, Build, Utils, Errors
+from waflib.Logs import debug, error
+from waflib.Tools import c_preproc
+
+re_inc = re.compile(
+	'^[ \t]*(#|%:)[ \t]*(include)[ \t]*[<"](.*)[>"]\r*$',
+	re.IGNORECASE | re.MULTILINE)
+
+def lines_includes(node):
+	code = node.read()
+	if c_preproc.use_trigraphs:
+		for (a, b) in c_preproc.trig_def: code = code.split(a).join(b)
+	code = c_preproc.re_nl.sub('', code)
+	code = c_preproc.re_cpp.sub(c_preproc.repl, code)
+	return [(m.group(2), m.group(3)) for m in re.finditer(re_inc, code)]
+
+parser = c_preproc.c_parser
+class dumb_parser(parser):
+	def addlines(self, node):
+		if node in self.nodes[:-1]:
+			return
+		self.currentnode_stack.append(node.parent)
+		self.lines = lines_includes(node) + [(c_preproc.POPFILE, '')] +  self.lines
+
+	def start(self, node, env):
+		self.addlines(node)
+		while self.lines:
+			(x, y) = self.lines.pop(0)
+			if x == c_preproc.POPFILE:
+				self.currentnode_stack.pop()
+				continue
+			self.tryfind(y)
+
+c_preproc.c_parser = dumb_parser
+
diff --git a/xpdeint/waf/waflib/extras/eclipse.py b/xpdeint/waf/waflib/extras/eclipse.py
new file mode 100644
index 0000000..b109697
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/eclipse.py
@@ -0,0 +1,308 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Eclipse CDT 5.0 generator for Waf
+# Richard Quirk 2009-1011 (New BSD License)
+# Thomas Nagy 2011 (ported to Waf 1.6)
+
+"""
+Usage:
+
+def options(opt):
+	opt.load('eclipse')
+
+$ waf configure eclipse
+"""
+
+import sys, os
+from waflib import Utils, Logs, Context, Options, Build, TaskGen, Scripting
+from xml.dom.minidom import Document
+
+oe_cdt = 'org.eclipse.cdt'
+cdt_mk = oe_cdt + '.make.core'
+cdt_core = oe_cdt + '.core'
+cdt_bld = oe_cdt + '.build.core'
+
+class eclipse(Build.BuildContext):
+	cmd = 'eclipse'
+	fun = Scripting.default_cmd
+
+	def execute(self):
+		"""
+		Entry point
+		"""
+		self.restore()
+		if not self.all_envs:
+			self.load_envs()
+		self.recurse([self.run_dir])
+
+		appname = getattr(Context.g_module, Context.APPNAME, os.path.basename(self.srcnode.abspath()))
+		self.create_cproject(appname, pythonpath=self.env['ECLIPSE_PYTHON_PATH'])
+
+	def create_cproject(self, appname, workspace_includes=[], pythonpath=[]):
+		"""
+		Create the Eclipse CDT .project and .cproject files
+		@param appname The name that will appear in the Project Explorer
+		@param build The BuildContext object to extract includes from
+		@param workspace_includes Optional project includes to prevent
+			  "Unresolved Inclusion" errors in the Eclipse editor
+		@param pythonpath Optional project specific python paths
+		"""
+		source_dirs = []
+		cpppath = self.env['CPPPATH']
+		Logs.warn('Generating Eclipse CDT project files')
+
+		for g in self.groups:
+			for tg in g:
+				if not isinstance(tg, TaskGen.task_gen):
+					continue
+
+				tg.post()
+				if not getattr(tg, 'link_task', None):
+					continue
+
+				l = Utils.to_list(getattr(tg, "includes", ''))
+				sources = Utils.to_list(getattr(tg, 'source', ''))
+				features = Utils.to_list(getattr(tg, 'features', ''))
+
+				is_cc = 'c' in features or 'cxx' in features
+
+				bldpath = tg.path.bldpath()
+
+				base = os.path.normpath(os.path.join(self.bldnode.name, tg.path.srcpath()))
+
+				if is_cc:
+					sources_dirs = set([src.parent for src in tg.to_nodes(sources)])
+
+				incnodes = tg.to_incnodes(tg.to_list(getattr(tg, 'includes', [])) + tg.env['INCLUDES'])
+				for p in incnodes:
+					path = p.path_from(self.srcnode)
+					workspace_includes.append(path)
+
+					if is_cc and path not in source_dirs:
+						source_dirs.append(path)
+
+		project = self.impl_create_project(sys.executable, appname)
+		self.srcnode.make_node('.project').write(project.toprettyxml())
+
+		waf = os.path.abspath(sys.argv[0])
+		project = self.impl_create_cproject(sys.executable, waf, appname, workspace_includes, cpppath, source_dirs)
+		self.srcnode.make_node('.cproject').write(project.toprettyxml())
+
+		project = self.impl_create_pydevproject(appname, sys.path, pythonpath)
+		self.srcnode.make_node('.pydevproject').write(project.toprettyxml())
+
+	def impl_create_project(self, executable, appname):
+		doc = Document()
+		projectDescription = doc.createElement('projectDescription')
+		self.add(doc, projectDescription, 'name', appname)
+		self.add(doc, projectDescription, 'comment')
+		self.add(doc, projectDescription, 'projects')
+		buildSpec = self.add(doc, projectDescription, 'buildSpec')
+		buildCommand = self.add(doc, buildSpec, 'buildCommand')
+		self.add(doc, buildCommand, 'name', oe_cdt + '.managedbuilder.core.genmakebuilder')
+		self.add(doc, buildCommand, 'triggers', 'clean,full,incremental,')
+		arguments = self.add(doc, buildCommand, 'arguments')
+		# the default make-style targets are overwritten by the .cproject values
+		dictionaries = {
+				cdt_mk + '.contents': cdt_mk + '.activeConfigSettings',
+				cdt_mk + '.enableAutoBuild': 'false',
+				cdt_mk + '.enableCleanBuild': 'true',
+				cdt_mk + '.enableFullBuild': 'true',
+				}
+		for k, v in dictionaries.items():
+			self.addDictionary(doc, arguments, k, v)
+
+		natures = self.add(doc, projectDescription, 'natures')
+		nature_list = """
+			core.ccnature
+			managedbuilder.core.ScannerConfigNature
+			managedbuilder.core.managedBuildNature
+			core.cnature
+		""".split()
+		for n in nature_list:
+			self.add(doc, natures, 'nature', oe_cdt + '.' + n)
+
+		self.add(doc, natures, 'nature', 'org.python.pydev.pythonNature')
+
+		doc.appendChild(projectDescription)
+		return doc
+
+	def impl_create_cproject(self, executable, waf, appname, workspace_includes, cpppath, source_dirs=[]):
+		doc = Document()
+		doc.appendChild(doc.createProcessingInstruction('fileVersion', '4.0.0'))
+		cconf_id = cdt_core + '.default.config.1'
+		cproject = doc.createElement('cproject')
+		storageModule = self.add(doc, cproject, 'storageModule',
+				{'moduleId': cdt_core + '.settings'})
+		cconf = self.add(doc, storageModule, 'cconfiguration', {'id':cconf_id})
+
+		storageModule = self.add(doc, cconf, 'storageModule',
+				{'buildSystemId': oe_cdt + '.managedbuilder.core.configurationDataProvider',
+				 'id': cconf_id,
+				 'moduleId': cdt_core + '.settings',
+				 'name': 'Default'})
+
+		self.add(doc, storageModule, 'externalSettings')
+
+		extensions = self.add(doc, storageModule, 'extensions')
+		extension_list = """
+			VCErrorParser
+			MakeErrorParser
+			GCCErrorParser
+			GASErrorParser
+			GLDErrorParser
+		""".split()
+		ext = self.add(doc, extensions, 'extension',
+					{'id': cdt_core + '.ELF', 'point':cdt_core + '.BinaryParser'})
+		for e in extension_list:
+			ext = self.add(doc, extensions, 'extension',
+					{'id': cdt_core + '.' + e, 'point':cdt_core + '.ErrorParser'})
+
+		storageModule = self.add(doc, cconf, 'storageModule',
+				{'moduleId': 'cdtBuildSystem', 'version': '4.0.0'})
+		config = self.add(doc, storageModule, 'configuration',
+					{'artifactName': appname,
+					 'id': cconf_id,
+					 'name': 'Default',
+					 'parent': cdt_bld + '.prefbase.cfg'})
+		folderInfo = self.add(doc, config, 'folderInfo',
+							{'id': cconf_id+'.', 'name': '/', 'resourcePath': ''})
+
+		toolChain = self.add(doc, folderInfo, 'toolChain',
+				{'id': cdt_bld + '.prefbase.toolchain.1',
+				 'name': 'No ToolChain',
+				 'resourceTypeBasedDiscovery': 'false',
+				 'superClass': cdt_bld + '.prefbase.toolchain'})
+
+		targetPlatform = self.add(doc, toolChain, 'targetPlatform',
+				{ 'binaryParser': 'org.eclipse.cdt.core.ELF',
+				  'id': cdt_bld + '.prefbase.toolchain.1', 'name': ''})
+
+		waf_build = '"%s" %s'%(waf, eclipse.fun)
+		waf_clean = '"%s" clean'%(waf)
+		builder = self.add(doc, toolChain, 'builder',
+						{'autoBuildTarget': waf_build,
+						 'command': executable,
+						 'enableAutoBuild': 'false',
+						 'cleanBuildTarget': waf_clean,
+						 'enableIncrementalBuild': 'true',
+						 'id': cdt_bld + '.settings.default.builder.1',
+						 'incrementalBuildTarget': waf_build,
+						 'managedBuildOn': 'false',
+						 'name': 'Gnu Make Builder',
+						 'superClass': cdt_bld + '.settings.default.builder'})
+
+		for tool_name in ("Assembly", "GNU C++", "GNU C"):
+			tool = self.add(doc, toolChain, 'tool',
+					{'id': cdt_bld + '.settings.holder.1',
+					 'name': tool_name,
+					 'superClass': cdt_bld + '.settings.holder'})
+			if cpppath or workspace_includes:
+				incpaths = cdt_bld + '.settings.holder.incpaths'
+				option = self.add(doc, tool, 'option',
+						{'id': incpaths+'.1',
+						 'name': 'Include Paths',
+						 'superClass': incpaths,
+						 'valueType': 'includePath'})
+				for i in workspace_includes:
+					self.add(doc, option, 'listOptionValue',
+								{'builtIn': 'false',
+								'value': '"${workspace_loc:/%s/%s}"'%(appname, i)})
+				for i in cpppath:
+					self.add(doc, option, 'listOptionValue',
+								{'builtIn': 'false',
+								'value': '"%s"'%(i)})
+		if source_dirs:
+			sourceEntries = self.add(doc, config, 'sourceEntries')
+			for i in source_dirs:
+				 self.add(doc, sourceEntries, 'entry',
+							{'excluding': i,
+							'flags': 'VALUE_WORKSPACE_PATH|RESOLVED',
+							'kind': 'sourcePath',
+							'name': ''})
+				 self.add(doc, sourceEntries, 'entry',
+							{
+							'flags': 'VALUE_WORKSPACE_PATH|RESOLVED',
+							'kind': 'sourcePath',
+							'name': i})
+
+		storageModule = self.add(doc, cconf, 'storageModule',
+							{'moduleId': cdt_mk + '.buildtargets'})
+		buildTargets = self.add(doc, storageModule, 'buildTargets')
+		def addTargetWrap(name, runAll):
+			return self.addTarget(doc, buildTargets, executable, name,
+								'"%s" %s'%(waf, name), runAll)
+		addTargetWrap('configure', True)
+		addTargetWrap('dist', False)
+		addTargetWrap('install', False)
+		addTargetWrap('check', False)
+
+		storageModule = self.add(doc, cproject, 'storageModule',
+							{'moduleId': 'cdtBuildSystem',
+							 'version': '4.0.0'})
+
+		project = self.add(doc, storageModule, 'project',
+					{'id': '%s.null.1'%appname, 'name': appname})
+
+		doc.appendChild(cproject)
+		return doc
+
+	def impl_create_pydevproject(self, appname, system_path, user_path):
+		# create a pydevproject file
+		doc = Document()
+		doc.appendChild(doc.createProcessingInstruction('eclipse-pydev', 'version="1.0"'))
+		pydevproject = doc.createElement('pydev_project')
+		prop = self.add(doc, pydevproject,
+					   'pydev_property',
+					   'python %d.%d'%(sys.version_info[0], sys.version_info[1]))
+		prop.setAttribute('name', 'org.python.pydev.PYTHON_PROJECT_VERSION')
+		prop = self.add(doc, pydevproject, 'pydev_property', 'Default')
+		prop.setAttribute('name', 'org.python.pydev.PYTHON_PROJECT_INTERPRETER')
+		# add waf's paths
+		wafadmin = [p for p in system_path if p.find('wafadmin') != -1]
+		if wafadmin:
+			prop = self.add(doc, pydevproject, 'pydev_pathproperty',
+					{'name':'org.python.pydev.PROJECT_EXTERNAL_SOURCE_PATH'})
+			for i in wafadmin:
+				self.add(doc, prop, 'path', i)
+		if user_path:
+			prop = self.add(doc, pydevproject, 'pydev_pathproperty',
+					{'name':'org.python.pydev.PROJECT_SOURCE_PATH'})
+			for i in user_path:
+				self.add(doc, prop, 'path', '/'+appname+'/'+i)
+
+		doc.appendChild(pydevproject)
+		return doc
+
+	def addDictionary(self, doc, parent, k, v):
+		dictionary = self.add(doc, parent, 'dictionary')
+		self.add(doc, dictionary, 'key', k)
+		self.add(doc, dictionary, 'value', v)
+		return dictionary
+
+	def addTarget(self, doc, buildTargets, executable, name, buildTarget, runAllBuilders=True):
+		target = self.add(doc, buildTargets, 'target',
+						{'name': name,
+						 'path': '',
+						 'targetID': oe_cdt + '.build.MakeTargetBuilder'})
+		self.add(doc, target, 'buildCommand', executable)
+		self.add(doc, target, 'buildArguments', None)
+		self.add(doc, target, 'buildTarget', buildTarget)
+		self.add(doc, target, 'stopOnError', 'true')
+		self.add(doc, target, 'useDefaultCommand', 'false')
+		self.add(doc, target, 'runAllBuilders', str(runAllBuilders).lower())
+
+	def add(self, doc, parent, tag, value = None):
+		el = doc.createElement(tag)
+		if (value):
+			if type(value) == type(str()):
+				el.appendChild(doc.createTextNode(value))
+			elif type(value) == type(dict()):
+				self.setAttributes(el, value)
+		parent.appendChild(el)
+		return el
+
+	def setAttributes(self, node, attrs):
+		for k, v in attrs.items():
+			node.setAttribute(k, v)
+
diff --git a/xpdeint/waf/waflib/extras/erlang.py b/xpdeint/waf/waflib/extras/erlang.py
new file mode 100644
index 0000000..b6349fe
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/erlang.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2010 (ita)
+
+"""
+Erlang support
+"""
+
+from waflib import TaskGen
+
+TaskGen.declare_chain(name = 'erlc',
+	rule      = '${ERLC} ${ERLC_FLAGS} ${SRC[0].abspath()} -o ${TGT[0].name}',
+	ext_in    = '.erl',
+	ext_out   = '.beam')
+
+def configure(conf):
+	conf.find_program('erlc', var='ERLC')
+	conf.env.ERLC_FLAGS = []
+
diff --git a/xpdeint/waf/waflib/extras/fc_bgxlf.py b/xpdeint/waf/waflib/extras/fc_bgxlf.py
new file mode 100644
index 0000000..9ba4b14
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/fc_bgxlf.py
@@ -0,0 +1,33 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# harald at klimachs.de
+
+import re
+from waflib.Tools import fc, fc_config, fc_scan
+from waflib.Configure import conf
+
+from waflib.Tools.compiler_fc import fc_compiler
+fc_compiler['linux'].insert(0, 'fc_bgxlf')
+
+ at conf
+def find_bgxlf(conf):
+	fc = conf.find_program(['bgxlf2003_r','bgxlf2003'], var='FC')
+	fc = conf.cmd_to_list(fc)
+	conf.get_xlf_version(fc)
+	conf.env.FC_NAME = 'BGXLF'
+
+ at conf
+def bg_flags(self):
+	self.env.SONAME_ST		 = ''
+	self.env.FCSHLIB_MARKER	= ''
+	self.env.FCSTLIB_MARKER	= ''
+	self.env.FCFLAGS_fcshlib   = ['-fPIC']
+	self.env.LINKFLAGS_fcshlib = ['-G', '-Wl,-bexpfull']
+
+def configure(conf):
+	conf.find_bgxlf()
+	conf.find_ar()
+	conf.fc_flags()
+	conf.xlf_flags()
+	conf.bg_flags()
+
diff --git a/xpdeint/waf/waflib/extras/fc_cray.py b/xpdeint/waf/waflib/extras/fc_cray.py
new file mode 100644
index 0000000..2100217
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/fc_cray.py
@@ -0,0 +1,50 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# harald at klimachs.de
+
+import re
+from waflib import Utils
+from waflib.Tools import fc, fc_config, fc_scan
+from waflib.Configure import conf
+
+from waflib.Tools.compiler_fc import fc_compiler
+fc_compiler['linux'].append('fc_cray')
+
+ at conf
+def find_crayftn(conf):
+	"""Find the Cray fortran compiler (will look in the environment variable 'FC')"""
+	fc = conf.find_program(['crayftn'], var='FC')
+	fc = conf.cmd_to_list(fc)
+	conf.get_crayftn_version(fc)
+	conf.env.FC_NAME = 'CRAY'
+	conf.env.FC_MOD_CAPITALIZATION = 'UPPER.mod'
+
+ at conf
+def crayftn_flags(conf):
+	v = conf.env
+	v['_FCMODOUTFLAGS']  = ['-em', '-J.'] # enable module files and put them in the current directoy
+	v['FCFLAGS_DEBUG'] = ['-m1'] # more verbose compiler warnings
+	v['FCFLAGS_fcshlib']   = ['-h pic']
+	v['LINKFLAGS_fcshlib'] = ['-h shared']
+
+	v['FCSTLIB_MARKER'] = '-h static'
+	v['FCSHLIB_MARKER'] = '-h dynamic'
+
+ at conf
+def get_crayftn_version(conf, fc):
+		version_re = re.compile(r"Cray Fortran\s*:\s*Version\s*(?P<major>\d*)\.(?P<minor>\d*)", re.I).search
+		cmd = fc + ['-V']
+		out,err = fc_config.getoutput(conf, cmd, stdin=False)
+		if out: match = version_re(out)
+		else: match = version_re(err)
+		if not match:
+				conf.fatal('Could not determine the Cray Fortran compiler version.')
+		k = match.groupdict()
+		conf.env['FC_VERSION'] = (k['major'], k['minor'])
+
+def configure(conf):
+	conf.find_crayftn()
+	conf.find_ar()
+	conf.fc_flags()
+	conf.crayftn_flags()
+
diff --git a/xpdeint/waf/waflib/extras/fc_open64.py b/xpdeint/waf/waflib/extras/fc_open64.py
new file mode 100644
index 0000000..eb3c028
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/fc_open64.py
@@ -0,0 +1,56 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# harald at klimachs.de
+
+import re
+from waflib import Utils
+from waflib.Tools import fc,fc_config,fc_scan
+from waflib.Configure import conf
+
+from waflib.Tools.compiler_fc import fc_compiler
+fc_compiler['linux'].insert(0, 'fc_open64')
+
+ at conf
+def find_openf95(conf):
+	"""Find the Open64 Fortran Compiler (will look in the environment variable 'FC')"""
+
+	fc = conf.find_program(['openf95', 'openf90'], var='FC')
+	fc = conf.cmd_to_list(fc)
+	conf.get_open64_version(fc)
+	conf.env.FC_NAME = 'OPEN64'
+	conf.env.FC_MOD_CAPITALIZATION = 'UPPER.mod'
+
+ at conf
+def openf95_flags(conf):
+	v = conf.env
+	v['FCFLAGS_DEBUG'] = ['-fullwarn']
+
+ at conf
+def openf95_modifier_platform(conf):
+	dest_os = conf.env['DEST_OS'] or Utils.unversioned_sys_platform()
+	openf95_modifier_func = getattr(conf, 'openf95_modifier_' + dest_os, None)
+	if openf95_modifier_func:
+		openf95_modifier_func()
+
+ at conf
+def get_open64_version(conf, fc):
+	"""Get the Open64 compiler version"""
+
+	version_re = re.compile(r"Open64 Compiler Suite: *Version *(?P<major>\d*)\.(?P<minor>\d*)", re.I).search
+	cmd = fc + ['-version']
+
+	out, err = fc_config.getoutput(conf,cmd,stdin=False)
+	if out: match = version_re(out)
+	else: match = version_re(err)
+	if not match:
+		conf.fatal('Could not determine the Open64 version.')
+	k = match.groupdict()
+	conf.env['FC_VERSION'] = (k['major'], k['minor'])
+
+def configure(conf):
+	conf.find_openf95()
+	conf.find_ar()
+	conf.fc_flags()
+	conf.openf95_flags()
+	conf.openf95_modifier_platform()
+
diff --git a/xpdeint/waf/waflib/extras/fc_pgfortran.py b/xpdeint/waf/waflib/extras/fc_pgfortran.py
new file mode 100644
index 0000000..1907966
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/fc_pgfortran.py
@@ -0,0 +1,65 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# harald at klimachs.de
+
+import re
+from waflib import Utils
+from waflib.Tools import fc, fc_config, fc_scan
+from waflib.Configure import conf
+
+from waflib.Tools.compiler_fc import fc_compiler
+fc_compiler['linux'].append('fc_pgfortran')
+
+ at conf
+def find_pgfortran(conf):
+	"""Find the PGI fortran compiler (will look in the environment variable 'FC')"""
+	fc = conf.find_program(['pgfortran', 'pgf95', 'pgf90'], var='FC')
+	fc = conf.cmd_to_list(fc)
+	conf.get_pgfortran_version(fc)
+	conf.env.FC_NAME = 'PGFC'
+
+ at conf
+def pgfortran_flags(conf):
+	v = conf.env
+	v['FCFLAGS_fcshlib']   = ['-shared']
+	v['FCFLAGS_DEBUG'] = ['-Minform=inform', '-Mstandard'] # why not
+	v['FCSTLIB_MARKER'] = '-Bstatic'
+	v['FCSHLIB_MARKER'] = '-Bdynamic'
+	v['SONAME_ST']	  = '-soname %s'
+
+ at conf
+def get_pgfortran_version(conf,fc):
+		version_re = re.compile(r"The Portland Group", re.I).search
+		cmd = fc + ['-V']
+		out,err = fc_config.getoutput(conf, cmd, stdin=False)
+		if out: match = version_re(out)
+		else: match = version_re(err)
+		if not match:
+				conf.fatal('Could not verify PGI signature')
+		cmd = fc + ['-help=variable']
+		out,err = fc_config.getoutput(conf, cmd, stdin=False)
+		if out.find('COMPVER')<0:
+				conf.fatal('Could not determine the compiler type')
+		k = {}
+		prevk = ''
+		out = out.split('\n')
+		for line in out:
+				lst = line.partition('=')
+				if lst[1] == '=':
+						key = lst[0].rstrip()
+						if key == '': key = prevk
+						val = lst[2].rstrip()
+						k[key] = val
+				else: prevk = line.partition(' ')[0]
+		def isD(var):
+				return var in k
+		def isT(var):
+				return var in k and k[var]!='0'
+		conf.env['FC_VERSION'] = (k['COMPVER'].split('.'))
+
+def configure(conf):
+	conf.find_pgfortran()
+	conf.find_ar()
+	conf.fc_flags()
+	conf.pgfortran_flags()
+
diff --git a/xpdeint/waf/waflib/extras/fc_solstudio.py b/xpdeint/waf/waflib/extras/fc_solstudio.py
new file mode 100644
index 0000000..e30e8f3
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/fc_solstudio.py
@@ -0,0 +1,60 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# harald at klimachs.de
+
+import re
+from waflib import Utils
+from waflib.Tools import fc,fc_config,fc_scan
+from waflib.Configure import conf
+
+from waflib.Tools.compiler_fc import fc_compiler
+fc_compiler['linux'].append('fc_solstudio')
+
+ at conf
+def find_solstudio(conf):
+	"""Find the Solaris Studio compiler (will look in the environment variable 'FC')"""
+
+	fc = conf.find_program(['sunf95', 'f95', 'sunf90', 'f90'], var='FC')
+	fc = conf.cmd_to_list(fc)
+	conf.get_solstudio_version(fc)
+	conf.env.FC_NAME = 'SOL'
+
+ at conf
+def solstudio_flags(conf):
+	v = conf.env
+	v['FCFLAGS_fcshlib'] = ['-Kpic']
+	v['FCFLAGS_DEBUG'] = ['-w3']
+	v['LINKFLAGS_fcshlib'] = ['-G']
+	v['FCSTLIB_MARKER'] = '-Bstatic'
+	v['FCSHLIB_MARKER'] = '-Bdynamic'
+	v['SONAME_ST']      = '-h %s'
+
+ at conf
+def solstudio_modifier_platform(conf):
+	dest_os = conf.env['DEST_OS'] or Utils.unversioned_sys_platform()
+	solstudio_modifier_func = getattr(conf, 'solstudio_modifier_' + dest_os, None)
+	if solstudio_modifier_func:
+		solstudio_modifier_func()
+
+ at conf
+def get_solstudio_version(conf, fc):
+	"""Get the compiler version"""
+
+	version_re = re.compile(r"Sun Fortran 95 *(?P<major>\d*)\.(?P<minor>\d*)", re.I).search
+	cmd = fc + ['-V']
+
+	out, err = fc_config.getoutput(conf,cmd,stdin=False)
+	if out: match = version_re(out)
+	else: match = version_re(err)
+	if not match:
+		conf.fatal('Could not determine the Sun Studio Fortran version.')
+	k = match.groupdict()
+	conf.env['FC_VERSION'] = (k['major'], k['minor'])
+
+def configure(conf):
+	conf.find_solstudio()
+	conf.find_ar()
+	conf.fc_flags()
+	conf.solstudio_flags()
+	conf.solstudio_modifier_platform()
+
diff --git a/xpdeint/waf/waflib/extras/fc_xlf.py b/xpdeint/waf/waflib/extras/fc_xlf.py
new file mode 100644
index 0000000..9e0ea4d
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/fc_xlf.py
@@ -0,0 +1,58 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# harald at klimachs.de
+
+import re
+from waflib import Utils
+from waflib.Tools import fc,fc_config,fc_scan
+from waflib.Configure import conf
+
+from waflib.Tools.compiler_fc import fc_compiler
+fc_compiler['aix'].insert(0, 'fc_xlf')
+
+ at conf
+def find_xlf(conf):
+	"""Find the xlf program (will look in the environment variable 'FC')"""
+
+	fc = conf.find_program(['xlf2003_r', 'xlf2003', 'xlf95_r', 'xlf95', 'xlf90_r', 'xlf90', 'xlf_r', 'xlf'], var='FC')
+	fc = conf.cmd_to_list(fc)
+	conf.get_xlf_version(fc)
+	conf.env.FC_NAME='XLF'
+
+ at conf
+def xlf_flags(conf):
+	v = conf.env
+	v['FCDEFINES_ST'] = '-WF,-D%s'
+	v['FCFLAGS_fcshlib'] = ['-qpic=small']
+	v['FCFLAGS_DEBUG'] = ['-qhalt=w']
+	v['LINKFLAGS_fcshlib'] = ['-Wl,-shared']
+
+ at conf
+def xlf_modifier_platform(conf):
+	dest_os = conf.env['DEST_OS'] or Utils.unversioned_sys_platform()
+	xlf_modifier_func = getattr(conf, 'xlf_modifier_' + dest_os, None)
+	if xlf_modifier_func:
+		xlf_modifier_func()
+
+ at conf
+def get_xlf_version(conf, fc):
+	"""Get the compiler version"""
+
+	version_re = re.compile(r"IBM XL Fortran.*, V(?P<major>\d*)\.(?P<minor>\d*)", re.I).search
+	cmd = fc + ['-qversion']
+
+	out, err = fc_config.getoutput(conf,cmd,stdin=False)
+	if out: match = version_re(out)
+	else: match = version_re(err)
+	if not match:
+		conf.fatal('Could not determine the XLF version.')
+	k = match.groupdict()
+	conf.env['FC_VERSION'] = (k['major'], k['minor'])
+
+def configure(conf):
+	conf.find_xlf()
+	conf.find_ar()
+	conf.fc_flags()
+	conf.xlf_flags()
+	conf.xlf_modifier_platform()
+
diff --git a/xpdeint/waf/waflib/extras/fluid.py b/xpdeint/waf/waflib/extras/fluid.py
new file mode 100644
index 0000000..075a0c4
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/fluid.py
@@ -0,0 +1,30 @@
+#!/usr/bin/python
+# encoding: utf-8
+# Grygoriy Fuchedzhy 2009
+
+"""
+Compile fluid files (fltk graphic library). Use the 'fluid' feature in conjuction with the 'cxx' feature.
+"""
+
+from waflib import Task
+from waflib.TaskGen import extension
+
+class fluid(Task.Task):
+	color   = 'BLUE'
+	ext_out = ['.h']
+	run_str = '${FLUID} -c -o ${TGT[0].abspath()} -h ${TGT[1].abspath()} ${SRC}'
+
+ at extension('.fl')
+def fluid(self, node):
+	"""add the .fl to the source list; the cxx file generated will be compiled when possible"""
+	cpp = node.change_ext('.cpp')
+	hpp = node.change_ext('.hpp')
+	self.create_task('fluid', node, [cpp, hpp])
+
+	if 'cxx' in self.features:
+		self.source.append(cpp)
+
+def configure(conf):
+	conf.find_program('fluid', var='FLUID')
+	conf.check_cfg(path='fltk-config', package='', args='--cxxflags --ldflags', uselib_store='FLTK', mandatory=True)
+
diff --git a/xpdeint/waf/waflib/extras/freeimage.py b/xpdeint/waf/waflib/extras/freeimage.py
new file mode 100644
index 0000000..f27e525
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/freeimage.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+# encoding: utf-8
+#
+# written by Sylvain Rouquette, 2011
+
+'''
+To add the freeimage tool to the waf file:
+$ ./waf-light --tools=compat15,freeimage
+	or, if you have waf >= 1.6.2
+$ ./waf update --files=freeimage
+
+The wscript will look like:
+
+def options(opt):
+	opt.load('compiler_cxx freeimage')
+
+def configure(conf):
+	conf.load('compiler_cxx freeimage')
+
+	# you can call check_freeimage with some parameters.
+	# It's optional on Linux, it's 'mandatory' on Windows if
+	# you didn't use --fi-path on the command-line
+
+	# conf.check_freeimage(path='FreeImage/Dist', fip=True)
+
+def build(bld):
+	bld(source='main.cpp', target='app', use='FREEIMAGE')
+'''
+
+from waflib import Utils
+from waflib.Configure import conf
+
+
+def options(opt):
+	opt.add_option('--fi-path', type='string', default='', dest='fi_path',
+				   help='''path to the FreeImage directory \
+						where the files are e.g. /FreeImage/Dist''')
+	opt.add_option('--fip', action='store_true', default=False, dest='fip',
+				   help='link with FreeImagePlus')
+	opt.add_option('--fi-static', action='store_true',
+				   default=False, dest='fi_static',
+				   help="link as shared libraries")
+
+
+ at conf
+def check_freeimage(self, path=None, fip=False):
+	self.start_msg('Checking FreeImage')
+	if not self.env['CXX']:
+		self.fatal('you must load compiler_cxx before loading freeimage')
+	prefix = self.options.fi_static and 'ST' or ''
+	platform = Utils.unversioned_sys_platform()
+	if platform == 'win32':
+		if not path:
+			self.fatal('you must specify the path to FreeImage. \
+					   use --fi-path=/FreeImage/Dist')
+		else:
+			self.env['INCLUDES_FREEIMAGE'] = path
+			self.env['%sLIBPATH_FREEIMAGE' % prefix] = path
+	libs = ['FreeImage']
+	if self.options.fip:
+		libs.append('FreeImagePlus')
+	if platform == 'win32':
+		self.env['%sLIB_FREEIMAGE' % prefix] = libs
+	else:
+		self.env['%sLIB_FREEIMAGE' % prefix] = [i.lower() for i in libs]
+	self.end_msg('ok')
+
+
+def configure(conf):
+	platform = Utils.unversioned_sys_platform()
+	if platform == 'win32' and not conf.options.fi_path:
+		return
+	conf.check_freeimage(conf.options.fi_path, conf.options.fip)
+
diff --git a/xpdeint/waf/waflib/extras/fsb.py b/xpdeint/waf/waflib/extras/fsb.py
new file mode 100644
index 0000000..1b8f398
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/fsb.py
@@ -0,0 +1,31 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2011 (ita)
+
+"""
+Fully sequential builds
+
+The previous tasks from task generators are re-processed, and this may lead to speed issues
+Yet, if you are using this, speed is probably a minor concern
+"""
+
+from waflib import Build
+
+def options(opt):
+	pass
+
+def configure(conf):
+	pass
+
+class FSBContext(Build.BuildContext):
+	def __call__(self, *k, **kw):
+		ret = Build.BuildContext.__call__(self, *k, **kw)
+
+		# evaluate the results immediately
+		Build.BuildContext.compile(self)
+
+		return ret
+
+	def compile(self):
+		pass
+
diff --git a/xpdeint/waf/waflib/extras/fsc.py b/xpdeint/waf/waflib/extras/fsc.py
new file mode 100644
index 0000000..150e675
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/fsc.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2011 (ita)
+
+"""
+Experimental F# stuff
+
+FSC="mono /path/to/fsc.exe" waf configure build
+"""
+
+from waflib import Utils, Task, Options, Logs, Errors
+from waflib.TaskGen import before_method, after_method, feature
+from waflib.Tools import ccroot, cs
+from waflib.Configure import conf
+
+ccroot.USELIB_VARS['fsc'] = set(['CSFLAGS', 'ASSEMBLIES', 'RESOURCES'])
+
+ at feature('fs')
+ at before_method('process_source')
+def apply_fsc(self):
+	cs_nodes = []
+	no_nodes = []
+	for x in self.to_nodes(self.source):
+		if x.name.endswith('.fs'):
+			cs_nodes.append(x)
+		else:
+			no_nodes.append(x)
+	self.source = no_nodes
+
+	bintype = getattr(self, 'type', self.gen.endswith('.dll') and 'library' or 'exe')
+	self.cs_task = tsk = self.create_task('fsc', cs_nodes, self.path.find_or_declare(self.gen))
+	tsk.env.CSTYPE = '/target:%s' % bintype
+	tsk.env.OUT    = '/out:%s' % tsk.outputs[0].abspath()
+
+	inst_to = getattr(self, 'install_path', bintype=='exe' and '${BINDIR}' or '${LIBDIR}')
+	if inst_to:
+		# note: we are making a copy, so the files added to cs_task.outputs won't be installed automatically
+		mod = getattr(self, 'chmod', bintype=='exe' and Utils.O755 or Utils.O644)
+		self.install_task = self.bld.install_files(inst_to, self.cs_task.outputs[:], env=self.env, chmod=mod)
+
+feature('fs')(cs.use_cs)
+after_method('apply_fsc')(cs.use_cs)
+
+feature('fs')(cs.debug_cs)
+after_method('apply_fsc', 'use_cs')(cs.debug_cs)
+
+class fsc(Task.Task):
+	"""
+	Compile F# files
+	"""
+	color   = 'YELLOW'
+	run_str = '${FSC} ${CSTYPE} ${CSFLAGS} ${ASS_ST:ASSEMBLIES} ${RES_ST:RESOURCES} ${OUT} ${SRC}'
+
+def configure(conf):
+	"""
+	Find a F# compiler, set the variable FSC for the compiler and FS_NAME (mono or fsc)
+	"""
+	conf.find_program(['fsc.exe', 'fsharpc'], var='FSC')
+	conf.env.FSC = conf.cmd_to_list(conf.env.FSC)
+	conf.env.ASS_ST = '/r:%s'
+	conf.env.RES_ST = '/resource:%s'
+
+	conf.env.CS_NAME = 'fsc'
+	if str(conf.env.FSC).lower().find('fsharpc') > -1:
+		conf.env.CS_NAME = 'mono'
+
diff --git a/xpdeint/waf/waflib/extras/gccdeps.py b/xpdeint/waf/waflib/extras/gccdeps.py
new file mode 100644
index 0000000..8b218f7
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/gccdeps.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2008-2010 (ita)
+
+"""
+Execute the tasks with gcc -MD, read the dependencies from the .d file
+and prepare the dependency calculation for the next run
+"""
+
+import os, re, threading
+from waflib import Task, Logs, Utils, Errors
+from waflib.Tools import c_preproc
+from waflib.TaskGen import before_method, after_method, feature
+
+lock = threading.Lock()
+
+preprocessor_flag = '-MD'
+
+ at feature('cc')
+ at before_method('apply_core')
+def add_mmd_cc(self):
+	if self.env.get_flat('CFLAGS').find(preprocessor_flag) < 0:
+		self.env.append_value('CFLAGS', [preprocessor_flag])
+
+ at feature('cxx')
+ at before_method('apply_core')
+def add_mmd_cxx(self):
+	if self.env.get_flat('CXXFLAGS').find(preprocessor_flag) < 0:
+		self.env.append_value('CXXFLAGS', [preprocessor_flag])
+
+def scan(self):
+	"the scanner does not do anything initially"
+	nodes = self.generator.bld.node_deps.get(self.uid(), [])
+	names = []
+	return (nodes, names)
+
+re_o = re.compile("\.o$")
+def post_run(self):
+	# The following code is executed by threads, it is not safe, so a lock is needed...
+
+	if getattr(self, 'cached', None):
+		return Task.Task.post_run(self)
+
+	name = self.outputs[0].abspath()
+	name = re_o.sub('.d', name)
+	txt = Utils.readf(name)
+	#os.unlink(name)
+
+	txt = txt.replace('\\\n', '')
+
+	lst = txt.strip().split(':')
+	val = ":".join(lst[1:])
+	val = val.split()
+
+	nodes = []
+	bld = self.generator.bld
+
+	f = re.compile("^(\.\.)[\\/](.*)$")
+	for x in val:
+
+		node = None
+		if os.path.isabs(x):
+
+			if not c_preproc.go_absolute:
+				continue
+
+			lock.acquire()
+			try:
+				node = bld.root.find_resource(x)
+			finally:
+				lock.release()
+		else:
+			path = bld.bldnode
+			x = [k for k in Utils.split_path(x) if k and k != '.']
+			while lst and x[0] == '..':
+				x = x[1:]
+				path = path.parent
+
+			# when calling find_resource, make sure the path does not begin by '..'
+			try:
+				lock.acquire()
+				node = path.find_resource(x)
+			finally:
+				lock.release()
+
+		if not node:
+			raise ValueError('could not find %r for %r' % (x, self))
+		else:
+			if id(node) == id(self.inputs[0]):
+				# ignore the source file, it is already in the dependencies
+				# this way, successful config tests may be retrieved from the cache
+				continue
+
+			nodes.append(node)
+
+	Logs.debug('deps: real scanner for %s returned %s' % (str(self), str(nodes)))
+
+	bld.node_deps[self.uid()] = nodes
+	bld.raw_deps[self.uid()] = []
+
+	try:
+		del self.cache_sig
+	except:
+		pass
+
+	Task.Task.post_run(self)
+
+def sig_implicit_deps(self):
+	try:
+		return Task.Task.sig_implicit_deps(self)
+	except Errors.WafError:
+		return Utils.SIG_NIL
+
+for name in 'cc cxx'.split():
+	try:
+		cls = Task.classes[name]
+	except KeyError:
+		pass
+	else:
+		cls.post_run = post_run
+		cls.scan = scan
+		cls.sig_implicit_deps = sig_implicit_deps
+
diff --git a/xpdeint/waf/waflib/extras/go.py b/xpdeint/waf/waflib/extras/go.py
new file mode 100644
index 0000000..5f04247
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/go.py
@@ -0,0 +1,262 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Tom Wambold tom5760 gmail.com 2009
+# Thomas Nagy 2010
+
+"""
+Go as a language may look nice, but its toolchain is one of the worse a developer
+has ever seen. It keeps changing though, and I would like to believe that it will get
+better eventually, but the crude reality is that this tool and the examples are
+getting broken every few months.
+
+If you have been lured into trying to use Go, you should stick to their Makefiles.
+"""
+
+import os, platform
+
+from waflib import Utils, Task, TaskGen
+from waflib.TaskGen import feature, extension, after_method, before_method
+from waflib.Tools.ccroot import link_task, stlink_task, propagate_uselib_vars, process_use
+
+class go(Task.Task):
+	run_str = '${GOC} ${GOCFLAGS} ${CPPPATH_ST:INCPATHS} -o ${TGT} ${SRC}'
+
+class gopackage(stlink_task):
+	run_str = '${GOP} grc ${TGT} ${SRC}'
+
+class goprogram(link_task):
+	run_str = '${GOL} ${GOLFLAGS} -o ${TGT} ${SRC}'
+	inst_to = '${BINDIR}'
+	chmod   = Utils.O755
+
+class cgopackage(stlink_task):
+	color   = 'YELLOW'
+	inst_to = '${LIBDIR}'
+	ext_in  = ['.go']
+	ext_out = ['.a']
+
+	def run(self):
+		src_dir = self.generator.bld.path
+		source  = self.inputs
+		target  = self.outputs[0].change_ext('')
+
+		#print ("--> %s" % self.outputs)
+		#print ('++> %s' % self.outputs[1])
+		bld_dir = self.outputs[1]
+		bld_dir.mkdir()
+		obj_dir = bld_dir.make_node('_obj')
+		obj_dir.mkdir()
+
+		bld_srcs = []
+		for s in source:
+			# FIXME: it seems gomake/cgo stumbles on filenames like a/b/c.go
+			# -> for the time being replace '/' with '_'...
+			#b = bld_dir.make_node(s.path_from(src_dir))
+			b = bld_dir.make_node(s.path_from(src_dir).replace(os.sep,'_'))
+			b.parent.mkdir()
+			#print ('++> %s' % (s.path_from(src_dir),))
+			try:
+				try:os.remove(b.abspath())
+				except Exception:pass
+				os.symlink(s.abspath(), b.abspath())
+			except Exception:
+				# if no support for symlinks, copy the file from src
+				b.write(s.read())
+			bld_srcs.append(b)
+			#print("--|> [%s]" % b.abspath())
+			b.sig = Utils.h_file(b.abspath())
+			pass
+		#self.set_inputs(bld_srcs)
+		#self.generator.bld.raw_deps[self.uid()] = [self.signature()] + bld_srcs
+		makefile_node = bld_dir.make_node("Makefile")
+		makefile_tmpl = '''\
+# Copyright 2009 The Go Authors.  All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file. ---
+
+include $(GOROOT)/src/Make.inc
+
+TARG=%(target)s
+
+GCIMPORTS= %(gcimports)s
+
+CGOFILES=\\
+\t%(source)s
+
+CGO_CFLAGS= %(cgo_cflags)s
+
+CGO_LDFLAGS= %(cgo_ldflags)s
+
+include $(GOROOT)/src/Make.pkg
+
+%%: install %%.go
+	$(GC) $*.go
+	$(LD) -o $@ $*.$O
+
+''' % {
+'gcimports': ' '.join(l for l in self.env['GOCFLAGS']),
+'cgo_cflags' : ' '.join(l for l in self.env['GOCFLAGS']),
+'cgo_ldflags': ' '.join(l for l in self.env['GOLFLAGS']),
+'target': target.path_from(obj_dir),
+'source': ' '.join([b.path_from(bld_dir) for b in bld_srcs])
+}
+		makefile_node.write(makefile_tmpl)
+		#print ("::makefile: %s"%makefile_node.abspath())
+		cmd = Utils.subst_vars('gomake ${GOMAKE_FLAGS}', self.env).strip()
+		o = self.outputs[0].change_ext('.gomake.log')
+		fout_node = bld_dir.find_or_declare(o.name)
+		fout = open(fout_node.abspath(), 'w')
+		rc = self.generator.bld.exec_command(
+		    cmd,
+		    stdout=fout,
+           stderr=fout,
+           cwd=bld_dir.abspath(),
+		)
+		if rc != 0:
+			import waflib.Logs as msg
+			msg.error('** error running [%s] (cgo-%s)' % (cmd, target))
+			msg.error(fout_node.read())
+			return rc
+		self.generator.bld.read_stlib(
+			target,
+			paths=[obj_dir.abspath(),],
+			)
+		tgt = self.outputs[0]
+		if tgt.parent != obj_dir:
+			install_dir = os.path.join('${LIBDIR}',
+				tgt.parent.path_from(obj_dir))
+		else:
+			install_dir = '${LIBDIR}'
+		#print('===> %s (%s)' % (tgt.abspath(), install_dir))
+		self.generator.bld.install_files(
+            install_dir,
+            tgt.abspath(),
+            relative_trick=False,
+            postpone=False,
+			)
+		return rc
+
+ at extension('.go')
+def compile_go(self, node):
+	#print('*'*80, self.name)
+	if not ('cgopackage' in self.features):
+		return self.create_compiled_task('go', node)
+	#print ('compile_go-cgo...')
+	bld_dir = node.parent.get_bld()
+	obj_dir = bld_dir.make_node('_obj')
+	target  = obj_dir.make_node(node.change_ext('.a').name)
+	return self.create_task('cgopackage',
+							node,
+							node.change_ext('.a'))
+
+ at feature('gopackage', 'goprogram', 'cgopackage')
+ at before_method('process_source')
+def go_compiler_is_foobar(self):
+	if self.env.GONAME == 'gcc':
+		return
+	self.source = self.to_nodes(self.source)
+	src = []
+	go = []
+	for node in self.source:
+		if node.name.endswith('.go'):
+			go.append(node)
+		else:
+			src.append(node)
+	self.source = src
+	if not ('cgopackage' in self.features):
+		#print('--> [%s]... (%s)' % (go[0], getattr(self, 'target', 'N/A')))
+		tsk = self.create_compiled_task('go', go[0])
+		tsk.inputs.extend(go[1:])
+	else:
+		#print ('+++ [%s] +++' % self.target)
+		bld_dir = self.path.get_bld().make_node('cgopackage--%s' %
+												self.target.replace(os.sep,'_'))
+		obj_dir = bld_dir.make_node('_obj')
+		target  = obj_dir.make_node(self.target+'.a')
+		tsk = self.create_task('cgopackage',
+							   go,
+							   [target, bld_dir])
+		self.link_task = tsk
+
+ at feature('gopackage', 'goprogram', 'cgopackage')
+ at after_method('process_source', 'apply_incpaths',)
+def go_local_libs(self):
+	names = self.to_list(getattr(self, 'use', []))
+	#print ('== go-local-libs == [%s] == use: %s' % (self.name, names))
+	for name in names:
+		tg = self.bld.get_tgen_by_name(name)
+		if not tg:
+			raise Utils.WafError('no target of name %r necessary for %r in go uselib local' % (name, self))
+		tg.post()
+		#print ("-- tg[%s]: %s" % (self.name,name))
+		lnk_task = getattr(tg, 'link_task', None)
+		if lnk_task:
+			for tsk in self.tasks:
+				if isinstance(tsk, (go, gopackage, cgopackage)):
+					tsk.set_run_after(lnk_task)
+					tsk.dep_nodes.extend(lnk_task.outputs)
+			path = lnk_task.outputs[0].parent.abspath()
+			if isinstance(lnk_task, (go, gopackage)):
+				# handle hierarchical packages
+				path = lnk_task.generator.path.get_bld().abspath()
+			elif isinstance(lnk_task, (cgopackage,)):
+				# handle hierarchical cgopackages
+				cgo_obj_dir = lnk_task.outputs[1].find_or_declare('_obj')
+				path = cgo_obj_dir.abspath()
+			# recursively add parent GOCFLAGS...
+			self.env.append_unique('GOCFLAGS',
+                                   getattr(lnk_task.env, 'GOCFLAGS',[]))
+			# ditto for GOLFLAGS...
+			self.env.append_unique('GOLFLAGS',
+                                   getattr(lnk_task.env, 'GOLFLAGS',[]))
+			self.env.append_unique('GOCFLAGS', ['-I%s' % path])
+			self.env.append_unique('GOLFLAGS', ['-L%s' % path])
+		for n in getattr(tg, 'includes_nodes', []):
+			self.env.append_unique('GOCFLAGS', ['-I%s' % n.abspath()])
+		pass
+	pass
+
+def configure(conf):
+
+	def set_def(var, val):
+		if not conf.env[var]:
+			conf.env[var] = val
+
+	goarch = os.getenv('GOARCH')
+	if goarch == '386':
+		set_def('GO_PLATFORM', 'i386')
+	elif goarch == 'amd64':
+		set_def('GO_PLATFORM', 'x86_64')
+	elif goarch == 'arm':
+		set_def('GO_PLATFORM', 'arm')
+	else:
+		set_def('GO_PLATFORM', platform.machine())
+
+	if conf.env.GO_PLATFORM == 'x86_64':
+		set_def('GO_COMPILER', '6g')
+		set_def('GO_LINKER', '6l')
+	elif conf.env.GO_PLATFORM in ['i386', 'i486', 'i586', 'i686']:
+		set_def('GO_COMPILER', '8g')
+		set_def('GO_LINKER', '8l')
+	elif conf.env.GO_PLATFORM == 'arm':
+		set_def('GO_COMPILER', '5g')
+		set_def('GO_LINKER', '5l')
+		set_def('GO_EXTENSION', '.5')
+
+	if not (conf.env.GO_COMPILER or conf.env.GO_LINKER):
+		raise conf.fatal('Unsupported platform ' + platform.machine())
+
+	set_def('GO_PACK', 'gopack')
+	set_def('gopackage_PATTERN', '%s.a')
+	set_def('CPPPATH_ST', '-I%s')
+
+	set_def('GOMAKE_FLAGS', ['--quiet'])
+	conf.find_program(conf.env.GO_COMPILER, var='GOC')
+	conf.find_program(conf.env.GO_LINKER,   var='GOL')
+	conf.find_program(conf.env.GO_PACK,     var='GOP')
+
+	conf.find_program('cgo',                var='CGO')
+
+TaskGen.feature('go')(process_use)
+TaskGen.feature('go')(propagate_uselib_vars)
+
diff --git a/xpdeint/waf/waflib/extras/gob2.py b/xpdeint/waf/waflib/extras/gob2.py
new file mode 100644
index 0000000..b4fa3b9
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/gob2.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Ali Sabil, 2007
+
+from waflib import TaskGen
+
+TaskGen.declare_chain(
+	name = 'gob2',
+	rule = '${GOB2} -o ${TGT[0].bld_dir()} ${GOB2FLAGS} ${SRC}',
+	ext_in = '.gob',
+	ext_out = '.c'
+)
+
+def configure(conf):
+	conf.find_program('gob2', var='GOB2')
+	conf.env['GOB2FLAGS'] = ''
+
diff --git a/xpdeint/waf/waflib/extras/local_rpath.py b/xpdeint/waf/waflib/extras/local_rpath.py
new file mode 100644
index 0000000..b2507e1
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/local_rpath.py
@@ -0,0 +1,19 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2011 (ita)
+
+from waflib.TaskGen import after_method, feature
+
+ at after_method('propagate_uselib_vars')
+ at feature('cprogram', 'cshlib', 'cxxprogram', 'cxxshlib', 'fcprogram', 'fcshlib')
+def add_rpath_stuff(self):
+	all = self.to_list(getattr(self, 'use', []))
+	while all:
+		name = all.pop()
+		try:
+			tg = self.bld.get_tgen_by_name(name)
+		except:
+			continue
+		self.env.append_value('RPATH', tg.link_task.outputs[0].parent.abspath())
+		all.extend(self.to_list(getattr(tg, 'use', [])))
+
diff --git a/xpdeint/waf/waflib/extras/lru_cache.py b/xpdeint/waf/waflib/extras/lru_cache.py
new file mode 100644
index 0000000..2bc9644
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/lru_cache.py
@@ -0,0 +1,98 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy 2011
+
+import os, shutil, re
+from waflib import Options, Build, Logs
+
+"""
+Apply a least recently used policy to the Waf cache.
+
+For performance reasons, it is called after the build is complete.
+
+We assume that the the folders are written atomically
+
+Do export WAFCACHE=/tmp/foo_xyz where xyz represents the cache size in bytes
+If missing, the default cache size will be set to 10GB
+"""
+
+re_num = re.compile('[a-zA-Z_-]+(\d+)')
+
+CACHESIZE = 10*1024*1024*1024 # in bytes
+CLEANRATIO = 0.8
+DIRSIZE = 4096
+
+def compile(self):
+	if Options.cache_global and not Options.options.nocache:
+		try:
+			os.makedirs(Options.cache_global)
+		except:
+			pass
+
+	try:
+		self.raw_compile()
+	finally:
+		if Options.cache_global and not Options.options.nocache:
+			self.sweep()
+
+def sweep(self):
+	global CACHESIZE
+	CACHEDIR = Options.cache_global
+
+	# get the cache max size from the WAFCACHE filename
+	re_num = re.compile('[a-zA-Z_]+(\d+)')
+	val = re_num.sub('\\1', os.path.basename(Options.cache_global))
+	try:
+		CACHESIZE = int(val)
+	except:
+		pass
+
+	# map folder names to timestamps
+	flist = {}
+	for x in os.listdir(CACHEDIR):
+		j = os.path.join(CACHEDIR, x)
+		if os.path.isdir(j) and len(x) == 64: # dir names are md5 hexdigests
+			flist[x] = [os.stat(j).st_mtime, 0]
+
+	for (x, v) in flist.items():
+		cnt = DIRSIZE # each entry takes 4kB
+		d = os.path.join(CACHEDIR, x)
+		for k in os.listdir(d):
+			cnt += os.stat(os.path.join(d, k)).st_size
+		flist[x][1] = cnt
+
+	total = sum([x[1] for x in flist.values()])
+	Logs.debug('lru: Cache size is %r' % total)
+
+	if total >= CACHESIZE:
+		Logs.debug('lru: Trimming the cache since %r > %r' % (total, CACHESIZE))
+
+		# make a list to sort the folders by timestamp
+		lst = [(p, v[0], v[1]) for (p, v) in flist.items()]
+		lst.sort(key=lambda x: x[1]) # sort by timestamp
+		lst.reverse()
+
+		while total >= CACHESIZE * CLEANRATIO:
+			(k, t, s) = lst.pop()
+			p = os.path.join(CACHEDIR, k)
+			v = p + '.del'
+			try:
+				os.rename(p, v)
+			except:
+				# someone already did it
+				pass
+			else:
+				try:
+					shutil.rmtree(v)
+				except:
+					# this should not happen, but who knows?
+					Logs.warn('If you ever see this message, report it (%r)' % v)
+			total -= s
+			del flist[k]
+
+	Logs.debug('lru: Total at the end %r' % total)
+
+Build.BuildContext.raw_compile = Build.BuildContext.compile
+Build.BuildContext.compile = compile
+Build.BuildContext.sweep = sweep
+
diff --git a/xpdeint/waf/waflib/extras/make.py b/xpdeint/waf/waflib/extras/make.py
new file mode 100644
index 0000000..57e841d
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/make.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2011 (ita)
+
+"""
+A make-like way of executing the build, following the relationships between inputs/outputs
+
+This algorithm will lead to slower builds, will not be as flexible as "waf build", but
+it might be useful for building data files (?)
+
+It is likely to break in the following cases:
+- files are created dynamically (no inputs or outputs)
+- headers
+- building two files from different groups
+"""
+
+import re
+from waflib import Options, Task, Logs
+from waflib.Build import BuildContext
+
+class MakeContext(BuildContext):
+	'''executes tasks in a step-by-step manner, following dependencies between inputs/outputs'''
+	cmd = 'make'
+	fun = 'build'
+
+	def __init__(self, **kw):
+		super(MakeContext, self).__init__(**kw)
+		self.files = Options.options.files
+
+	def get_build_iterator(self):
+		if not self.files:
+			while 1:
+				yield super(MakeContext, self).get_build_iterator()
+
+		for g in self.groups:
+			for tg in g:
+				try:
+					f = tg.post
+				except AttributeError:
+					pass
+				else:
+					f()
+
+			provides = {}
+			uses = {}
+			all_tasks = []
+			tasks = []
+			for pat in self.files.split(','):
+				matcher = self.get_matcher(pat)
+				for tg in g:
+					if isinstance(tg, Task.TaskBase):
+						lst = [tg]
+					else:
+						lst = tg.tasks
+					for tsk in lst:
+						all_tasks.append(tsk)
+
+						do_exec = False
+						for node in getattr(tsk, 'inputs', []):
+							try:
+								uses[node].append(tsk)
+							except:
+								uses[node] = [tsk]
+
+							if matcher(node, output=False):
+								do_exec = True
+								break
+
+						for node in getattr(tsk, 'outputs', []):
+							try:
+								provides[node].append(tsk)
+							except:
+								provides[node] = [tsk]
+
+							if matcher(node, output=True):
+								do_exec = True
+								break
+						if do_exec:
+							tasks.append(tsk)
+
+			# so we have the tasks that we need to process, the list of all tasks,
+			# the map of the tasks providing nodes, and the map of tasks using nodes
+
+			if not tasks:
+				# if there are no tasks matching, return everything in the current group
+				result = all_tasks
+			else:
+				# this is like a big filter...
+				result = set([])
+				seen = set([])
+				cur = set(tasks)
+				while cur:
+					result |= cur
+					tosee = set([])
+					for tsk in cur:
+						for node in getattr(tsk, 'inputs', []):
+							if node in seen:
+								continue
+							seen.add(node)
+							tosee |= set(provides.get(node, []))
+					cur = tosee
+				result = list(result)
+
+			Task.set_file_constraints(result)
+			Task.set_precedence_constraints(result)
+			yield result
+
+		while 1:
+			yield []
+
+	def get_matcher(self, pat):
+		# this returns a function
+		inn = True
+		out = True
+		if pat.startswith('in:'):
+			out = False
+			pat = pat.replace('in:', '')
+		elif pat.startswith('out:'):
+			inn = False
+			pat = pat.replace('out:', '')
+
+		anode = self.root.find_node(pat)
+		pattern = None
+		if not anode:
+			if not pat.startswith('^'):
+				pat = '^.+?%s' % pat
+			if not pat.endswith('$'):
+				pat = '%s$' % pat
+			pattern = re.compile(pat)
+
+		def match(node, output):
+			if output == True and not out:
+				return False
+			if output == False and not inn:
+				return False
+
+			if anode:
+				return anode == node
+			else:
+				return pattern.match(node.abspath())
+		return match
+
diff --git a/xpdeint/waf/waflib/extras/md5_tstamp.py b/xpdeint/waf/waflib/extras/md5_tstamp.py
new file mode 100644
index 0000000..8c67bcc
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/md5_tstamp.py
@@ -0,0 +1,69 @@
+#! /usr/bin/env python
+# encoding: utf-8
+
+"""
+Store some values on the buildcontext mapping file paths to
+stat values and md5 values (timestamp + md5)
+this way the md5 hashes are computed only when timestamp change (can be faster)
+There is usually little or no gain from enabling this, but it can be used to enable
+the second level cache with timestamps (WAFCACHE)
+
+You may have to run distclean or to remove the build directory before enabling/disabling
+this hashing scheme
+"""
+
+import os, stat
+try: import cPickle
+except: import pickle as cPickle
+from waflib import Utils, Build, Context
+
+STRONGEST = True
+Context.DBFILE += '_md5tstamp'
+
+Build.hashes_md5_tstamp = {}
+Build.SAVED_ATTRS.append('hashes_md5_tstamp')
+def store(self):
+	# save the hash cache as part of the default pickle file
+	self.hashes_md5_tstamp = Build.hashes_md5_tstamp
+	self.store_real()
+Build.BuildContext.store_real = Build.BuildContext.store
+Build.BuildContext.store      = store
+
+def restore(self):
+	# we need a module variable for h_file below
+	self.restore_real()
+	try:
+		Build.hashes_md5_tstamp = self.hashes_md5_tstamp or {}
+	except Exception as e:
+		Build.hashes_md5_tstamp = {}
+Build.BuildContext.restore_real = Build.BuildContext.restore
+Build.BuildContext.restore      = restore
+
+def h_file(filename):
+	st = os.stat(filename)
+	if stat.S_ISDIR(st[stat.ST_MODE]): raise IOError('not a file')
+
+	if filename in Build.hashes_md5_tstamp:
+		if Build.hashes_md5_tstamp[filename][0] == str(st.st_mtime):
+			return Build.hashes_md5_tstamp[filename][1]
+	m = Utils.md5()
+
+	if STRONGEST:
+		f = open(filename, 'rb')
+		read = 1
+		try:
+			while read:
+				read = f.read(100000)
+				m.update(read)
+		finally:
+			f.close()
+	else:
+		m.update(str(st.st_mtime))
+		m.update(str(st.st_size))
+		m.update(filename)
+
+	# ensure that the cache is overwritten
+	Build.hashes_md5_tstamp[filename] = (str(st.st_mtime), m.digest())
+	return m.digest()
+Utils.h_file = h_file
+
diff --git a/xpdeint/waf/waflib/extras/misc.py b/xpdeint/waf/waflib/extras/misc.py
new file mode 100644
index 0000000..e8620fb
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/misc.py
@@ -0,0 +1,416 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+
+"""
+This tool is totally deprecated
+
+Try using:
+	.pc.in files for .pc files
+	the feature intltool_in - see demos/intltool
+	make-like rules
+"""
+
+import shutil, re, os
+from waflib import TaskGen, Node, Task, Utils, Build, Errors
+from waflib.TaskGen import feature, after_method, before_method
+from waflib.Logs import debug
+
+def copy_attrs(orig, dest, names, only_if_set=False):
+	"""
+	copy class attributes from an object to another
+	"""
+	for a in Utils.to_list(names):
+		u = getattr(orig, a, ())
+		if u or not only_if_set:
+			setattr(dest, a, u)
+
+def copy_func(tsk):
+	"Make a file copy. This might be used to make other kinds of file processing (even calling a compiler is possible)"
+	env = tsk.env
+	infile = tsk.inputs[0].abspath()
+	outfile = tsk.outputs[0].abspath()
+	try:
+		shutil.copy2(infile, outfile)
+	except (OSError, IOError):
+		return 1
+	else:
+		if tsk.chmod: os.chmod(outfile, tsk.chmod)
+		return 0
+
+def action_process_file_func(tsk):
+	"Ask the function attached to the task to process it"
+	if not tsk.fun: raise Errors.WafError('task must have a function attached to it for copy_func to work!')
+	return tsk.fun(tsk)
+
+ at feature('cmd')
+def apply_cmd(self):
+	"call a command everytime"
+	if not self.fun: raise Errors.WafError('cmdobj needs a function!')
+	tsk = Task.TaskBase()
+	tsk.fun = self.fun
+	tsk.env = self.env
+	self.tasks.append(tsk)
+	tsk.install_path = self.install_path
+
+ at feature('copy')
+ at before_method('process_source')
+def apply_copy(self):
+	Utils.def_attrs(self, fun=copy_func)
+	self.default_install_path = 0
+
+	lst = self.to_list(self.source)
+	self.meths.remove('process_source')
+
+	for filename in lst:
+		node = self.path.find_resource(filename)
+		if not node: raise Errors.WafError('cannot find input file %s for processing' % filename)
+
+		target = self.target
+		if not target or len(lst)>1: target = node.name
+
+		# TODO the file path may be incorrect
+		newnode = self.path.find_or_declare(target)
+
+		tsk = self.create_task('copy', node, newnode)
+		tsk.fun = self.fun
+		tsk.chmod = getattr(self, 'chmod', Utils.O644)
+
+		if not tsk.env:
+			tsk.debug()
+			raise Errors.WafError('task without an environment')
+
+def subst_func(tsk):
+	"Substitutes variables in a .in file"
+
+	m4_re = re.compile('@(\w+)@', re.M)
+
+	code = tsk.inputs[0].read() #Utils.readf(infile)
+
+	# replace all % by %% to prevent errors by % signs in the input file while string formatting
+	code = code.replace('%', '%%')
+
+	s = m4_re.sub(r'%(\1)s', code)
+
+	env = tsk.env
+	di = getattr(tsk, 'dict', {}) or getattr(tsk.generator, 'dict', {})
+	if not di:
+		names = m4_re.findall(code)
+		for i in names:
+			di[i] = env.get_flat(i) or env.get_flat(i.upper())
+
+	tsk.outputs[0].write(s % di)
+
+ at feature('subst')
+ at before_method('process_source')
+def apply_subst(self):
+	Utils.def_attrs(self, fun=subst_func)
+	lst = self.to_list(self.source)
+	self.meths.remove('process_source')
+
+	self.dict = getattr(self, 'dict', {})
+
+	for filename in lst:
+		node = self.path.find_resource(filename)
+		if not node: raise Errors.WafError('cannot find input file %s for processing' % filename)
+
+		if self.target:
+			newnode = self.path.find_or_declare(self.target)
+		else:
+			newnode = node.change_ext('')
+
+		try:
+			self.dict = self.dict.get_merged_dict()
+		except AttributeError:
+			pass
+
+		if self.dict and not self.env['DICT_HASH']:
+			self.env = self.env.derive()
+			keys = list(self.dict.keys())
+			keys.sort()
+			lst = [self.dict[x] for x in keys]
+			self.env['DICT_HASH'] = str(Utils.h_list(lst))
+
+		tsk = self.create_task('copy', node, newnode)
+		tsk.fun = self.fun
+		tsk.dict = self.dict
+		tsk.dep_vars = ['DICT_HASH']
+		tsk.chmod = getattr(self, 'chmod', Utils.O644)
+
+		if not tsk.env:
+			tsk.debug()
+			raise Errors.WafError('task without an environment')
+
+####################
+## command-output ####
+####################
+
+class cmd_arg(object):
+	"""command-output arguments for representing files or folders"""
+	def __init__(self, name, template='%s'):
+		self.name = name
+		self.template = template
+		self.node = None
+
+class input_file(cmd_arg):
+	def find_node(self, base_path):
+		assert isinstance(base_path, Node.Node)
+		self.node = base_path.find_resource(self.name)
+		if self.node is None:
+			raise Errors.WafError("Input file %s not found in " % (self.name, base_path))
+
+	def get_path(self, env, absolute):
+		if absolute:
+			return self.template % self.node.abspath()
+		else:
+			return self.template % self.node.srcpath()
+
+class output_file(cmd_arg):
+	def find_node(self, base_path):
+		assert isinstance(base_path, Node.Node)
+		self.node = base_path.find_or_declare(self.name)
+		if self.node is None:
+			raise Errors.WafError("Output file %s not found in " % (self.name, base_path))
+
+	def get_path(self, env, absolute):
+		if absolute:
+			return self.template % self.node.abspath()
+		else:
+			return self.template % self.node.bldpath()
+
+class cmd_dir_arg(cmd_arg):
+	def find_node(self, base_path):
+		assert isinstance(base_path, Node.Node)
+		self.node = base_path.find_dir(self.name)
+		if self.node is None:
+			raise Errors.WafError("Directory %s not found in " % (self.name, base_path))
+
+class input_dir(cmd_dir_arg):
+	def get_path(self, dummy_env, dummy_absolute):
+		return self.template % self.node.abspath()
+
+class output_dir(cmd_dir_arg):
+	def get_path(self, env, dummy_absolute):
+		return self.template % self.node.abspath()
+
+
+class command_output(Task.Task):
+	color = "BLUE"
+	def __init__(self, env, command, command_node, command_args, stdin, stdout, cwd, os_env, stderr):
+		Task.Task.__init__(self, env=env)
+		assert isinstance(command, (str, Node.Node))
+		self.command = command
+		self.command_args = command_args
+		self.stdin = stdin
+		self.stdout = stdout
+		self.cwd = cwd
+		self.os_env = os_env
+		self.stderr = stderr
+
+		if command_node is not None: self.dep_nodes = [command_node]
+		self.dep_vars = [] # additional environment variables to look
+
+	def run(self):
+		task = self
+		#assert len(task.inputs) > 0
+
+		def input_path(node, template):
+			if task.cwd is None:
+				return template % node.bldpath()
+			else:
+				return template % node.abspath()
+		def output_path(node, template):
+			fun = node.abspath
+			if task.cwd is None: fun = node.bldpath
+			return template % fun()
+
+		if isinstance(task.command, Node.Node):
+			argv = [input_path(task.command, '%s')]
+		else:
+			argv = [task.command]
+
+		for arg in task.command_args:
+			if isinstance(arg, str):
+				argv.append(arg)
+			else:
+				assert isinstance(arg, cmd_arg)
+				argv.append(arg.get_path(task.env, (task.cwd is not None)))
+
+		if task.stdin:
+			stdin = open(input_path(task.stdin, '%s'))
+		else:
+			stdin = None
+
+		if task.stdout:
+			stdout = open(output_path(task.stdout, '%s'), "w")
+		else:
+			stdout = None
+
+		if task.stderr:
+			stderr = open(output_path(task.stderr, '%s'), "w")
+		else:
+			stderr = None
+
+		if task.cwd is None:
+			cwd = ('None (actually %r)' % os.getcwd())
+		else:
+			cwd = repr(task.cwd)
+		debug("command-output: cwd=%s, stdin=%r, stdout=%r, argv=%r" %
+			     (cwd, stdin, stdout, argv))
+
+		if task.os_env is None:
+			os_env = os.environ
+		else:
+			os_env = task.os_env
+		command = Utils.subprocess.Popen(argv, stdin=stdin, stdout=stdout, stderr=stderr, cwd=task.cwd, env=os_env)
+		return command.wait()
+
+ at feature('command-output')
+def init_cmd_output(self):
+	Utils.def_attrs(self,
+		stdin = None,
+		stdout = None,
+		stderr = None,
+		# the command to execute
+		command = None,
+
+		# whether it is an external command; otherwise it is assumed
+		# to be an executable binary or script that lives in the
+		# source or build tree.
+		command_is_external = False,
+
+		# extra parameters (argv) to pass to the command (excluding
+		# the command itself)
+		argv = [],
+
+		# dependencies to other objects -> this is probably not what you want (ita)
+		# values must be 'task_gen' instances (not names!)
+		dependencies = [],
+
+		# dependencies on env variable contents
+		dep_vars = [],
+
+		# input files that are implicit, i.e. they are not
+		# stdin, nor are they mentioned explicitly in argv
+		hidden_inputs = [],
+
+		# output files that are implicit, i.e. they are not
+		# stdout, nor are they mentioned explicitly in argv
+		hidden_outputs = [],
+
+		# change the subprocess to this cwd (must use obj.input_dir() or output_dir() here)
+		cwd = None,
+
+		# OS environment variables to pass to the subprocess
+		# if None, use the default environment variables unchanged
+		os_env = None)
+
+ at feature('command-output')
+ at after_method('init_cmd_output')
+def apply_cmd_output(self):
+	if self.command is None:
+		raise Errors.WafError("command-output missing command")
+	if self.command_is_external:
+		cmd = self.command
+		cmd_node = None
+	else:
+		cmd_node = self.path.find_resource(self.command)
+		assert cmd_node is not None, ('''Could not find command '%s' in source tree.
+Hint: if this is an external command,
+use command_is_external=True''') % (self.command,)
+		cmd = cmd_node
+
+	if self.cwd is None:
+		cwd = None
+	else:
+		assert isinstance(cwd, CmdDirArg)
+		self.cwd.find_node(self.path)
+
+	args = []
+	inputs = []
+	outputs = []
+
+	for arg in self.argv:
+		if isinstance(arg, cmd_arg):
+			arg.find_node(self.path)
+			if isinstance(arg, input_file):
+				inputs.append(arg.node)
+			if isinstance(arg, output_file):
+				outputs.append(arg.node)
+
+	if self.stdout is None:
+		stdout = None
+	else:
+		assert isinstance(self.stdout, str)
+		stdout = self.path.find_or_declare(self.stdout)
+		if stdout is None:
+			raise Errors.WafError("File %s not found" % (self.stdout,))
+		outputs.append(stdout)
+
+	if self.stderr is None:
+		stderr = None
+	else:
+		assert isinstance(self.stderr, str)
+		stderr = self.path.find_or_declare(self.stderr)
+		if stderr is None:
+			raise Errors.WafError("File %s not found" % (self.stderr,))
+		outputs.append(stderr)
+
+	if self.stdin is None:
+		stdin = None
+	else:
+		assert isinstance(self.stdin, str)
+		stdin = self.path.find_resource(self.stdin)
+		if stdin is None:
+			raise Errors.WafError("File %s not found" % (self.stdin,))
+		inputs.append(stdin)
+
+	for hidden_input in self.to_list(self.hidden_inputs):
+		node = self.path.find_resource(hidden_input)
+		if node is None:
+			raise Errors.WafError("File %s not found in dir %s" % (hidden_input, self.path))
+		inputs.append(node)
+
+	for hidden_output in self.to_list(self.hidden_outputs):
+		node = self.path.find_or_declare(hidden_output)
+		if node is None:
+			raise Errors.WafError("File %s not found in dir %s" % (hidden_output, self.path))
+		outputs.append(node)
+
+	if not (inputs or getattr(self, 'no_inputs', None)):
+		raise Errors.WafError('command-output objects must have at least one input file or give self.no_inputs')
+	if not (outputs or getattr(self, 'no_outputs', None)):
+		raise Errors.WafError('command-output objects must have at least one output file or give self.no_outputs')
+
+	cwd = self.bld.variant_dir
+	task = command_output(self.env, cmd, cmd_node, self.argv, stdin, stdout, cwd, self.os_env, stderr)
+	task.generator = self
+	copy_attrs(self, task, 'before after ext_in ext_out', only_if_set=True)
+	self.tasks.append(task)
+
+	task.inputs = inputs
+	task.outputs = outputs
+	task.dep_vars = self.to_list(self.dep_vars)
+
+	for dep in self.dependencies:
+		assert dep is not self
+		dep.post()
+		for dep_task in dep.tasks:
+			task.set_run_after(dep_task)
+
+	if not task.inputs:
+		# the case for svnversion, always run, and update the output nodes
+		task.runnable_status = type(Task.TaskBase.run)(runnable_status, task, task.__class__) # always run
+		task.post_run = type(Task.TaskBase.run)(post_run, task, task.__class__)
+
+	# TODO the case with no outputs?
+
+def post_run(self):
+	for x in self.outputs:
+		x.sig = Utils.h_file(x.abspath())
+
+def runnable_status(self):
+	return self.RUN_ME
+
+Task.task_factory('copy', vars=[], func=action_process_file_func)
+
diff --git a/xpdeint/waf/waflib/extras/msvs.py b/xpdeint/waf/waflib/extras/msvs.py
new file mode 100644
index 0000000..0ca5b3c
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/msvs.py
@@ -0,0 +1,1017 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Avalanche Studios 2009-2011
+# Thomas Nagy 2011
+
+"""
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+"""
+
+"""
+To add this tool to your project:
+def options(conf):
+	opt.load('msvs')
+
+It can be a good idea to add the sync_exec tool too.
+
+To generate solution files:
+$ waf configure msvs
+
+To customize the outputs, provide subclasses in your wscript files:
+
+from waflib.extras import msvs
+class vsnode_target(msvs.vsnode_target):
+	def get_build_command(self, props):
+		# likely to be required
+		return "waf.bat build"
+	def collect_source(self):
+		# likely to be required
+		...
+class msvs_bar(msvs.msvs_generator):
+	def init(self):
+		msvs.msvs_generator.init(self)
+		self.vsnode_target = vsnode_target
+
+The msvs class re-uses the same build() function for reading the targets (task generators),
+you may therefore specify msvs settings on the context object:
+
+def build(bld):
+	bld.solution_name = 'foo.sln'
+	bld.waf_command = 'waf.bat'
+	bld.projects_dir = bld.srcnode.make_node('.depproj')
+	bld.projects_dir.mkdir()
+
+For visual studio 2008, the command is called 'msvs2008', and the classes
+such as vsnode_target are wrapped by a decorator class 'wrap_2008' to
+provide special functionality.
+
+ASSUMPTIONS:
+* a project can be either a directory or a target, vcxproj files are written only for targets that have source files
+* each project is a vcxproj file, therefore the project uuid needs only to be a hash of the absolute path
+"""
+
+import os, re, sys
+import uuid # requires python 2.5
+from waflib.Build import BuildContext
+from waflib import Utils, TaskGen, Logs, Task, Context, Node, Options
+
+HEADERS_GLOB = '**/(*.h|*.hpp|*.H|*.inl)'
+
+PROJECT_TEMPLATE = r'''<?xml version="1.0" encoding="UTF-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0"
+	xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+	<ItemGroup Label="ProjectConfigurations">
+		${for b in project.build_properties}
+		<ProjectConfiguration Include="${b.configuration}|${b.platform}">
+			<Configuration>${b.configuration}</Configuration>
+			<Platform>${b.platform}</Platform>
+		</ProjectConfiguration>
+		${endfor}
+	</ItemGroup>
+
+	<PropertyGroup Label="Globals">
+		<ProjectGuid>{${project.uuid}}</ProjectGuid>
+		<Keyword>MakeFileProj</Keyword>
+		<ProjectName>${project.name}</ProjectName>
+	</PropertyGroup>
+	<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+
+	${for b in project.build_properties}
+	<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='${b.configuration}|${b.platform}'" Label="Configuration">
+		<ConfigurationType>Makefile</ConfigurationType>
+		<OutDir>${b.outdir}</OutDir>
+	</PropertyGroup>
+	${endfor}
+
+	<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+	<ImportGroup Label="ExtensionSettings">
+	</ImportGroup>
+
+	${for b in project.build_properties}
+	<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='${b.configuration}|${b.platform}'">
+		<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+	</ImportGroup>
+	${endfor}
+
+	${for b in project.build_properties}
+	<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='${b.configuration}|${b.platform}'">
+		<NMakeBuildCommandLine>${xml:project.get_build_command(b)}</NMakeBuildCommandLine>
+		<NMakeReBuildCommandLine>${xml:project.get_rebuild_command(b)}</NMakeReBuildCommandLine>
+		<NMakeCleanCommandLine>${xml:project.get_clean_command(b)}</NMakeCleanCommandLine>
+		<NMakeIncludeSearchPath>${xml:b.includes_search_path}</NMakeIncludeSearchPath>
+		<NMakePreprocessorDefinitions>${xml:b.preprocessor_definitions};$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>
+		<IncludePath>${xml:b.includes_search_path}</IncludePath>
+		<ExecutablePath>$(ExecutablePath)</ExecutablePath>
+
+		${if getattr(b, 'output_file', None)}
+		<NMakeOutput>${xml:b.output_file}</NMakeOutput>
+		${endif}
+		${if getattr(b, 'deploy_dir', None)}
+		<RemoteRoot>${xml:b.deploy_dir}</RemoteRoot>
+		${endif}
+	</PropertyGroup>
+	${endfor}
+
+	${for b in project.build_properties}
+		${if getattr(b, 'deploy_dir', None)}
+	<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='${b.configuration}|${b.platform}'">
+		<Deploy>
+			<DeploymentType>CopyToHardDrive</DeploymentType>
+		</Deploy>
+	</ItemDefinitionGroup>
+		${endif}
+	${endfor}
+
+	<ItemGroup>
+		${for x in project.source}
+		<${project.get_key(x)} Include='${x.abspath()}' />
+		${endfor}
+	</ItemGroup>
+	<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+	<ImportGroup Label="ExtensionTargets">
+	</ImportGroup>
+</Project>
+'''
+
+FILTER_TEMPLATE = '''<?xml version="1.0" encoding="UTF-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+	<ItemGroup>
+		${for x in project.source}
+			<${project.get_key(x)} Include="${x.abspath()}">
+				<Filter>${project.get_filter_name(x.parent)}</Filter>
+			</${project.get_key(x)}>
+		${endfor}
+	</ItemGroup>
+	<ItemGroup>
+		${for x in project.dirs()}
+			<Filter Include="${project.get_filter_name(x)}">
+				<UniqueIdentifier>{${project.make_uuid(x.abspath())}}</UniqueIdentifier>
+			</Filter>
+		${endfor}
+	</ItemGroup>
+</Project>
+'''
+
+PROJECT_2008_TEMPLATE = r'''<?xml version="1.0" encoding="UTF-8"?>
+<VisualStudioProject ProjectType="Visual C++" Version="9,00"
+	Name="${xml: project.name}" ProjectGUID="{${project.uuid}}"
+	Keyword="MakeFileProj"
+	TargetFrameworkVersion="196613">
+	<Platforms>
+		${if project.build_properties}
+		${for b in project.build_properties}
+		   <Platform Name="${xml: b.platform}" />
+		${endfor}
+		${else}
+		   <Platform Name="Win32" />
+		${endif}
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		${if project.build_properties}
+		${for b in project.build_properties}
+		<Configuration
+			Name="${xml: b.configuration}|${xml: b.platform}"
+			IntermediateDirectory="$ConfigurationName"
+			OutputDirectory="${xml: b.outdir}"
+			ConfigurationType="0">
+			<Tool
+				Name="VCNMakeTool"
+				BuildCommandLine="${xml: project.get_build_command(b)}"
+				ReBuildCommandLine="${xml: project.get_rebuild_command(b)}"
+				CleanCommandLine="${xml: project.get_clean_command(b)}"
+				${if getattr(b, 'output_file', None)}
+				Output="${xml: b.output_file}"
+				${endif}
+				PreprocessorDefinitions="${xml: b.preprocessor_definitions}"
+				IncludeSearchPath="${xml: b.includes_search_path}"
+				ForcedIncludes=""
+				ForcedUsingAssemblies=""
+				AssemblySearchPath=""
+				CompileAsManaged=""
+			/>
+		</Configuration>
+		${endfor}
+		${else}
+			<Configuration Name="Release|Win32" >
+		</Configuration>
+		${endif}
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+${project.display_filter()}
+	</Files>
+</VisualStudioProject>
+'''
+
+SOLUTION_TEMPLATE = '''Microsoft Visual Studio Solution File, Format Version ${project.numver}
+# Visual Studio ${project.vsver}
+${for p in project.all_projects}
+Project("{${p.ptype()}}") = "${p.name}", "${p.title}", "{${p.uuid}}"
+EndProject${endfor}
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		${if project.all_projects}
+		${for (configuration, platform) in project.all_projects[0].ctx.project_configurations()}
+		${configuration}|${platform} = ${configuration}|${platform}
+		${endfor}
+		${endif}
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		${for p in project.all_projects}
+			${if hasattr(p, 'source')}
+			${for b in p.build_properties}
+		{${p.uuid}}.${b.configuration}|${b.platform}.ActiveCfg = ${b.configuration}|${b.platform}
+			${if getattr(p, 'is_active', None)}
+		{${p.uuid}}.${b.configuration}|${b.platform}.Build.0 = ${b.configuration}|${b.platform}
+			${endif}
+			${endfor}
+			${endif}
+		${endfor}
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+	${for p in project.all_projects}
+		${if p.parent}
+		{${p.uuid}} = {${p.parent.uuid}}
+		${endif}
+	${endfor}
+	EndGlobalSection
+EndGlobal
+'''
+
+COMPILE_TEMPLATE = '''def f(project):
+	lst = []
+	def xml_escape(value):
+		return value.replace("&", "&").replace('"', """).replace("'", "'").replace("<", "<").replace(">", ">")
+
+	%s
+
+	#f = open('cmd.txt', 'w')
+	#f.write(str(lst))
+	#f.close()
+	return ''.join(lst)
+'''
+reg_act = re.compile(r"(?P<backslash>\\)|(?P<dollar>\$\$)|(?P<subst>\$\{(?P<code>[^}]*?)\})", re.M)
+def compile_template(line):
+	"""
+	Compile a template expression into a python function (like jsps, but way shorter)
+	"""
+	extr = []
+	def repl(match):
+		g = match.group
+		if g('dollar'): return "$"
+		elif g('backslash'):
+			return "\\"
+		elif g('subst'):
+			extr.append(g('code'))
+			return "<<|@|>>"
+		return None
+
+	line2 = reg_act.sub(repl, line)
+	params = line2.split('<<|@|>>')
+	assert(extr)
+
+
+	indent = 0
+	buf = []
+	dvars = []
+	app = buf.append
+
+	def app(txt):
+		buf.append(indent * '\t' + txt)
+
+	for x in range(len(extr)):
+		if params[x]:
+			app("lst.append(%r)" % params[x])
+
+		f = extr[x]
+		if f.startswith('if') or f.startswith('for'):
+			app(f + ':')
+			indent += 1
+		elif f.startswith('py:'):
+			app(f[3:])
+		elif f.startswith('endif') or f.startswith('endfor'):
+			indent -= 1
+		elif f.startswith('else') or f.startswith('elif'):
+			indent -= 1
+			app(f + ':')
+			indent += 1
+		elif f.startswith('xml:'):
+			app('lst.append(xml_escape(%s))' % f[4:])
+		else:
+			#app('lst.append((%s) or "cannot find %s")' % (f, f))
+			app('lst.append(%s)' % f)
+
+	if extr:
+		if params[-1]:
+			app("lst.append(%r)" % params[-1])
+
+	fun = COMPILE_TEMPLATE % "\n\t".join(buf)
+	#print(fun)
+	return Task.funex(fun)
+
+
+re_blank = re.compile('(\n|\r|\\s)*\n', re.M)
+def rm_blank_lines(txt):
+	txt = re_blank.sub('\r\n', txt)
+	return txt
+
+BOM = '\xef\xbb\xbf'
+try:
+	BOM = bytes(BOM, 'iso8859-1') # python 3
+except:
+	pass
+
+def stealth_write(self, data, flags='wb'):
+	try:
+		x = unicode
+	except:
+		data = data.encode('utf-8') # python 3
+	else:
+		data = data.decode(sys.getfilesystemencoding(), 'replace')
+		data = data.encode('utf-8')
+
+	if self.name.endswith('.vcproj') or self.name.endswith('.vcxproj'):
+		data = BOM + data
+
+	try:
+		txt = self.read(flags='rb')
+		if txt != data:
+			raise ValueError('must write')
+	except (IOError, ValueError):
+		self.write(data, flags=flags)
+	else:
+		Logs.debug('msvs: skipping %s' % self.abspath())
+Node.Node.stealth_write = stealth_write
+
+re_quote = re.compile("[^a-zA-Z0-9-]")
+def quote(s):
+	return re_quote.sub("_", s)
+
+def xml_escape(value):
+	return value.replace("&", "&").replace('"', """).replace("'", "'").replace("<", "<").replace(">", ">")
+
+def make_uuid(v, prefix = None):
+	"""
+	simple utility function
+	"""
+	if isinstance(v, dict):
+		keys = list(v.keys())
+		keys.sort()
+		tmp = str([(k, v[k]) for k in keys])
+	else:
+		tmp = str(v)
+	d = Utils.md5(tmp.encode()).hexdigest().upper()
+	if prefix:
+		d = '%s%s' % (prefix, d[8:])
+	gid = uuid.UUID(d, version = 4)
+	return str(gid).upper()
+
+def diff(node, fromnode):
+	# difference between two nodes, but with "(..)" instead of ".."
+	c1 = node
+	c2 = fromnode
+
+	c1h = c1.height()
+	c2h = c2.height()
+
+	lst = []
+	up = 0
+
+	while c1h > c2h:
+		lst.append(c1.name)
+		c1 = c1.parent
+		c1h -= 1
+
+	while c2h > c1h:
+		up += 1
+		c2 = c2.parent
+		c2h -= 1
+
+	while id(c1) != id(c2):
+		lst.append(c1.name)
+		up += 1
+
+		c1 = c1.parent
+		c2 = c2.parent
+
+	for i in range(up):
+		lst.append('(..)')
+	lst.reverse()
+	return tuple(lst)
+
+class build_property(object):
+	pass
+
+class vsnode(object):
+	"""
+	Abstract class representing visual studio elements
+	We assume that all visual studio nodes have a uuid and a parent
+	"""
+	def __init__(self, ctx):
+		self.ctx = ctx # msvs context
+		self.name = '' # string, mandatory
+		self.vspath = '' # path in visual studio (name for dirs, absolute path for projects)
+		self.uuid = '' # string, mandatory
+		self.parent = None # parent node for visual studio nesting
+
+	def get_waf(self):
+		"""
+		Override in subclasses...
+		"""
+		return 'cd /d "%s" & %s' % (self.ctx.srcnode.abspath(), getattr(self.ctx, 'waf_command', 'waf.bat'))
+
+	def ptype(self):
+		"""
+		Return a special uuid for projects written in the solution file
+		"""
+		pass
+
+	def write(self):
+		"""
+		Write the project file, by default, do nothing
+		"""
+		pass
+
+	def make_uuid(self, val):
+		"""
+		Alias for creating uuid values easily (the templates cannot access global variables)
+		"""
+		return make_uuid(val)
+
+class vsnode_vsdir(vsnode):
+	"""
+	Nodes representing visual studio folders (which do not match the filesystem tree!)
+	"""
+	VS_GUID_SOLUTIONFOLDER = "2150E333-8FDC-42A3-9474-1A3956D46DE8"
+	def __init__(self, ctx, uuid, name, vspath=''):
+		vsnode.__init__(self, ctx)
+		self.title = self.name = name
+		self.uuid = uuid
+		self.vspath = vspath or name
+
+	def ptype(self):
+		return self.VS_GUID_SOLUTIONFOLDER
+
+class vsnode_project(vsnode):
+	"""
+	Abstract class representing visual studio project elements
+	A project is assumed to be writable, and has a node representing the file to write to
+	"""
+	VS_GUID_VCPROJ = "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942"
+	def ptype(self):
+		return self.VS_GUID_VCPROJ
+
+	def __init__(self, ctx, node):
+		vsnode.__init__(self, ctx)
+		self.path = node
+		self.uuid = make_uuid(node.abspath())
+		self.name = node.name
+		self.title = self.path.abspath()
+		self.source = [] # list of node objects
+		self.build_properties = [] # list of properties (nmake commands, output dir, etc)
+
+	def dirs(self):
+		"""
+		Get the list of parent folders of the source files (header files included)
+		for writing the filters
+		"""
+		lst = []
+		def add(x):
+			if x.height() > self.tg.path.height() and x not in lst:
+				lst.append(x)
+				add(x.parent)
+		for x in self.source:
+			add(x.parent)
+		return lst
+
+	def write(self):
+		Logs.debug('msvs: creating %r' % self.path)
+
+		# first write the project file
+		template1 = compile_template(PROJECT_TEMPLATE)
+		proj_str = template1(self)
+		proj_str = rm_blank_lines(proj_str)
+		self.path.stealth_write(proj_str)
+
+		# then write the filter
+		template2 = compile_template(FILTER_TEMPLATE)
+		filter_str = template2(self)
+		filter_str = rm_blank_lines(filter_str)
+		tmp = self.path.parent.make_node(self.path.name + '.filters')
+		tmp.stealth_write(filter_str)
+
+	def get_key(self, node):
+		"""
+		required for writing the source files
+		"""
+		name = node.name
+		if name.endswith('.cpp') or name.endswith('.c'):
+			return 'ClCompile'
+		return 'ClInclude'
+
+	def collect_properties(self):
+		"""
+		Returns a list of triplet (configuration, platform, output_directory)
+		"""
+		ret = []
+		for c in self.ctx.configurations:
+			for p in self.ctx.platforms:
+				x = build_property()
+				x.outdir = ''
+
+				x.configuration = c
+				x.platform = p
+
+				x.preprocessor_definitions = ''
+				x.includes_search_path = ''
+
+				# can specify "deploy_dir" too
+				ret.append(x)
+		self.build_properties = ret
+
+	def get_build_params(self, props):
+		opt = '--execsolution=%s' % self.ctx.get_solution_node().abspath()
+		return (self.get_waf(), opt)
+
+	def get_build_command(self, props):
+		return "%s build %s" % self.get_build_params(props)
+
+	def get_clean_command(self, props):
+		return "%s clean %s" % self.get_build_params(props)
+
+	def get_rebuild_command(self, props):
+		return "%s clean build %s" % self.get_build_params(props)
+
+	def get_filter_name(self, node):
+		lst = diff(node, self.tg.path)
+		return '\\'.join(lst) or '.'
+
+class vsnode_alias(vsnode_project):
+	def __init__(self, ctx, node, name):
+		vsnode_project.__init__(self, ctx, node)
+		self.name = name
+		self.output_file = ''
+
+class vsnode_build_all(vsnode_alias):
+	"""
+	Fake target used to emulate the behaviour of "make all" (starting one process by target is slow)
+	This is the only alias enabled by default
+	"""
+	def __init__(self, ctx, node, name='build_all_projects'):
+		vsnode_alias.__init__(self, ctx, node, name)
+		self.is_active = True
+
+class vsnode_install_all(vsnode_alias):
+	"""
+	Fake target used to emulate the behaviour of "make install"
+	"""
+	def __init__(self, ctx, node, name='install_all_projects'):
+		vsnode_alias.__init__(self, ctx, node, name)
+
+	def get_build_command(self, props):
+		return "%s build install %s" % self.get_build_params(props)
+
+	def get_clean_command(self, props):
+		return "%s clean %s" % self.get_build_params(props)
+
+	def get_rebuild_command(self, props):
+		return "%s clean build install %s" % self.get_build_params(props)
+
+class vsnode_project_view(vsnode_alias):
+	"""
+	Fake target used to emulate a file system view
+	"""
+	def __init__(self, ctx, node, name='project_view'):
+		vsnode_alias.__init__(self, ctx, node, name)
+		self.tg = self.ctx() # fake one, cannot remove
+		self.exclude_files = Node.exclude_regs + '''
+waf-1.6.*
+waf3-1.6.*/**
+.waf-1.6.*
+.waf3-1.6.*/**
+**/*.sdf
+**/*.suo
+**/*.ncb
+**/%s
+		''' % Options.lockfile
+
+	def collect_source(self):
+		# this is likely to be slow
+		self.source = self.ctx.srcnode.ant_glob('**', excl=self.exclude_files)
+
+	def get_build_command(self, props):
+		params = self.get_build_params(props) + (self.ctx.cmd,)
+		return "%s %s %s" % params
+
+	def get_clean_command(self, props):
+		return ""
+
+	def get_rebuild_command(self, props):
+		return self.get_build_command(props)
+
+class vsnode_target(vsnode_project):
+	"""
+	Visual studio project representing a targets (programs, libraries, etc) and bound
+	to a task generator
+	"""
+	def __init__(self, ctx, tg):
+		"""
+		A project is more or less equivalent to a file/folder
+		"""
+		base = getattr(ctx, 'projects_dir', None) or tg.path
+		node = base.make_node(quote(tg.name) + ctx.project_extension) # the project file as a Node
+		vsnode_project.__init__(self, ctx, node)
+		self.name = quote(tg.name)
+		self.tg     = tg  # task generator
+
+	def get_build_params(self, props):
+		"""
+		Override the default to add the target name
+		"""
+		opt = '--execsolution=%s' % self.ctx.get_solution_node().abspath()
+		if getattr(self, 'tg', None):
+			opt += " --targets=%s" % self.tg.name
+		return (self.get_waf(), opt)
+
+	def collect_source(self):
+		tg = self.tg
+		source_files = tg.to_nodes(getattr(tg, 'source', []))
+		include_dirs = Utils.to_list(getattr(tg, 'msvs_includes', []))
+		include_files = []
+		for x in include_dirs:
+			if isinstance(x, str):
+				x = tg.path.find_node(x)
+			if x:
+				lst = [y for y in x.ant_glob(HEADERS_GLOB, flat=False)]
+				include_files.extend(lst)
+
+		# remove duplicates
+		self.source.extend(list(set(source_files + include_files)))
+		self.source.sort(key=lambda x: x.abspath())
+
+	def collect_properties(self):
+		"""
+		Visual studio projects are associated with platforms and configurations (for building especially)
+		"""
+		super(vsnode_target, self).collect_properties()
+		for x in self.build_properties:
+			x.outdir = self.path.parent.abspath()
+			x.preprocessor_definitions = ''
+			x.includes_search_path = ''
+
+			try:
+				tsk = self.tg.link_task
+			except AttributeError:
+				pass
+			else:
+				x.output_file = tsk.outputs[0].abspath()
+				x.preprocessor_definitions = ';'.join(tsk.env.DEFINES)
+				x.includes_search_path = ';'.join(self.tg.env.INCPATHS)
+
+class msvs_generator(BuildContext):
+	'''generates a visual studio 2010 solution'''
+	cmd = 'msvs'
+	fun = 'build'
+
+	def init(self):
+		"""
+		Some data that needs to be present
+		"""
+		if not getattr(self, 'configurations', None):
+			self.configurations = ['Release'] # LocalRelease, RemoteDebug, etc
+		if not getattr(self, 'platforms', None):
+			self.platforms = ['Win32']
+		if not getattr(self, 'all_projects', None):
+			self.all_projects = []
+		if not getattr(self, 'project_extension', None):
+			self.project_extension = '.vcxproj'
+		if not getattr(self, 'projects_dir', None):
+			self.projects_dir = self.srcnode.make_node('.depproj')
+			self.projects_dir.mkdir()
+
+		# bind the classes to the object, so that subclass can provide custom generators
+		if not getattr(self, 'vsnode_vsdir', None):
+			self.vsnode_vsdir = vsnode_vsdir
+		if not getattr(self, 'vsnode_target', None):
+			self.vsnode_target = vsnode_target
+		if not getattr(self, 'vsnode_build_all', None):
+			self.vsnode_build_all = vsnode_build_all
+		if not getattr(self, 'vsnode_install_all', None):
+			self.vsnode_install_all = vsnode_install_all
+		if not getattr(self, 'vsnode_project_view', None):
+			self.vsnode_project_view = vsnode_project_view
+
+		self.numver = '11.00'
+		self.vsver  = '2010'
+
+	def execute(self):
+		"""
+		Entry point
+		"""
+		self.restore()
+		if not self.all_envs:
+			self.load_envs()
+		self.recurse([self.run_dir])
+
+		# user initialization
+		self.init()
+
+		# two phases for creating the solution
+		self.collect_projects() # add project objects into "self.all_projects"
+		self.write_files() # write the corresponding project and solution files
+
+	def collect_projects(self):
+		"""
+		Fill the list self.all_projects with project objects
+		Fill the list of build targets
+		"""
+		self.collect_targets()
+		self.add_aliases()
+		self.collect_dirs()
+		self.all_projects.sort(key=lambda x: getattr(x, 'path', None) and x.path.abspath() or x.name)
+
+	def write_files(self):
+		"""
+		Write the project and solution files from the data collected
+		so far. It is unlikely that you will want to change this
+		"""
+		for p in self.all_projects:
+			p.write()
+
+		# and finally write the solution file
+		node = self.get_solution_node()
+		node.parent.mkdir()
+		Logs.warn('Creating %r' % node)
+		template1 = compile_template(SOLUTION_TEMPLATE)
+		sln_str = template1(self)
+		sln_str = rm_blank_lines(sln_str)
+		node.stealth_write(sln_str)
+
+	def get_solution_node(self):
+		"""
+		The solution filename is required when writing the .vcproj files
+		return self.solution_node and if it does not exist, make one
+		"""
+		try:
+			return self.solution_node
+		except:
+			pass
+
+		solution_name = getattr(self, 'solution_name', None)
+		if not solution_name:
+			solution_name = getattr(Context.g_module, Context.APPNAME, 'project') + '.sln'
+		if os.path.isabs(solution_name):
+			self.solution_node = self.root.make_node(solution_name)
+		else:
+			self.solution_node = self.srcnode.make_node(solution_name)
+		return self.solution_node
+
+	def project_configurations(self):
+		"""
+		Helper that returns all the pairs (config,platform)
+		"""
+		ret = []
+		for c in self.configurations:
+			for p in self.platforms:
+				ret.append((c, p))
+		return ret
+
+	def collect_targets(self):
+		"""
+		Process the list of task generators
+		"""
+		for g in self.groups:
+			for tg in g:
+				if not isinstance(tg, TaskGen.task_gen):
+					continue
+
+				if not hasattr(tg, 'msvs_includes'):
+					tg.msvs_includes = tg.to_list(getattr(tg, 'includes', [])) + tg.to_list(getattr(tg, 'export_includes', []))
+				tg.post()
+				if not getattr(tg, 'link_task', None):
+					continue
+
+				p = self.vsnode_target(self, tg)
+				p.collect_source() # delegate this processing
+				p.collect_properties()
+				self.all_projects.append(p)
+
+	def add_aliases(self):
+		"""
+		Add a specific target that emulates the "make all" necessary for Visual studio when pressing F7
+		We also add an alias for "make install" (disabled by default)
+		"""
+		base = getattr(self, 'projects_dir', None) or self.tg.path
+
+		node_project = base.make_node('build_all_projects' + self.project_extension) # Node
+		p_build = self.vsnode_build_all(self, node_project)
+		p_build.collect_properties()
+		self.all_projects.append(p_build)
+
+		node_project = base.make_node('install_all_projects' + self.project_extension) # Node
+		p_install = self.vsnode_install_all(self, node_project)
+		p_install.collect_properties()
+		self.all_projects.append(p_install)
+
+		node_project = base.make_node('project_view' + self.project_extension) # Node
+		p_view = self.vsnode_project_view(self, node_project)
+		p_view.collect_source()
+		p_view.collect_properties()
+		self.all_projects.append(p_view)
+
+		n = self.vsnode_vsdir(self, make_uuid(self.srcnode.abspath() + 'build_aliases'), "build_aliases")
+		p_build.parent = p_install.parent = p_view.parent = n
+		self.all_projects.append(n)
+
+	def collect_dirs(self):
+		"""
+		Create the folder structure in the Visual studio project view
+		"""
+		seen = {}
+		def make_parents(proj):
+			# look at a project, try to make a parent
+			if getattr(proj, 'parent', None):
+				# aliases already have parents
+				return
+			x = proj.iter_path
+			if x in seen:
+				proj.parent = seen[x]
+				return
+
+			# There is not vsnode_vsdir for x.
+			# So create a project representing the folder "x"
+			n = proj.parent = seen[x] = self.vsnode_vsdir(self, make_uuid(x.abspath()), x.name)
+			n.iter_path = x.parent
+			self.all_projects.append(n)
+
+			# recurse up to the project directory
+			if x.height() > self.srcnode.height() + 1:
+				make_parents(n)
+
+		for p in self.all_projects[:]: # iterate over a copy of all projects
+			if not getattr(p, 'tg', None):
+				# but only projects that have a task generator
+				continue
+
+			# make a folder for each task generator
+			p.iter_path = p.tg.path
+			make_parents(p)
+
+def wrap_2008(cls):
+	class dec(cls):
+		def __init__(self, *k, **kw):
+			cls.__init__(self, *k, **kw)
+			self.project_template = PROJECT_2008_TEMPLATE
+
+		def display_filter(self):
+
+			root = build_property()
+			root.subfilters = []
+			root.sourcefiles = []
+			root.source = []
+			root.name = ''
+
+			@Utils.run_once
+			def add_path(lst):
+				if not lst:
+					return root
+				child = build_property()
+				child.subfilters = []
+				child.sourcefiles = []
+				child.source = []
+				child.name = lst[-1]
+
+				par = add_path(lst[:-1])
+				par.subfilters.append(child)
+				return child
+
+			for x in self.source:
+				# this crap is for enabling subclasses to override get_filter_name
+				tmp = self.get_filter_name(x.parent)
+				tmp = tmp != '.' and tuple(tmp.split('\\')) or ()
+				par = add_path(tmp)
+				par.source.append(x)
+
+			def display(n):
+				buf = []
+				for x in n.source:
+					buf.append('<File RelativePath="%s" FileType="%s"/>\n' % (xml_escape(x.abspath()), self.get_key(x)))
+				for x in n.subfilters:
+					buf.append('<Filter Name="%s">' % xml_escape(x.name))
+					buf.append(display(x))
+					buf.append('</Filter>')
+				return '\n'.join(buf)
+
+			return display(root)
+
+		def get_key(self, node):
+			"""
+			If you do not want to let visual studio use the default file extensions,
+			override this method to return a value:
+				0: C/C++ Code, 1: C++ Class, 2: C++ Header File, 3: C++ Form,
+				4: C++ Control, 5: Text File, 6: DEF File, 7: IDL File,
+				8: Makefile, 9: RGS File, 10: RC File, 11: RES File, 12: XSD File,
+				13: XML File, 14: HTML File, 15: CSS File, 16: Bitmap, 17: Icon,
+				18: Resx File, 19: BSC File, 20: XSX File, 21: C++ Web Service,
+				22: ASAX File, 23: Asp Page, 24: Document, 25: Discovery File,
+				26: C# File, 27: eFileTypeClassDiagram, 28: MHTML Document,
+				29: Property Sheet, 30: Cursor, 31: Manifest, 32: eFileTypeRDLC
+			"""
+			return ''
+
+		def write(self):
+			Logs.debug('msvs: creating %r' % self.path)
+			template1 = compile_template(self.project_template)
+			proj_str = template1(self)
+			proj_str = rm_blank_lines(proj_str)
+			self.path.stealth_write(proj_str)
+
+	return dec
+
+class msvs_2008_generator(msvs_generator):
+	'''generates a visual studio 2008 solution'''
+	cmd = 'msvs2008'
+	fun = msvs_generator.fun
+
+	def init(self):
+		if not getattr(self, 'project_extension', None):
+			self.project_extension = '_2008.vcproj'
+		if not getattr(self, 'solution_name', None):
+			self.solution_name = getattr(Context.g_module, Context.APPNAME, 'project') + '_2008.sln'
+
+		if not getattr(self, 'vsnode_target', None):
+			self.vsnode_target = wrap_2008(vsnode_target)
+		if not getattr(self, 'vsnode_build_all', None):
+			self.vsnode_build_all = wrap_2008(vsnode_build_all)
+		if not getattr(self, 'vsnode_install_all', None):
+			self.vsnode_install_all = wrap_2008(vsnode_install_all)
+		if not getattr(self, 'vsnode_project_view', None):
+			self.vsnode_project_view = wrap_2008(vsnode_project_view)
+
+		msvs_generator.init(self)
+		self.numver = '10.00'
+		self.vsver  = '2008'
+
+def options(ctx):
+	"""
+	If the msvs option is used, try to detect if the build is made from visual studio
+	"""
+	ctx.add_option('--execsolution', action='store', help='when building with visual studio, use a build state file')
+
+	old = BuildContext.execute
+	def override_build_state(ctx):
+		def lock(rm, add):
+			uns = ctx.options.execsolution.replace('.sln', rm)
+			uns = ctx.root.make_node(uns)
+			try:
+				uns.delete()
+			except:
+				pass
+
+			uns = ctx.options.execsolution.replace('.sln', add)
+			uns = ctx.root.make_node(uns)
+			try:
+				uns.write('')
+			except:
+				pass
+
+		if ctx.options.execsolution:
+			ctx.launch_dir = Context.top_dir # force a build for the whole project (invalid cwd when called by visual studio)
+			lock('.lastbuildstate', '.unsuccessfulbuild')
+			old(ctx)
+			lock('.unsuccessfulbuild', '.lastbuildstate')
+		else:
+			old(ctx)
+	BuildContext.execute = override_build_state
+
diff --git a/xpdeint/waf/waflib/extras/netcache_client.py b/xpdeint/waf/waflib/extras/netcache_client.py
new file mode 100644
index 0000000..48aa7d6
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/netcache_client.py
@@ -0,0 +1,328 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2011 (ita)
+
+"""
+A client for the network cache (playground/netcache/). Launch the server with:
+./netcache_server, then use it for the builds by adding the following:
+
+	def options(opt):
+		opt.load('netcache_client')
+
+The parameters should be present in the environment in the form:
+	NETCACHE=host:port at mode waf configure build
+
+where:
+	mode: PUSH, PULL, PUSH_PULL
+	host: host where the server resides, for example 127.0.0.1
+	port: by default the server runs on port 51200
+
+The cache can be enabled for the build only:
+	def options(opt):
+		opt.load('netcache_client', funs=[])
+	def build(bld):
+		bld.setup_netcache('localhost', 51200, 'PUSH_PULL')
+"""
+
+import os, socket, time, atexit
+from waflib import Task, Logs, Utils, Build, Options, Runner
+from waflib.Configure import conf
+
+BUF = 8192 * 16
+HEADER_SIZE = 128
+MODES = ['PUSH', 'PULL', 'PUSH_PULL']
+STALE_TIME = 30 # seconds
+
+GET = 'GET'
+PUT = 'PUT'
+LST = 'LST'
+BYE = 'BYE'
+
+all_sigs_in_cache = (0.0, [])
+
+active_connections = Runner.Queue(0)
+def get_connection():
+	# return a new connection... do not forget to release it!
+	try:
+		ret = active_connections.get(block=False)
+	except Exception:
+		ret = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+		ret.connect(Task.net_cache[:2])
+	return ret
+
+def release_connection(conn, msg=''):
+	if conn:
+		active_connections.put(conn)
+
+def close_connection(conn, msg=''):
+	if conn:
+		data = '%s,%s' % (BYE, msg)
+		try:
+			conn.send(data.ljust(HEADER_SIZE))
+		except:
+			pass
+		try:
+			conn.close()
+		except:
+			pass
+
+def close_all():
+	while active_connections.qsize():
+		conn = active_connections.get()
+		try:
+			close_connection(conn)
+		except:
+			pass
+atexit.register(close_all)
+
+def read_header(conn):
+	cnt = 0
+	buf = []
+	while cnt < HEADER_SIZE:
+		data = conn.recv(HEADER_SIZE - cnt)
+		if not data:
+			#import traceback
+			#traceback.print_stack()
+			raise ValueError('connection ended when reading a header %r' % buf)
+		buf.append(data)
+		cnt += len(data)
+	return ''.join(buf)
+
+def check_cache(conn, ssig):
+	"""
+	List the files on the server, this is an optimization because it assumes that
+	concurrent builds are rare
+	"""
+	global all_sigs_in_cache
+	if not STALE_TIME:
+		return
+	if time.time() - all_sigs_in_cache[0] > STALE_TIME:
+
+		params = (LST,'')
+		conn.send(','.join(params).ljust(HEADER_SIZE))
+
+		# read what is coming back
+		ret = read_header(conn)
+		size = int(ret.split(',')[0])
+
+		buf = []
+		cnt = 0
+		while cnt < size:
+			data = conn.recv(min(BUF, size-cnt))
+			if not data:
+				raise ValueError('connection ended %r %r' % (cnt, size))
+			buf.append(data)
+			cnt += len(data)
+		all_sigs_in_cache = (time.time(), ''.join(buf).split('\n'))
+		Logs.debug('netcache: server cache has %r entries' % len(all_sigs_in_cache[1]))
+
+	if not ssig in all_sigs_in_cache[1]:
+		raise ValueError('no file %s in cache' % ssig)
+
+class MissingFile(Exception):
+	pass
+
+def recv_file(conn, ssig, count, p):
+	check_cache(conn, ssig)
+
+	params = (GET, ssig, str(count))
+	conn.send(','.join(params).ljust(HEADER_SIZE))
+	data = read_header(conn)
+
+	size = int(data.split(',')[0])
+
+	if size == -1:
+		raise MissingFile('no file %s - %s in cache' % (ssig, count))
+
+	# get the file, writing immediately
+	# TODO a tmp file would be better
+	f = open(p, 'wb')
+	cnt = 0
+	while cnt < size:
+		data = conn.recv(min(BUF, size-cnt))
+		if not data:
+			raise ValueError('connection ended %r %r' % (cnt, size))
+		f.write(data)
+		cnt += len(data)
+	f.close()
+
+def put_data(conn, ssig, cnt, p):
+	#print "pushing %r %r %r" % (ssig, cnt, p)
+	size = os.stat(p).st_size
+	params = (PUT, ssig, str(cnt), str(size))
+	conn.send(','.join(params).ljust(HEADER_SIZE))
+	f = open(p, 'rb')
+	cnt = 0
+	while cnt < size:
+		r = f.read(min(BUF, size-cnt))
+		while r:
+			k = conn.send(r)
+			if not k:
+				raise ValueError('connection ended')
+			cnt += k
+			r = r[k:]
+
+#def put_data(conn, ssig, cnt, p):
+#	size = os.stat(p).st_size
+#	params = (PUT, ssig, str(cnt), str(size))
+#	conn.send(','.join(params).ljust(HEADER_SIZE))
+#	conn.send(','*size)
+#	params = (BYE, 'he')
+#	conn.send(','.join(params).ljust(HEADER_SIZE))
+
+def can_retrieve_cache(self):
+	if not Task.net_cache:
+		return False
+	if not self.outputs:
+		return False
+	if Task.net_cache[-1] == 'PUSH':
+		return
+	self.cached = False
+
+	cnt = 0
+	sig = self.signature()
+	ssig = self.uid().encode('hex') + sig.encode('hex')
+
+	conn = None
+	err = False
+	try:
+		try:
+			conn = get_connection()
+			for node in self.outputs:
+				p = node.abspath()
+				recv_file(conn, ssig, cnt, p)
+				cnt += 1
+		except MissingFile as e:
+			Logs.debug('netcache: file is not in the cache %r' % e)
+			err = True
+
+		except Exception as e:
+			Logs.debug('netcache: could not get the files %r' % e)
+			err = True
+
+			# broken connection? remove this one
+			close_connection(conn)
+			conn = None
+	finally:
+		release_connection(conn)
+	if err:
+		return False
+
+	for node in self.outputs:
+		node.sig = sig
+		#if self.generator.bld.progress_bar < 1:
+		#	self.generator.bld.to_log('restoring from cache %r\n' % node.abspath())
+
+	self.cached = True
+	return True
+
+ at Utils.run_once
+def put_files_cache(self):
+	if not Task.net_cache:
+		return
+	if not self.outputs:
+		return
+	if Task.net_cache[-1] == 'PULL':
+		return
+	if getattr(self, 'cached', None):
+		return
+
+	#print "called put_files_cache", id(self)
+	bld = self.generator.bld
+	sig = self.signature()
+	ssig = self.uid().encode('hex') + sig.encode('hex')
+
+	conn = None
+	cnt = 0
+	try:
+		for node in self.outputs:
+			# We could re-create the signature of the task with the signature of the outputs
+			# in practice, this means hashing the output files
+			# this is unnecessary
+			try:
+				if not conn:
+					conn = get_connection()
+				put_data(conn, ssig, cnt, node.abspath())
+			except Exception as e:
+				Logs.debug("netcache: could not push the files %r" % e)
+
+				# broken connection? remove this one
+				close_connection(conn)
+				conn = None
+			cnt += 1
+	finally:
+		release_connection(conn)
+
+	bld.task_sigs[self.uid()] = self.cache_sig
+
+def hash_env_vars(self, env, vars_lst):
+	if not env.table:
+		env = env.parent
+		if not env:
+			return Utils.SIG_NIL
+
+	idx = str(id(env)) + str(vars_lst)
+	try:
+		cache = self.cache_env
+	except AttributeError:
+		cache = self.cache_env = {}
+	else:
+		try:
+			return self.cache_env[idx]
+		except KeyError:
+			pass
+
+	v = str([env[a] for a in vars_lst])
+	v = v.replace(self.srcnode.abspath(), '') # here
+	m = Utils.md5()
+	m.update(v.encode())
+	ret = m.digest()
+
+	Logs.debug('envhash: %r %r', ret, v)
+
+	cache[idx] = ret
+
+	return ret
+
+def uid(self):
+	try:
+		return self.uid_
+	except AttributeError:
+		m = Utils.md5()
+		src = self.generator.bld.srcnode
+		up = m.update
+		up(self.__class__.__name__.encode())
+		for x in self.inputs + self.outputs:
+			up(x.path_from(src).encode())
+		self.uid_ = m.digest()
+		return self.uid_
+
+ at conf
+def setup_netcache(ctx, host, port, mode):
+	Logs.warn('Using the network cache %s, %s, %s' % (host, port, mode))
+	Task.net_cache = (host, port, mode)
+	Task.Task.can_retrieve_cache = can_retrieve_cache
+	Task.Task.put_files_cache = put_files_cache
+	Task.Task.uid = uid
+	Build.BuildContext.hash_env_vars = hash_env_vars
+	ctx.cache_global = Options.cache_global = True
+
+def options(opt):
+	if not 'NETCACHE' in os.environ:
+		Logs.warn('the network cache is disabled, set NETCACHE=host:port at mode to enable')
+	else:
+		v = os.environ['NETCACHE']
+		if v in MODES:
+			host = socket.gethostname()
+			port = 51200
+			mode = v
+		else:
+			mode = 'PUSH_PULL'
+			host, port = v.split(':')
+			if port.find('@'):
+				port, mode = port.split('@')
+			port = int(port)
+			if not mode in MODES:
+				opt.fatal('Invalid mode %s not in %r' % (mode, MODES))
+		setup_netcache(opt, host, port, mode)
+
diff --git a/xpdeint/waf/waflib/extras/objcopy.py b/xpdeint/waf/waflib/extras/objcopy.py
new file mode 100644
index 0000000..923a7f2
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/objcopy.py
@@ -0,0 +1,54 @@
+#!/usr/bin/python
+# Grygoriy Fuchedzhy 2010
+
+"""
+Support for converting linked targets to ihex, srec or binary files using
+objcopy. Use the 'objcopy' feature in conjuction with the 'cc' or 'cxx'
+feature. The 'objcopy' feature uses the following attributes:
+
+objcopy_bfdname		Target object format name (eg. ihex, srec, binary).
+					   Defaults to ihex.
+objcopy_target		 File name used for objcopy output. This defaults to the
+					   target name with objcopy_bfdname as extension.
+objcopy_install_path   Install path for objcopy_target file. Defaults to ${PREFIX}/fw.
+objcopy_flags		  Additional flags passed to objcopy.
+"""
+
+from waflib.Utils import def_attrs
+from waflib import Task
+from waflib.TaskGen import feature, after_method
+
+class objcopy(Task.Task):
+	run_str = '${OBJCOPY} -O ${TARGET_BFDNAME} ${OBJCOPYFLAGS} ${SRC} ${TGT}'
+	color   = 'CYAN'
+
+ at feature('objcopy')
+ at after_method('apply_link')
+def objcopy(self):
+	def_attrs(self,
+	   objcopy_bfdname = 'ihex',
+	   objcopy_target = None,
+	   objcopy_install_path = "${PREFIX}/firmware",
+	   objcopy_flags = '')
+
+	link_output = self.link_task.outputs[0]
+	if not self.objcopy_target:
+		self.objcopy_target = link_output.change_ext('.' + self.objcopy_bfdname).name
+	task = self.create_task('objcopy',
+							src=link_output,
+							tgt=self.path.find_or_declare(self.objcopy_target))
+
+	task.env.append_unique('TARGET_BFDNAME', self.objcopy_bfdname)
+	try:
+		task.env.append_unique('OBJCOPYFLAGS', getattr(self, 'objcopy_flags'))
+	except AttributeError:
+		pass
+
+	if self.objcopy_install_path:
+		self.bld.install_files(self.objcopy_install_path,
+							   task.outputs[0],
+							   env=task.env.derive())
+
+def configure(ctx):
+	objcopy = ctx.find_program('objcopy', var='OBJCOPY', mandatory=True)
+
diff --git a/xpdeint/waf/waflib/extras/ocaml.py b/xpdeint/waf/waflib/extras/ocaml.py
new file mode 100644
index 0000000..5cbe5b7
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/ocaml.py
@@ -0,0 +1,326 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+
+"ocaml support"
+
+import os, re
+from waflib import TaskGen, Utils, Task, Build
+from waflib.Logs import error
+from waflib.TaskGen import feature, before_method, after_method, extension
+
+EXT_MLL = ['.mll']
+EXT_MLY = ['.mly']
+EXT_MLI = ['.mli']
+EXT_MLC = ['.c']
+EXT_ML  = ['.ml']
+
+open_re = re.compile('^\s*open\s+([a-zA-Z]+)(;;){0,1}$', re.M)
+foo = re.compile(r"""(\(\*)|(\*\))|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^()*"'\\]*)""", re.M)
+def filter_comments(txt):
+	meh = [0]
+	def repl(m):
+		if m.group(1): meh[0] += 1
+		elif m.group(2): meh[0] -= 1
+		elif not meh[0]: return m.group(0)
+		return ''
+	return foo.sub(repl, txt)
+
+def scan(self):
+	node = self.inputs[0]
+	code = filter_comments(node.read())
+
+	global open_re
+	names = []
+	import_iterator = open_re.finditer(code)
+	if import_iterator:
+		for import_match in import_iterator:
+			names.append(import_match.group(1))
+	found_lst = []
+	raw_lst = []
+	for name in names:
+		nd = None
+		for x in self.incpaths:
+			nd = x.find_resource(name.lower()+'.ml')
+			if not nd: nd = x.find_resource(name+'.ml')
+			if nd:
+				found_lst.append(nd)
+				break
+		else:
+			raw_lst.append(name)
+
+	return (found_lst, raw_lst)
+
+native_lst=['native', 'all', 'c_object']
+bytecode_lst=['bytecode', 'all']
+
+ at feature('ocaml')
+def init_ml(self):
+	Utils.def_attrs(self,
+		type = 'all',
+		incpaths_lst = [],
+		bld_incpaths_lst = [],
+		mlltasks = [],
+		mlytasks = [],
+		mlitasks = [],
+		native_tasks = [],
+		bytecode_tasks = [],
+		linktasks = [],
+		bytecode_env = None,
+		native_env = None,
+		compiled_tasks = [],
+		includes = '',
+		uselib = '',
+		are_deps_set = 0)
+
+ at feature('ocaml')
+ at after_method('init_ml')
+def init_envs_ml(self):
+
+	self.islibrary = getattr(self, 'islibrary', False)
+
+	global native_lst, bytecode_lst
+	self.native_env = None
+	if self.type in native_lst:
+		self.native_env = self.env.derive()
+		if self.islibrary: self.native_env['OCALINKFLAGS']   = '-a'
+
+	self.bytecode_env = None
+	if self.type in bytecode_lst:
+		self.bytecode_env = self.env.derive()
+		if self.islibrary: self.bytecode_env['OCALINKFLAGS'] = '-a'
+
+	if self.type == 'c_object':
+		self.native_env.append_unique('OCALINKFLAGS_OPT', '-output-obj')
+
+ at feature('ocaml')
+ at before_method('apply_vars_ml')
+ at after_method('init_envs_ml')
+def apply_incpaths_ml(self):
+	inc_lst = self.includes.split()
+	lst = self.incpaths_lst
+	for dir in inc_lst:
+		node = self.path.find_dir(dir)
+		if not node:
+			error("node not found: " + str(dir))
+			continue
+		if not node in lst:
+			lst.append(node)
+		self.bld_incpaths_lst.append(node)
+	# now the nodes are added to self.incpaths_lst
+
+ at feature('ocaml')
+ at before_method('process_source')
+def apply_vars_ml(self):
+	for i in self.incpaths_lst:
+		if self.bytecode_env:
+			app = self.bytecode_env.append_value
+			app('OCAMLPATH', ['-I', i.bldpath(), '-I', i.srcpath()])
+
+		if self.native_env:
+			app = self.native_env.append_value
+			app('OCAMLPATH', ['-I', i.bldpath(), '-I', i.srcpath()])
+
+	varnames = ['INCLUDES', 'OCAMLFLAGS', 'OCALINKFLAGS', 'OCALINKFLAGS_OPT']
+	for name in self.uselib.split():
+		for vname in varnames:
+			cnt = self.env[vname+'_'+name]
+			if cnt:
+				if self.bytecode_env: self.bytecode_env.append_value(vname, cnt)
+				if self.native_env: self.native_env.append_value(vname, cnt)
+
+ at feature('ocaml')
+ at after_method('process_source')
+def apply_link_ml(self):
+
+	if self.bytecode_env:
+		ext = self.islibrary and '.cma' or '.run'
+
+		linktask = self.create_task('ocalink')
+		linktask.bytecode = 1
+		linktask.set_outputs(self.path.find_or_declare(self.target + ext))
+		linktask.env = self.bytecode_env
+		self.linktasks.append(linktask)
+
+	if self.native_env:
+		if self.type == 'c_object': ext = '.o'
+		elif self.islibrary: ext = '.cmxa'
+		else: ext = ''
+
+		linktask = self.create_task('ocalinkx')
+		linktask.set_outputs(self.path.find_or_declare(self.target + ext))
+		linktask.env = self.native_env
+		self.linktasks.append(linktask)
+
+		# we produce a .o file to be used by gcc
+		self.compiled_tasks.append(linktask)
+
+ at extension(*EXT_MLL)
+def mll_hook(self, node):
+	mll_task = self.create_task('ocamllex', node, node.change_ext('.ml'))
+	mll_task.env = self.native_env.derive()
+	self.mlltasks.append(mll_task)
+
+	self.source.append(mll_task.outputs[0])
+
+ at extension(*EXT_MLY)
+def mly_hook(self, node):
+	mly_task = self.create_task('ocamlyacc', node, [node.change_ext('.ml'), node.change_ext('.mli')])
+	mly_task.env = self.native_env.derive()
+	self.mlytasks.append(mly_task)
+	self.source.append(mly_task.outputs[0])
+
+	task = self.create_task('ocamlcmi', mly_task.outputs[1], mly_task.outputs[1].change_ext('.cmi'))
+	task.env = self.native_env.derive()
+
+ at extension(*EXT_MLI)
+def mli_hook(self, node):
+	task = self.create_task('ocamlcmi', node, node.change_ext('.cmi'))
+	task.env = self.native_env.derive()
+	self.mlitasks.append(task)
+
+ at extension(*EXT_MLC)
+def mlc_hook(self, node):
+	task = self.create_task('ocamlcc', node, node.change_ext('.o'))
+	task.env = self.native_env.derive()
+	self.compiled_tasks.append(task)
+
+ at extension(*EXT_ML)
+def ml_hook(self, node):
+	if self.native_env:
+		task = self.create_task('ocamlx', node, node.change_ext('.cmx'))
+		task.env = self.native_env.derive()
+		task.incpaths = self.bld_incpaths_lst
+		self.native_tasks.append(task)
+
+	if self.bytecode_env:
+		task = self.create_task('ocaml', node, node.change_ext('.cmo'))
+		task.env = self.bytecode_env.derive()
+		task.bytecode = 1
+		task.incpaths = self.bld_incpaths_lst
+		self.bytecode_tasks.append(task)
+
+def compile_may_start(self):
+
+	if not getattr(self, 'flag_deps', ''):
+		self.flag_deps = 1
+
+		# the evil part is that we can only compute the dependencies after the
+		# source files can be read (this means actually producing the source files)
+		if getattr(self, 'bytecode', ''): alltasks = self.generator.bytecode_tasks
+		else: alltasks = self.generator.native_tasks
+
+		self.signature() # ensure that files are scanned - unfortunately
+		tree = self.generator.bld
+		env = self.env
+		for node in self.inputs:
+			lst = tree.node_deps[self.uid()]
+			for depnode in lst:
+				for t in alltasks:
+					if t == self: continue
+					if depnode in t.inputs:
+						self.set_run_after(t)
+
+		# TODO necessary to get the signature right - for now
+		delattr(self, 'cache_sig')
+		self.signature()
+
+	return Task.Task.runnable_status(self)
+
+class ocamlx(Task.Task):
+	"""native caml compilation"""
+	color   = 'GREEN'
+	run_str = '${OCAMLOPT} ${OCAMLPATH} ${OCAMLFLAGS} ${OCAMLINCLUDES} -c -o ${TGT} ${SRC}'
+	scan    = scan
+	runnable_status = compile_may_start
+
+class ocaml(Task.Task):
+	"""bytecode caml compilation"""
+	color   = 'GREEN'
+	run_str = '${OCAMLC} ${OCAMLPATH} ${OCAMLFLAGS} ${OCAMLINCLUDES} -c -o ${TGT} ${SRC}'
+	scan    = scan
+	runnable_status = compile_may_start
+
+class ocamlcmi(Task.Task):
+	"""interface generator (the .i files?)"""
+	color   = 'BLUE'
+	run_str = '${OCAMLC} ${OCAMLPATH} ${OCAMLINCLUDES} -o ${TGT} -c ${SRC}'
+	before  = ['ocamlcc', 'ocaml', 'ocamlcc']
+
+class ocamlcc(Task.Task):
+	"""ocaml to c interfaces"""
+	color   = 'GREEN'
+	run_str = 'cd ${TGT[0].bld_dir()} && ${OCAMLOPT} ${OCAMLFLAGS} ${OCAMLPATH} ${OCAMLINCLUDES} -c ${SRC[0].abspath()}'
+
+class ocamllex(Task.Task):
+	"""lexical generator"""
+	color   = 'BLUE'
+	run_str = '${OCAMLLEX} ${SRC} -o ${TGT}'
+	before  = ['ocamlcmi', 'ocaml', 'ocamlcc']
+
+class ocamlyacc(Task.Task):
+	"""parser generator"""
+	color   = 'BLUE'
+	run_str = '${OCAMLYACC} -b ${TGT[0].bld_base(env)} ${SRC}'
+	before  = ['ocamlcmi', 'ocaml', 'ocamlcc']
+
+def link_may_start(self):
+
+	if getattr(self, 'bytecode', 0): alltasks = self.generator.bytecode_tasks
+	else: alltasks = self.generator.native_tasks
+
+	for x in alltasks:
+		if not x.hasrun:
+			return Task.ASK_LATER
+
+	if not getattr(self, 'order', ''):
+
+		# now reorder the inputs given the task dependencies
+		# this part is difficult, we do not have a total order on the tasks
+		# if the dependencies are wrong, this may not stop
+		seen = []
+		pendant = []+alltasks
+		while pendant:
+			task = pendant.pop(0)
+			if task in seen: continue
+			for x in task.run_after:
+				if not x in seen:
+					pendant.append(task)
+					break
+			else:
+				seen.append(task)
+		self.inputs = [x.outputs[0] for x in seen]
+		self.order = 1
+	return Task.Task.runnable_status(self)
+
+class ocalink(Task.Task):
+	"""bytecode caml link"""
+	color   = 'YELLOW'
+	run_str = '${OCAMLC} -o ${TGT} ${OCAMLINCLUDES} ${OCALINKFLAGS} ${SRC}'
+	runnable_status = link_may_start
+	after = ['ocaml', 'ocamlcc']
+
+class ocalinkx(Task.Task):
+	"""native caml link"""
+	color   = 'YELLOW'
+	run_str = '${OCAMLOPT} -o ${TGT} ${OCAMLINCLUDES} ${OCALINKFLAGS_OPT} ${SRC}'
+	runnable_status = link_may_start
+	after = ['ocamlx', 'ocamlcc']
+
+def configure(conf):
+	opt = conf.find_program('ocamlopt', var='OCAMLOPT', mandatory=False)
+	occ = conf.find_program('ocamlc', var='OCAMLC', mandatory=False)
+	if (not opt) or (not occ):
+		conf.fatal('The objective caml compiler was not found:\ninstall it or make it available in your PATH')
+
+	v = conf.env
+	v['OCAMLC']       = occ
+	v['OCAMLOPT']     = opt
+	v['OCAMLLEX']     = conf.find_program('ocamllex', var='OCAMLLEX', mandatory=False)
+	v['OCAMLYACC']    = conf.find_program('ocamlyacc', var='OCAMLYACC', mandatory=False)
+	v['OCAMLFLAGS']   = ''
+	v['OCAMLLIB']     = conf.cmd_and_log(conf.env['OCAMLC']+' -where').strip()+os.sep
+	v['LIBPATH_OCAML'] = conf.cmd_and_log(conf.env['OCAMLC']+' -where').strip()+os.sep
+	v['INCLUDES_OCAML'] = conf.cmd_and_log(conf.env['OCAMLC']+' -where').strip()+os.sep
+	v['LIB_OCAML'] = 'camlrun'
+
diff --git a/xpdeint/waf/waflib/extras/package.py b/xpdeint/waf/waflib/extras/package.py
new file mode 100644
index 0000000..b03c95c
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/package.py
@@ -0,0 +1,76 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2011
+
+"""
+Obtain packages, unpack them in a location, and add associated uselib variables
+(CFLAGS_pkgname, LIBPATH_pkgname, etc).
+
+The default is use a Dependencies.txt file in the source directory.
+
+This is a work in progress.
+
+Usage:
+
+def options(opt):
+	opt.load('package')
+
+def configure(conf):
+    conf.load_packages()
+"""
+
+from waflib import Logs
+from waflib.Configure import conf
+
+try:
+	from urllib import request
+except:
+	from urllib import urlopen
+else:
+	urlopen = request.urlopen
+
+
+CACHEVAR = 'WAFCACHE_PACKAGE'
+
+ at conf
+def get_package_cache_dir(self):
+	cache = None
+	if CACHEVAR in conf.environ:
+		cache = conf.environ[CACHEVAR]
+		cache = self.root.make_node(cache)
+	elif self.env[CACHEVAR]:
+		cache = self.env[CACHEVAR]
+		cache = self.root.make_node(cache)
+	else:
+		cache = self.srcnode.make_node('.wafcache_package')
+	cache.mkdir()
+	return cache
+
+ at conf
+def download_archive(self, src, dst):
+	for x in self.env.PACKAGE_REPO:
+		url = '/'.join((x, src))
+		try:
+			web = urlopen(url)
+			try:
+				if web.getcode() != 200:
+					continue
+			except AttributeError:
+				pass
+		except Exception:
+			# on python3 urlopen throws an exception
+			# python 2.3 does not have getcode and throws an exception to fail
+			continue
+		else:
+			tmp = self.root.make_node(dst)
+			tmp.write(web.read())
+			Logs.warn('Downloaded %s from %s' % (tmp.abspath(), url))
+			break
+	else:
+		self.fatal('Could not get the package %s' % src)
+
+ at conf
+def load_packages(self):
+	cache = self.get_package_cache_dir()
+	# read the dependencies, get the archives, ..
+
diff --git a/xpdeint/waf/waflib/extras/parallel_debug.py b/xpdeint/waf/waflib/extras/parallel_debug.py
new file mode 100644
index 0000000..25691d0
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/parallel_debug.py
@@ -0,0 +1,341 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2007-2010 (ita)
+
+"""
+Debugging helper for parallel compilation, outputs
+a file named pdebug.svg in the source directory::
+
+	def options(opt):
+		opt.load('parallel_debug')
+	def configure(conf):
+		conf.load('parallel_debug')
+	def build(bld):
+   	 ...
+"""
+
+import os, time, sys
+try: from Queue import Queue
+except: from queue import Queue
+from waflib import Runner, Options, Utils, Task, Logs, Errors
+
+#import random
+#random.seed(100)
+
+def options(opt):
+	opt.add_option('--dtitle', action='store', default='Parallel build representation for %r' % ' '.join(sys.argv),
+		help='title for the svg diagram', dest='dtitle')
+	opt.add_option('--dwidth', action='store', type='int', help='diagram width', default=800, dest='dwidth')
+	opt.add_option('--dtime', action='store', type='float', help='recording interval in seconds', default=0.009, dest='dtime')
+	opt.add_option('--dband', action='store', type='int', help='band width', default=22, dest='dband')
+	opt.add_option('--dmaxtime', action='store', type='float', help='maximum time, for drawing fair comparisons', default=0, dest='dmaxtime')
+
+# red   #ff4d4d
+# green #4da74d
+# lila  #a751ff
+
+color2code = {
+	'GREEN'  : '#4da74d',
+	'YELLOW' : '#fefe44',
+	'PINK'   : '#a751ff',
+	'RED'    : '#cc1d1d',
+	'BLUE'   : '#6687bb',
+	'CYAN'   : '#34e2e2',
+}
+
+mp = {}
+info = [] # list of (text,color)
+
+def map_to_color(name):
+	if name in mp:
+		return mp[name]
+	try:
+		cls = Task.classes[name]
+	except KeyError:
+		return color2code['RED']
+	if cls.color in mp:
+		return mp[cls.color]
+	if cls.color in color2code:
+		return color2code[cls.color]
+	return color2code['RED']
+
+def process(self):
+	m = self.master
+	if m.stop:
+		m.out.put(self)
+		return
+
+	self.master.set_running(1, id(Utils.threading.currentThread()), self)
+
+	# remove the task signature immediately before it is executed
+	# in case of failure the task will be executed again
+	try:
+		del self.generator.bld.task_sigs[self.uid()]
+	except:
+		pass
+
+	try:
+		self.generator.bld.returned_tasks.append(self)
+		self.log_display(self.generator.bld)
+		ret = self.run()
+	except Exception:
+		self.err_msg = Utils.ex_stack()
+		self.hasrun = Task.EXCEPTION
+
+		# TODO cleanup
+		m.error_handler(self)
+		m.out.put(self)
+		return
+
+	if ret:
+		self.err_code = ret
+		self.hasrun = Task.CRASHED
+	else:
+		try:
+			self.post_run()
+		except Errors.WafError:
+			pass
+		except Exception:
+			self.err_msg = Utils.ex_stack()
+			self.hasrun = Task.EXCEPTION
+		else:
+			self.hasrun = Task.SUCCESS
+	if self.hasrun != Task.SUCCESS:
+		m.error_handler(self)
+
+	self.master.set_running(-1, id(Utils.threading.currentThread()), self)
+	m.out.put(self)
+Task.Task.process = process
+
+old_start = Runner.Parallel.start
+def do_start(self):
+	try:
+		Options.options.dband
+	except AttributeError:
+		self.bld.fatal('use def options(opt): opt.load("parallel_debug")!')
+
+	self.taskinfo = Queue()
+	old_start(self)
+	if self.dirty:
+		process_colors(self)
+Runner.Parallel.start = do_start
+
+def set_running(self, by, i, tsk):
+	self.taskinfo.put( (i, id(tsk), time.time(), tsk.__class__.__name__, self.processed, self.count, by)  )
+Runner.Parallel.set_running = set_running
+
+def name2class(name):
+	return name.replace(' ', '_').replace('.', '_')
+
+def process_colors(producer):
+	# first, cast the parameters
+	tmp = []
+	try:
+		while True:
+			tup = producer.taskinfo.get(False)
+			tmp.append(list(tup))
+	except:
+		pass
+
+	try:
+		ini = float(tmp[0][2])
+	except:
+		return
+
+	if not info:
+		seen = []
+		for x in tmp:
+			name = x[3]
+			if not name in seen:
+				seen.append(name)
+			else:
+				continue
+
+			info.append((name, map_to_color(name)))
+		info.sort(key=lambda x: x[0])
+
+	thread_count = 0
+	acc = []
+	for x in tmp:
+		thread_count += x[6]
+		acc.append("%d %d %f %r %d %d %d" % (x[0], x[1], x[2] - ini, x[3], x[4], x[5], thread_count))
+	data_node = producer.bld.path.make_node('pdebug.dat')
+	data_node.write('\n'.join(acc))
+
+	tmp = [lst[:2] + [float(lst[2]) - ini] + lst[3:] for lst in tmp]
+
+	st = {}
+	for l in tmp:
+		if not l[0] in st:
+			st[l[0]] = len(st.keys())
+	tmp = [  [st[lst[0]]] + lst[1:] for lst in tmp ]
+	THREAD_AMOUNT = len(st.keys())
+
+	st = {}
+	for l in tmp:
+		if not l[1] in st:
+			st[l[1]] = len(st.keys())
+	tmp = [  [lst[0]] + [st[lst[1]]] + lst[2:] for lst in tmp ]
+
+
+	BAND = Options.options.dband
+
+	seen = {}
+	acc = []
+	for x in range(len(tmp)):
+		line = tmp[x]
+		id = line[1]
+
+		if id in seen:
+			continue
+		seen[id] = True
+
+		begin = line[2]
+		thread_id = line[0]
+		for y in range(x + 1, len(tmp)):
+			line = tmp[y]
+			if line[1] == id:
+				end = line[2]
+				#print id, thread_id, begin, end
+				#acc.append(  ( 10*thread_id, 10*(thread_id+1), 10*begin, 10*end ) )
+				acc.append( (BAND * begin, BAND*thread_id, BAND*end - BAND*begin, BAND, line[3]) )
+				break
+
+	if Options.options.dmaxtime < 0.1:
+		gwidth = 1
+		for x in tmp:
+			m = BAND * x[2]
+			if m > gwidth:
+				gwidth = m
+	else:
+		gwidth = BAND * Options.options.dmaxtime
+
+	ratio = float(Options.options.dwidth) / gwidth
+	gwidth = Options.options.dwidth
+
+	gheight = BAND * (THREAD_AMOUNT + len(info) + 1.5)
+
+	out = []
+
+	out.append("""<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>
+<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\"
+\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">
+<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.0\"
+   x=\"%r\" y=\"%r\" width=\"%r\" height=\"%r\"
+   id=\"svg602\" xml:space=\"preserve\">
+
+<style type='text/css' media='screen'>
+	g.over rect  { stroke:#FF0000; fill-opacity:0.4 }
+</style>
+
+<script type='text/javascript'><![CDATA[
+var svg  = document.getElementsByTagName('svg')[0];
+
+svg.addEventListener('mouseover', function(e) {
+	var g = e.target.parentNode;
+	var x = document.getElementById('r_' + g.id);
+	if (x) {
+		g.setAttribute('class', g.getAttribute('class') + ' over');
+		x.setAttribute('class', x.getAttribute('class') + ' over');
+		showInfo(e, g.id);
+	}
+}, false);
+
+svg.addEventListener('mouseout', function(e) {
+		var g = e.target.parentNode;
+		var x = document.getElementById('r_' + g.id);
+		if (x) {
+			g.setAttribute('class', g.getAttribute('class').replace(' over', ''));
+			x.setAttribute('class', x.getAttribute('class').replace(' over', ''));
+			hideInfo(e);
+		}
+}, false);
+
+function showInfo(evt, txt) {
+	tooltip = document.getElementById('tooltip');
+
+	var t = document.getElementById('tooltiptext');
+	t.firstChild.data = txt;
+
+	var x = evt.clientX + 9;
+	if (x > 250) { x -= t.getComputedTextLength() + 16; }
+	var y = evt.clientY + 20;
+	tooltip.setAttribute("transform", "translate(" + x + "," + y + ")");
+	tooltip.setAttributeNS(null, "visibility", "visible");
+
+	var r = document.getElementById('tooltiprect');
+	r.setAttribute('width', t.getComputedTextLength() + 6);
+}
+
+function hideInfo(evt) {
+	var tooltip = document.getElementById('tooltip');
+	tooltip.setAttributeNS(null,"visibility","hidden");
+}
+]]></script>
+
+<!-- inkscape requires a big rectangle or it will not export the pictures properly -->
+<rect
+   x='%r' y='%r'
+   width='%r' height='%r'
+   style=\"font-size:10;fill:#ffffff;fill-opacity:0.01;fill-rule:evenodd;stroke:#ffffff;\"
+   />\n
+
+""" % (0, 0, gwidth + 4, gheight + 4,   0, 0, gwidth + 4, gheight + 4))
+
+	# main title
+	if Options.options.dtitle:
+		out.append("""<text x="%d" y="%d" style="font-size:15px; text-anchor:middle; font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans">%s</text>
+""" % (gwidth/2, gheight - 5, Options.options.dtitle))
+
+	# the rectangles
+
+	groups = {}
+	for (x, y, w, h, clsname) in acc:
+		try:
+			groups[clsname].append((x, y, w, h))
+		except:
+			groups[clsname] = [(x, y, w, h)]
+	for cls in groups:
+		out.append("<g id='%s'>\n" % name2class(cls))
+
+		for (x, y, w, h) in groups[cls]:
+			out.append("""<rect
+   x='%r' y='%r'
+   width='%r' height='%r'
+   style=\"font-size:10;fill:%s;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;\"
+   />\n""" % (2 + x*ratio, 2 + y, w*ratio, h, map_to_color(cls)))
+		out.append("</g>\n")
+
+	# output the caption
+	cnt = THREAD_AMOUNT
+
+	for (text, color) in info:
+		# caption box
+		b = BAND/2
+		out.append("""<g id='r_%s'><rect
+		x='%r' y='%r'
+		width='%r' height='%r'
+		style=\"font-size:10;fill:%s;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;\"
+  />\n""" %                       (name2class(text), 2 + BAND,     5 + (cnt + 0.5) * BAND, b, b, color))
+
+		# caption text
+		out.append("""<text
+   style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+   x="%r" y="%d">%s</text></g>\n""" % (2 + 2 * BAND, 5 + (cnt + 0.5) * BAND + 10, text))
+		cnt += 1
+
+	out.append("""
+<g transform="translate(0,0)" visibility="hidden" id="tooltip">
+  <rect id="tooltiprect" y="-15" x="-3" width="1" height="20" style="stroke:black;fill:#edefc2;stroke-width:1"/>
+  <text id="tooltiptext" style="font-family:Arial; font-size:12;fill:black;"> </text>
+</g>""")
+
+	out.append("\n</svg>")
+
+	node = producer.bld.path.make_node('pdebug.svg')
+	node.write("".join(out))
+	Logs.warn('Created the diagram %r' % node.abspath())
+
+	p = node.parent.abspath()
+	producer.bld.exec_command(['convert', p + os.sep + 'pdebug.svg', p + os.sep + 'pdebug.png'])
+
diff --git a/xpdeint/waf/waflib/extras/pep8.py b/xpdeint/waf/waflib/extras/pep8.py
new file mode 100644
index 0000000..5cace1d
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/pep8.py
@@ -0,0 +1,106 @@
+#! /usr/bin/env python
+# encoding: utf-8
+#
+# written by Sylvain Rouquette, 2011
+
+'''
+Install pep8 module:
+$ easy_install pep8
+	or
+$ pip install pep8
+
+To add the boost tool to the waf file:
+$ ./waf-light --tools=compat15,pep8
+	or, if you have waf >= 1.6.2
+$ ./waf update --files=pep8
+
+
+Then add this to your wscript:
+
+[at]extension('.py', 'wscript')
+def run_pep8(self, node):
+	self.create_task('Pep8', node)
+
+'''
+
+import threading
+from waflib import TaskGen, Task, Options
+
+pep8 = __import__('pep8')
+
+
+class Pep8(Task.Task):
+	color = 'PINK'
+	lock = threading.Lock()
+
+	def check_options(self):
+		if pep8.options:
+			return
+		pep8.options = Options.options
+		pep8.options.prog = 'pep8'
+		excl = pep8.options.exclude.split(',')
+		pep8.options.exclude = [s.rstrip('/') for s in excl]
+		if pep8.options.filename:
+			pep8.options.filename = pep8.options.filename.split(',')
+		if pep8.options.select:
+			pep8.options.select = pep8.options.select.split(',')
+		else:
+			pep8.options.select = []
+		if pep8.options.ignore:
+			pep8.options.ignore = pep8.options.ignore.split(',')
+		elif pep8.options.select:
+			# Ignore all checks which are not explicitly selected
+			pep8.options.ignore = ['']
+		elif pep8.options.testsuite or pep8.options.doctest:
+			# For doctest and testsuite, all checks are required
+			pep8.options.ignore = []
+		else:
+			# The default choice: ignore controversial checks
+			pep8.options.ignore = pep8.DEFAULT_IGNORE.split(',')
+		pep8.options.physical_checks = pep8.find_checks('physical_line')
+		pep8.options.logical_checks = pep8.find_checks('logical_line')
+		pep8.options.counters = dict.fromkeys(pep8.BENCHMARK_KEYS, 0)
+		pep8.options.messages = {}
+
+	def run(self):
+		with Pep8.lock:
+			self.check_options()
+		pep8.input_file(self.inputs[0].abspath())
+		return 0 if not pep8.get_count() else -1
+
+
+def options(opt):
+	opt.add_option('-q', '--quiet', default=0, action='count',
+				   help="report only file names, or nothing with -qq")
+	opt.add_option('-r', '--repeat', action='store_true',
+				   help="show all occurrences of the same error")
+	opt.add_option('--exclude', metavar='patterns',
+				   default=pep8.DEFAULT_EXCLUDE,
+				   help="exclude files or directories which match these "
+				   "comma separated patterns (default: %s)" %
+				   pep8.DEFAULT_EXCLUDE,
+				   dest='exclude')
+	opt.add_option('--filename', metavar='patterns', default='*.py',
+				   help="when parsing directories, only check filenames "
+				   "matching these comma separated patterns (default: "
+				   "*.py)")
+	opt.add_option('--select', metavar='errors', default='',
+				   help="select errors and warnings (e.g. E,W6)")
+	opt.add_option('--ignore', metavar='errors', default='',
+				   help="skip errors and warnings (e.g. E4,W)")
+	opt.add_option('--show-source', action='store_true',
+				   help="show source code for each error")
+	opt.add_option('--show-pep8', action='store_true',
+				   help="show text of PEP 8 for each error")
+	opt.add_option('--statistics', action='store_true',
+				   help="count errors and warnings")
+	opt.add_option('--count', action='store_true',
+				   help="print total number of errors and warnings "
+				   "to standard error and set exit code to 1 if "
+				   "total is not null")
+	opt.add_option('--benchmark', action='store_true',
+				   help="measure processing speed")
+	opt.add_option('--testsuite', metavar='dir',
+				   help="run regression tests from dir")
+	opt.add_option('--doctest', action='store_true',
+				   help="run doctest on myself")
diff --git a/xpdeint/waf/waflib/extras/pgicc.py b/xpdeint/waf/waflib/extras/pgicc.py
new file mode 100644
index 0000000..f471633
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/pgicc.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Antoine Dechaume 2011
+
+"""
+Detect the PGI C compiler
+"""
+
+import sys, re
+from waflib.Configure import conf
+from waflib.Tools.compiler_c import c_compiler
+c_compiler['linux'].append('pgicc')
+
+ at conf
+def find_pgi_compiler(conf, var, name):
+	"""
+	Find the program name, and execute it to ensure it really is itself.
+	"""
+	if sys.platform == 'cygwin':
+		conf.fatal('The PGI compiler does not work on Cygwin')
+
+	v = conf.env
+	cc = None
+	if v[var]: cc = v[var]
+	elif var in conf.environ: cc = conf.environ[var]
+	if not cc: cc = conf.find_program(name, var=var)
+	if not cc: conf.fatal('PGI Compiler (%s) was not found' % name)
+	cc = conf.cmd_to_list(cc)
+
+	v[var + '_VERSION'] = conf.get_pgi_version(cc)
+	v[var] = cc
+	v[var + '_NAME'] = 'pgi'
+
+ at conf
+def get_pgi_version(conf, cc):
+	"""Find the version of a pgi compiler."""
+	version_re = re.compile(r"The Portland Group", re.I).search
+	cmd = cc + ['-V']
+
+	try:
+		out, err = conf.cmd_and_log(cmd, output=0)
+	except:
+		conf.fatal('Could not find pgi compiler %r' % cmd)
+
+	if out: match = version_re(out)
+	else: match = version_re(err)
+
+	if not match:
+		conf.fatal('Could not verify PGI signature')
+
+	cmd = cc + ['-help=variable']
+	try:
+		out, err = conf.cmd_and_log(cmd, output=0)
+	except:
+		conf.fatal('Could not find pgi compiler %r' % cmd)
+
+	version = re.findall('^COMPVER\s*=(.*)', out, re.M)
+	if len(version) != 1:
+		conf.fatal('Could not determine the compiler version')
+	return version[0]
+
+def configure(conf):
+	conf.find_pgi_compiler('CC', 'pgcc')
+	conf.find_ar()
+	conf.gcc_common_flags()
+	conf.cc_load_tools()
+	conf.cc_add_flags()
+	conf.link_add_flags()
+
diff --git a/xpdeint/waf/waflib/extras/pgicxx.py b/xpdeint/waf/waflib/extras/pgicxx.py
new file mode 100644
index 0000000..926f40a
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/pgicxx.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Antoine Dechaume 2011
+
+"""
+Detect the PGI C++ compiler
+"""
+
+import sys, re
+from waflib.Configure import conf
+from waflib.Tools.compiler_cxx import cxx_compiler
+cxx_compiler['linux'].append('pgicxx')
+
+from waflib.extras import pgicc
+
+def configure(conf):
+	conf.find_pgi_compiler('CXX', 'pgCC')
+	conf.find_ar()
+	conf.gxx_common_flags()
+	conf.cxx_load_tools()
+	conf.cxx_add_flags()
+	conf.link_add_flags()
diff --git a/xpdeint/waf/waflib/extras/print_commands.py b/xpdeint/waf/waflib/extras/print_commands.py
new file mode 100644
index 0000000..c9d5794
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/print_commands.py
@@ -0,0 +1,45 @@
+#! /usr/bin/env python
+
+"""
+Illustrate how to override a class method to do something
+
+In this case, print the commands being executed as strings
+(the commands are usually lists, so this can be misleading)
+"""
+
+from waflib import Context, Utils, Logs
+
+def exec_command(self, cmd, **kw):
+	subprocess = Utils.subprocess
+	kw['shell'] = isinstance(cmd, str)
+
+	txt = cmd
+	if isinstance(cmd, list):
+		txt = ' '.join(cmd)
+
+	print(txt)
+	Logs.debug('runner_env: kw=%s' % kw)
+
+	try:
+		if self.logger:
+			# warning: may deadlock with a lot of output (subprocess limitation)
+
+			self.logger.info(cmd)
+
+			kw['stdout'] = kw['stderr'] = subprocess.PIPE
+			p = subprocess.Popen(cmd, **kw)
+			(out, err) = p.communicate()
+			if out:
+				self.logger.debug('out: %s' % out.decode(sys.stdout.encoding or 'iso8859-1'))
+			if err:
+				self.logger.error('err: %s' % err.decode(sys.stdout.encoding or 'iso8859-1'))
+			return p.returncode
+		else:
+			p = subprocess.Popen(cmd, **kw)
+			return p.wait()
+	except OSError:
+		return -1
+
+Context.Context.exec_command = exec_command
+
+
diff --git a/xpdeint/waf/waflib/extras/proc.py b/xpdeint/waf/waflib/extras/proc.py
new file mode 100644
index 0000000..f97adef
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/proc.py
@@ -0,0 +1,56 @@
+#! /usr/bin/env python
+# per rosengren 2011
+
+from os import environ, path
+from waflib import TaskGen, Utils
+
+def options(opt):
+	grp = opt.add_option_group('Oracle ProC Options')
+	grp.add_option('--oracle_home', action='store', default=environ.get('PROC_ORACLE'), help='Path to Oracle installation home (has bin/lib)')
+	grp.add_option('--tns_admin', action='store', default=environ.get('TNS_ADMIN'), help='Directory containing server list (TNS_NAMES.ORA)')
+	grp.add_option('--connection', action='store', default='dummy-user/dummy-password at dummy-server', help='Format: user/password at server')
+
+def configure(cnf):
+	env = cnf.env
+	if not env.PROC_ORACLE:
+		env.PROC_ORACLE = cnf.options.oracle_home
+	if not env.PROC_TNS_ADMIN:
+		env.PROC_TNS_ADMIN = cnf.options.tns_admin
+	if not env.PROC_CONNECTION:
+		env.PROC_CONNECTION = cnf.options.connection
+	cnf.find_program('proc', var='PROC', path_list=env.PROC_ORACLE + path.sep + 'bin')
+
+def proc(tsk):
+	env = tsk.env
+	gen = tsk.generator
+	bld = gen.bld
+	inc_nodes = gen.to_incnodes(Utils.to_list(getattr(gen,'includes',[])) + env['INCLUDES'])
+
+	# FIXME the if-else construct will not work in python 2
+	cmd = (
+		[env.PROC] +
+		['SQLCHECK=SEMANTICS'] +
+		(['SYS_INCLUDE=(' + ','.join(env.PROC_INCLUDES) + ')']
+			if env.PROC_INCLUDES else []) +
+		['INCLUDE=(' + ','.join(
+			[i.bldpath() for i in inc_nodes]
+		) + ')'] +
+		['userid=' + env.PROC_CONNECTION] +
+		['INAME=' + tsk.inputs[0].bldpath()] +
+		['ONAME=' + tsk.outputs[0].bldpath()]
+	)
+	exec_env = {
+		'ORACLE_HOME': env.PROC_ORACLE,
+		'LD_LIBRARY_PATH': env.PROC_ORACLE + path.sep + 'lib',
+	}
+	if env.PROC_TNS_ADMIN:
+		exec_env['TNS_ADMIN'] = env.PROC_TNS_ADMIN
+	return tsk.exec_command(cmd, env=exec_env)
+
+TaskGen.declare_chain(
+	name = 'proc',
+	rule = proc,
+	ext_in = '.pc',
+	ext_out = '.c',
+)
+
diff --git a/xpdeint/waf/waflib/extras/qnxnto.py b/xpdeint/waf/waflib/extras/qnxnto.py
new file mode 100644
index 0000000..d764176
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/qnxnto.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Jérôme Carretero 2011 (zougloub)
+# QNX neutrino compatibility functions
+
+import sys, os
+from waflib import Utils
+
+class Popen(object):
+	"""
+	Popen cannot work on QNX from a threaded program:
+	Forking in threads is not implemented in neutrino.
+
+	Python's os.popen / spawn / fork won't work when running in threads (they will if in the main program thread)
+
+	In waf, this happens mostly in build.
+	And the use cases can be replaced by os.system() calls.
+	"""
+	__slots__ = ["prog", "kw", "popen", "verbose"]
+	verbose = 0
+	def __init__(self, prog, **kw):
+		try:
+			self.prog = prog
+			self.kw = kw
+			self.popen = None
+			if Popen.verbose:
+				sys.stdout.write("Popen created: %r, kw=%r..." % (prog, kw))
+
+			do_delegate = kw.get('stdout', None) == -1 and kw.get('stderr', None) == -1
+			if do_delegate:
+				if Popen.verbose:
+					print("Delegating to real Popen")
+				self.popen = self.real_Popen(prog, **kw)
+			else:
+				if Popen.verbose:
+					print("Emulating")
+		except Exception, e:
+			if Popen.verbose:
+				print("Exception: %s" % e)
+			raise
+
+	def __getattr__(self, name):
+		if Popen.verbose:
+			sys.stdout.write("Getattr: %s..." % name)
+		if name in Popen.__slots__:
+			if Popen.verbose:
+				print("In slots!")
+			return object.__getattr__(self, name)
+		else:
+			if self.popen is not None:
+				if Popen.verbose:
+					print("from Popen")
+				return getattr(self.popen, name)
+			else:
+				if name == "wait":
+					return self.emu_wait
+				else:
+					raise Exception("subprocess emulation: not implemented: %s" % name)
+
+	def emu_wait(self):
+		if Popen.verbose:
+			print("emulated wait (%r kw=%r)" % (self.prog, self.kw))
+		if isinstance(self.prog, str):
+			cmd = self.prog
+		else:
+			cmd = " ".join(self.prog)
+		if 'cwd' in self.kw:
+			cmd = 'cd "%s" && %s' % (self.kw['cwd'], cmd)
+		return os.system(cmd)
+
+if sys.platform == "qnx6":
+	Popen.real_Popen = Utils.subprocess.Popen
+	Utils.subprocess.Popen = Popen
+
diff --git a/xpdeint/waf/waflib/extras/relocation.py b/xpdeint/waf/waflib/extras/relocation.py
new file mode 100644
index 0000000..ab8dd36
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/relocation.py
@@ -0,0 +1,85 @@
+#! /usr/bin/env python
+# encoding: utf-8
+
+"""
+Waf 1.6
+
+Try to detect if the project directory was relocated, and if it was,
+change the node representing the project directory. Just call:
+
+ waf configure build
+
+Note that if the project directory name changes, the signatures for the tasks using
+files in that directory will change, causing a partial build.
+"""
+
+import os
+from waflib import Build, ConfigSet, Task, Utils, Errors
+from waflib.TaskGen import feature, before_method, after_method
+
+EXTRA_LOCK = '.old_srcdir'
+
+old1 = Build.BuildContext.store
+def store(self):
+	old1(self)
+	db = os.path.join(self.variant_dir, EXTRA_LOCK)
+	env = ConfigSet.ConfigSet()
+	env.SRCDIR = self.srcnode.abspath()
+	env.store(db)
+Build.BuildContext.store = store
+
+old2 = Build.BuildContext.init_dirs
+def init_dirs(self):
+
+	if not (os.path.isabs(self.top_dir) and os.path.isabs(self.out_dir)):
+		raise Errors.WafError('The project was not configured: run "waf configure" first!')
+
+	srcdir = None
+	db = os.path.join(self.variant_dir, EXTRA_LOCK)
+	env = ConfigSet.ConfigSet()
+	try:
+		env.load(db)
+		srcdir = env.SRCDIR
+	except:
+		pass
+
+	if srcdir:
+		d = self.root.find_node(srcdir)
+		if d and srcdir != self.top_dir and getattr(d, 'children', ''):
+			srcnode = self.root.make_node(self.top_dir)
+			print("relocating the source directory %r -> %r" % (srcdir, self.top_dir))
+			srcnode.children = {}
+
+			for (k, v) in d.children.items():
+				srcnode.children[k] = v
+				v.parent = srcnode
+			d.children = {}
+
+	old2(self)
+
+Build.BuildContext.init_dirs = init_dirs
+
+
+def uid(self):
+	try:
+		return self.uid_
+	except AttributeError:
+		# this is not a real hot zone, but we want to avoid surprizes here
+		m = Utils.md5()
+		up = m.update
+		up(self.__class__.__name__.encode())
+		for x in self.inputs + self.outputs:
+			up(x.path_from(x.ctx.srcnode).encode())
+		self.uid_ = m.digest()
+		return self.uid_
+Task.Task.uid = uid
+
+ at feature('c', 'cxx', 'd', 'go', 'asm', 'fc', 'includes')
+ at after_method('propagate_uselib_vars', 'process_source')
+def apply_incpaths(self):
+	lst = self.to_incnodes(self.to_list(getattr(self, 'includes', [])) + self.env['INCLUDES'])
+	self.includes_nodes = lst
+	bld = self.bld
+	self.env['INCPATHS'] = [x.is_child_of(bld.srcnode) and x.path_from(bld.srcnode) or x.abspath() for x in lst]
+
+
diff --git a/xpdeint/waf/waflib/extras/review.py b/xpdeint/waf/waflib/extras/review.py
new file mode 100644
index 0000000..4a7ad2f
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/review.py
@@ -0,0 +1,328 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Laurent Birtz, 2011
+# moved the code into a separate tool (ita)
+
+"""
+There are several things here:
+- a different command-line option management making options persistent
+- the review command to display the options set
+
+Assumptions:
+- configuration options are not always added to the right group (and do not count on the users to do it...)
+- the options are persistent between the executions (waf options are NOT persistent by design), even for the configuration
+- when the options change, the build is invalidated (forcing a reconfiguration)
+"""
+
+import os, textwrap, shutil
+from waflib import Logs, Context, ConfigSet, Options, Build, Configure
+
+class Odict(dict):
+	"""Ordered dictionary"""
+	def __init__(self, data=None):
+		self._keys = []
+		dict.__init__(self)
+		if data:
+			# we were provided a regular dict
+			if isinstance(data, dict):
+				self.append_from_dict(data)
+
+			# we were provided a tuple list
+			elif type(data) == list:
+				self.append_from_plist(data)
+
+			# we were provided invalid input
+			else:
+				raise Exception("expected a dict or a tuple list")
+
+	def append_from_dict(self, dict):
+		map(self.__setitem__, dict.keys(), dict.values())
+
+	def append_from_plist(self, plist):
+		for pair in plist:
+			if len(pair) != 2:
+				raise Exception("invalid pairs list")
+		for (k, v) in plist:
+			self.__setitem__(k, v)
+
+	def __delitem__(self, key):
+		if not key in self._keys:
+			raise KeyError(key)
+		dict.__delitem__(self, key)
+		self._keys.remove(key)
+
+	def __setitem__(self, key, item):
+		dict.__setitem__(self, key, item)
+		if key not in self._keys:
+			self._keys.append(key)
+
+	def clear(self):
+		dict.clear(self)
+		self._keys = []
+
+	def copy(self):
+		return Odict(self.plist())
+
+	def items(self):
+		return zip(self._keys, self.values())
+
+	def keys(self):
+		return list(self._keys) # return a copy of the list
+
+	def values(self):
+		return map(self.get, self._keys)
+
+	def plist(self):
+		p = []
+		for k, v in self.items():
+			p.append( (k, v) )
+		return p
+
+	def __str__(self):
+		s = "{"
+		l = len(self._keys)
+		for k, v in self.items():
+			l -= 1
+			strkey = str(k)
+			if isinstance(k, basestring): strkey = "'"+strkey+"'"
+			strval = str(v)
+			if isinstance(v, basestring): strval = "'"+strval+"'"
+			s += strkey + ":" + strval
+			if l > 0: s += ", "
+		s += "}"
+		return s
+
+review_options = Odict()
+"""
+Ordered dictionary mapping configuration option names to their optparse option.
+"""
+
+review_defaults = {}
+"""
+Dictionary mapping configuration option names to their default value.
+"""
+
+old_review_set = None
+"""
+Review set containing the configuration values before parsing the command line.
+"""
+
+new_review_set = None
+"""
+Review set containing the configuration values after parsing the command line.
+"""
+
+class OptionsReview(Options.OptionsContext):
+	def __init__(self, **kw):
+		super(self.__class__, self).__init__(**kw)
+
+	def prepare_config_review(self):
+		"""
+		Find the configuration options that are reviewable, detach
+		their default value from their optparse object and store them
+		into the review dictionaries.
+		"""
+		gr = self.get_option_group('configure options')
+		for opt in gr.option_list:
+			if opt.action != 'store' or opt.dest in ("out", "top"):
+				continue
+			review_options[opt.dest] = opt
+			review_defaults[opt.dest] = opt.default
+			if gr.defaults.has_key(opt.dest):
+				del gr.defaults[opt.dest]
+			opt.default = None
+
+	def parse_args(self):
+		self.prepare_config_review()
+		self.parser.get_option('--prefix').help = 'installation prefix'
+		super(OptionsReview, self).parse_args()
+		Context.create_context('review').refresh_review_set()
+
+class ReviewContext(Context.Context):
+	'''reviews the configuration values'''
+
+	cmd = 'review'
+
+	def __init__(self, **kw):
+		super(self.__class__, self).__init__(**kw)
+
+		out = Options.options.out
+		if not out:
+			out = getattr(Context.g_module, Context.OUT, None)
+		if not out:
+			out = Options.lockfile.replace('.lock-waf', '')
+		self.build_path = (os.path.isabs(out) and self.root or self.path).make_node(out).abspath()
+		"""Path to the build directory"""
+
+		self.cache_path = os.path.join(self.build_path, Build.CACHE_DIR)
+		"""Path to the cache directory"""
+
+		self.review_path = os.path.join(self.cache_path, 'review.cache')
+		"""Path to the review cache file"""
+
+	def execute(self):
+		"""
+		Display and store the review set. Invalidate the cache as required.
+		"""
+		if not self.compare_review_set(old_review_set, new_review_set):
+			self.invalidate_cache()
+		self.store_review_set(new_review_set)
+		print(self.display_review_set(new_review_set))
+
+	def invalidate_cache(self):
+		"""Invalidate the cache to prevent bad builds."""
+		try:
+			Logs.warn("Removing the cached configuration since the options have changed")
+			shutil.rmtree(self.cache_path)
+		except:
+			pass
+
+	def refresh_review_set(self):
+		"""
+		Obtain the old review set and the new review set, and import the new set.
+		"""
+		global old_review_set, new_review_set
+		old_review_set = self.load_review_set()
+		new_review_set = self.update_review_set(old_review_set)
+		self.import_review_set(new_review_set)
+
+	def load_review_set(self):
+		"""
+		Load and return the review set from the cache if it exists.
+		Otherwise, return an empty set.
+		"""
+		if os.path.isfile(self.review_path):
+			return ConfigSet.ConfigSet(self.review_path)
+		return ConfigSet.ConfigSet()
+
+	def store_review_set(self, review_set):
+		"""
+		Store the review set specified in the cache.
+		"""
+		if not os.path.isdir(self.cache_path):
+			os.makedirs(self.cache_path)
+		review_set.store(self.review_path)
+
+	def update_review_set(self, old_set):
+		"""
+		Merge the options passed on the command line with those imported
+		from the previous review set and return the corresponding
+		preview set.
+		"""
+
+		# Convert value to string. It's important that 'None' maps to
+		# the empty string.
+		def val_to_str(val):
+			if val == None or val == '':
+				return ''
+			return str(val)
+
+		new_set = ConfigSet.ConfigSet()
+		opt_dict = Options.options.__dict__
+
+		for name in review_options.keys():
+			# the option is specified explicitly on the command line
+			if name in opt_dict:
+				# if the option is the default, pretend it was never specified
+				if val_to_str(opt_dict[name]) != val_to_str(review_defaults[name]):
+					new_set[name] = opt_dict[name]
+			# the option was explicitly specified in a previous command
+			elif name in old_set:
+				new_set[name] = old_set[name]
+
+		return new_set
+
+	def import_review_set(self, review_set):
+		"""
+		Import the actual value of the reviewable options in the option
+		dictionary, given the current review set.
+		"""
+		for name in review_options.keys():
+			if name in review_set:
+				value = review_set[name]
+			else:
+				value = review_defaults[name]
+			setattr(Options.options, name, value)
+
+	def compare_review_set(self, set1, set2):
+		"""
+		Return true if the review sets specified are equal.
+		"""
+		if len(set1.keys()) != len(set2.keys()): return False
+		for key in set1.keys():
+			if not key in set2 or set1[key] != set2[key]:
+				return False
+		return True
+
+	def display_review_set(self, review_set):
+		"""
+		Return the string representing the review set specified.
+		"""
+		term_width = Logs.get_term_cols()
+		lines = []
+		for dest in review_options.keys():
+			opt = review_options[dest]
+			name = ", ".join(opt._short_opts + opt._long_opts)
+			help = opt.help
+			actual = None
+			if dest in review_set: actual = review_set[dest]
+			default = review_defaults[dest]
+			lines.append(self.format_option(name, help, actual, default, term_width))
+		return "Configuration:\n\n" + "\n\n".join(lines) + "\n"
+
+	def format_option(self, name, help, actual, default, term_width):
+		"""
+		Return the string representing the option specified.
+		"""
+		def val_to_str(val):
+			if val == None or val == '':
+				return "(void)"
+			return str(val)
+
+		max_name_len = 20
+		sep_len = 2
+
+		w = textwrap.TextWrapper()
+		w.width = term_width - 1
+		if w.width < 60: w.width = 60
+
+		out = ""
+
+		# format the help
+		out += w.fill(help) + "\n"
+
+		# format the name
+		name_len = len(name)
+		out += Logs.colors.CYAN + name + Logs.colors.NORMAL
+
+		# set the indentation used when the value wraps to the next line
+		w.subsequent_indent = " ".rjust(max_name_len + sep_len)
+		w.width -= (max_name_len + sep_len)
+
+		# the name string is too long, switch to the next line
+		if name_len > max_name_len:
+			out += "\n" + w.subsequent_indent
+
+		# fill the remaining of the line with spaces
+		else:
+			out += " ".rjust(max_name_len + sep_len - name_len)
+
+		# format the actual value, if there is one
+		if actual != None:
+			out += Logs.colors.BOLD + w.fill(val_to_str(actual)) + Logs.colors.NORMAL + "\n" + w.subsequent_indent
+
+		# format the default value
+		default_fmt = val_to_str(default)
+		if actual != None:
+			default_fmt = "default: " + default_fmt
+		out += Logs.colors.NORMAL + w.fill(default_fmt) + Logs.colors.NORMAL
+
+		return out
+
+# Monkey-patch ConfigurationContext.execute() to have it store the review set.
+old_configure_execute = Configure.ConfigurationContext.execute
+def new_configure_execute(self):
+	old_configure_execute(self)
+	Context.create_context('review').store_review_set(new_review_set)
+Configure.ConfigurationContext.execute = new_configure_execute
+
diff --git a/xpdeint/waf/waflib/extras/sas.py b/xpdeint/waf/waflib/extras/sas.py
new file mode 100644
index 0000000..79c9a51
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/sas.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Mark Coggeshall, 2010
+
+"SAS support"
+
+import os, re
+from waflib import Utils, Task, TaskGen, Runner, Build, Errors, Node
+from waflib.TaskGen import feature, before_method
+from waflib.Logs import error, warn, debug
+
+sas_fun, _ = Task.compile_fun('sas -sysin ${SRCFILE} -log ${LOGFILE} -print ${LSTFILE}', shell=False)
+
+class sas(Task.Task):
+	vars = ['SAS', 'SASFLAGS']
+	def run(task):
+		command = 'SAS'
+		env = task.env
+		bld = task.generator.bld
+
+		fun = sas_fun
+
+		node = task.inputs[0]
+		logfilenode = node.change_ext('.log')
+		lstfilenode = node.change_ext('.lst')
+
+		# set the cwd
+		task.cwd = task.inputs[0].parent.get_src().abspath()
+		debug('runner: %s on %s' % (command, node.abspath))
+
+		SASINPUTS = node.parent.get_bld().abspath() + os.pathsep + node.parent.get_src().abspath() + os.pathsep
+		task.env.env = {'SASINPUTS': SASINPUTS}
+
+		task.env.SRCFILE = node.abspath()
+		task.env.LOGFILE = logfilenode.abspath()
+		task.env.LSTFILE = lstfilenode.abspath()
+		ret = fun(task)
+		if ret:
+			error('Running %s on %r returned a non-zero exit' % (command, node))
+			error('SRCFILE = %r' % node)
+			error('LOGFILE = %r' % logfilenode)
+			error('LSTFILE = %r' % lstfilenode)
+		return ret
+
+ at feature('sas')
+ at before_method('process_source')
+def apply_sas(self):
+	if not getattr(self, 'type', None) in ['sas']:
+		self.type = 'sas'
+
+	self.env['logdir'] = getattr(self, 'logdir', 'log')
+	self.env['lstdir'] = getattr(self, 'lstdir', 'lst')
+
+	deps_lst = []
+
+	if getattr(self, 'deps', None):
+		deps = self.to_list(self.deps)
+		for filename in deps:
+			n = self.path.find_resource(filename)
+			if not n: n = self.bld.root.find_resource(filename)
+			if not n: raise Errors.WafError('cannot find input file %s for processing' % filename)
+			if not n in deps_lst: deps_lst.append(n)
+
+	for node in self.to_nodes(self.source):
+		if self.type == 'sas':
+			task = self.create_task('sas', src=node)
+		task.dep_nodes = deps_lst
+	self.source = []
+
+def configure(self):
+	self.find_program('sas', var='SAS', mandatory=False)
+
diff --git a/xpdeint/waf/waflib/extras/scala.py b/xpdeint/waf/waflib/extras/scala.py
new file mode 100644
index 0000000..e7b6d23
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/scala.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2010 (ita)
+
+"""
+Scala support
+
+scalac outputs files a bit where it wants to
+"""
+
+import os, re
+from waflib.Configure import conf
+from waflib import TaskGen, Task, Utils, Options, Build, Errors, Node
+from waflib.TaskGen import feature, before_method, after_method
+
+from waflib.Tools import ccroot
+ccroot.USELIB_VARS['scalac'] = set(['CLASSPATH', 'SCALACFLAGS'])
+
+from waflib.Tools import javaw
+
+ at feature('scalac')
+ at before_method('process_source')
+def apply_scalac(self):
+
+	Utils.def_attrs(self, jarname='', classpath='',
+		sourcepath='.', srcdir='.',
+		jar_mf_attributes={}, jar_mf_classpath=[])
+
+	nodes_lst = []
+
+	outdir = getattr(self, 'outdir', None)
+	if outdir:
+		if not isinstance(outdir, Node.Node):
+			outdir = self.path.get_bld().make_node(self.outdir)
+	else:
+		outdir = self.path.get_bld()
+	outdir.mkdir()
+	self.env['OUTDIR'] = outdir.abspath()
+
+	self.scalac_task = tsk = self.create_task('scalac')
+	tmp = []
+
+	srcdir = getattr(self, 'srcdir', '')
+	if isinstance(srcdir, Node.Node):
+		srcdir = [srcdir]
+	for x in Utils.to_list(srcdir):
+		if isinstance(x, Node.Node):
+			y = x
+		else:
+			y = self.path.find_dir(x)
+			if not y:
+				self.bld.fatal('Could not find the folder %s from %s' % (x, self.path))
+		tmp.append(y)
+	tsk.srcdir = tmp
+
+# reuse some code
+feature('scalac')(javaw.use_javac_files)
+after_method('apply_scalac')(javaw.use_javac_files)
+
+feature('scalac')(javaw.set_classpath)
+after_method('apply_scalac', 'use_scalac_files')(javaw.set_classpath)
+
+
+SOURCE_RE = '**/*.scala'
+class scalac(javaw.javac):
+	color = 'GREEN'
+	vars    = ['CLASSPATH', 'SCALACFLAGS', 'SCALAC', 'OUTDIR']
+
+	def runnable_status(self):
+		"""
+		Wait for dependent tasks to be complete, then read the file system to find the input nodes.
+		"""
+		for t in self.run_after:
+			if not t.hasrun:
+				return Task.ASK_LATER
+
+		if not self.inputs:
+			global SOURCE_RE
+			self.inputs  = []
+			for x in self.srcdir:
+				self.inputs.extend(x.ant_glob(SOURCE_RE, remove=False))
+		return super(javaw.javac, self).runnable_status()
+
+	def run(self):
+		"""
+		Execute the scalac compiler
+		"""
+		env = self.env
+		gen = self.generator
+		bld = gen.bld
+		wd = bld.bldnode.abspath()
+		def to_list(xx):
+			if isinstance(xx, str): return [xx]
+			return xx
+		self.last_cmd = lst = []
+		lst.extend(to_list(env['SCALAC']))
+		lst.extend(['-classpath'])
+		lst.extend(to_list(env['CLASSPATH']))
+		lst.extend(['-d'])
+		lst.extend(to_list(env['OUTDIR']))
+		lst.extend(to_list(env['SCALACFLAGS']))
+		lst.extend([a.abspath() for a in self.inputs])
+		lst = [x for x in lst if x]
+		try:
+			self.out = self.generator.bld.cmd_and_log(lst, cwd=wd, env=env.env or None, output=0, quiet=0)[1]
+		except:
+			self.generator.bld.cmd_and_log(lst, cwd=wd, env=env.env or None)
+
+def configure(self):
+	"""
+	Detect the scalac program
+	"""
+	# If SCALA_HOME is set, we prepend it to the path list
+	java_path = self.environ['PATH'].split(os.pathsep)
+	v = self.env
+
+	if 'SCALA_HOME' in self.environ:
+		java_path = [os.path.join(self.environ['SCALA_HOME'], 'bin')] + java_path
+		self.env['SCALA_HOME'] = [self.environ['SCALA_HOME']]
+
+	for x in 'scalac scala'.split():
+		self.find_program(x, var=x.upper(), path_list=java_path)
+		self.env[x.upper()] = self.cmd_to_list(self.env[x.upper()])
+
+	if 'CLASSPATH' in self.environ:
+		v['CLASSPATH'] = self.environ['CLASSPATH']
+
+	v.SCALACFLAGS = ['-verbose']
+	if not v['SCALAC']: self.fatal('scalac is required for compiling scala classes')
+
diff --git a/xpdeint/waf/waflib/extras/slow_qt4.py b/xpdeint/waf/waflib/extras/slow_qt4.py
new file mode 100644
index 0000000..3ba6a81
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/slow_qt4.py
@@ -0,0 +1,95 @@
+#! /usr/bin/env python
+# Thomas Nagy, 2011 (ita)
+
+"""
+Create _moc.cpp files
+
+The builds are 30-40% faster when .moc files are included,
+you should NOT use this tool. If you really
+really want it:
+
+def configure(conf):
+	conf.load('compiler_cxx qt4')
+	conf.load('slow_qt4')
+
+See playground/slow_qt/wscript for a complete example.
+"""
+
+from waflib.TaskGen import extension
+from waflib import Task
+import waflib.Tools.qt4
+import waflib.Tools.cxx
+
+ at extension(*waflib.Tools.qt4.EXT_QT4)
+def cxx_hook(self, node):
+	self.create_compiled_task('cxx_qt', node)
+
+class cxx_qt(waflib.Tools.cxx.cxx):
+	def runnable_status(self):
+		ret = waflib.Tools.cxx.cxx.runnable_status(self)
+		if ret != Task.ASK_LATER and not getattr(self, 'moc_done', None):
+
+			try:
+				cache = self.generator.moc_cache
+			except AttributeError:
+				cache = self.generator.moc_cache = {}
+
+			deps = self.generator.bld.node_deps[self.uid()]
+			for x in [self.inputs[0]] + deps:
+				if x.read().find('Q_OBJECT') > 0:
+
+					# process "foo.h -> foo.moc" only if "foo.cpp" is in the sources for the current task generator
+					# this code will work because it is in the main thread (runnable_status)
+					if x.name.rfind('.') > -1: # a .h file...
+						name = x.name[:x.name.rfind('.')]
+						for tsk in self.generator.compiled_tasks:
+							if tsk.inputs and tsk.inputs[0].name.startswith(name):
+								break
+						else:
+							# no corresponding file, continue
+							continue
+
+					# the file foo.cpp could be compiled for a static and a shared library - hence the %number in the name
+					cxx_node = x.parent.get_bld().make_node(x.name.replace('.', '_') + '_%d_moc.cpp' % self.generator.idx)
+					if cxx_node in cache:
+						continue
+					cache[cxx_node] = self
+
+					tsk = Task.classes['moc'](env=self.env, generator=self.generator)
+					tsk.set_inputs(x)
+					tsk.set_outputs(cxx_node)
+
+					if x.name.endswith('.cpp'):
+						# moc is trying to be too smart but it is too dumb:
+						# why forcing the #include when Q_OBJECT is in the cpp file?
+						gen = self.generator.bld.producer
+						gen.outstanding.insert(0, tsk)
+						gen.total += 1
+						self.set_run_after(tsk)
+					else:
+						cxxtsk = Task.classes['cxx'](env=self.env, generator=self.generator)
+						cxxtsk.set_inputs(tsk.outputs)
+						cxxtsk.set_outputs(cxx_node.change_ext('.o'))
+						cxxtsk.set_run_after(tsk)
+
+						try:
+							self.more_tasks.extend([tsk, cxxtsk])
+						except AttributeError:
+							self.more_tasks = [tsk, cxxtsk]
+
+						try:
+							link = self.generator.link_task
+						except:
+							pass
+						else:
+							link.set_run_after(cxxtsk)
+							link.inputs.extend(cxxtsk.outputs)
+
+			self.moc_done = True
+
+		for t in self.run_after:
+			if not t.hasrun:
+				return Task.ASK_LATER
+
+		return ret
+
diff --git a/xpdeint/waf/waflib/extras/smart_continue.py b/xpdeint/waf/waflib/extras/smart_continue.py
new file mode 100644
index 0000000..3af7b1f
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/smart_continue.py
@@ -0,0 +1,81 @@
+#! /usr/bin/env python
+# Thomas Nagy, 2011
+
+# Try to cancel the tasks that cannot run with the option -k when an error occurs:
+# 1 direct file dependencies
+# 2 tasks listed in the before/after/ext_in/ext_out attributes
+
+from waflib import Task, Runner
+
+Task.CANCELED = 4
+
+def cancel_next(self, tsk):
+	if not isinstance(tsk, Task.TaskBase):
+		return
+	if tsk.hasrun >= Task.SKIPPED:
+		# normal execution, no need to do anything here
+		return
+
+	try:
+		canceled_tasks, canceled_nodes = self.canceled_tasks, self.canceled_nodes
+	except AttributeError:
+		canceled_tasks = self.canceled_tasks = set([])
+		canceled_nodes = self.canceled_nodes = set([])
+
+	try:
+		canceled_nodes.update(tsk.outputs)
+	except AttributeError:
+		pass
+
+	try:
+		canceled_tasks.add(tsk)
+	except AttributeError:
+		pass
+
+def get_out(self):
+	tsk = self.out.get()
+	if not self.stop:
+		self.add_more_tasks(tsk)
+	self.count -= 1
+	self.dirty = True
+	self.cancel_next(tsk) # new code
+
+def error_handler(self, tsk):
+	if not self.bld.keep:
+		self.stop = True
+	self.error.append(tsk)
+	self.cancel_next(tsk) # new code
+
+Runner.Parallel.cancel_next = cancel_next
+Runner.Parallel.get_out = get_out
+Runner.Parallel.error_handler = error_handler
+
+def get_next_task(self):
+	tsk = self.get_next_task_smart_continue()
+	if not tsk:
+		return tsk
+
+	try:
+		canceled_tasks, canceled_nodes = self.canceled_tasks, self.canceled_nodes
+	except AttributeError:
+		pass
+	else:
+		# look in the tasks that this one is waiting on
+		# if one of them was canceled, cancel this one too
+		for x in tsk.run_after:
+			if x in canceled_tasks:
+				tsk.hasrun = Task.CANCELED
+				self.cancel_next(tsk)
+				break
+		else:
+			# so far so good, now consider the nodes
+			for x in getattr(tsk, 'inputs', []) + getattr(tsk, 'deps', []):
+				if x in canceled_nodes:
+					tsk.hasrun = Task.CANCELED
+					self.cancel_next(tsk)
+					break
+	return tsk
+
+Runner.Parallel.get_next_task_smart_continue = Runner.Parallel.get_next_task
+Runner.Parallel.get_next_task = get_next_task
+
diff --git a/xpdeint/waf/waflib/extras/softlink_libs.py b/xpdeint/waf/waflib/extras/softlink_libs.py
new file mode 100644
index 0000000..ad63da4
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/softlink_libs.py
@@ -0,0 +1,74 @@
+#! /usr/bin/env python
+# per rosengren 2011
+
+from waflib.TaskGen import feature, after_method
+from waflib.Task import Task, always_run
+from os.path import basename, isabs
+from os import tmpfile, linesep
+
+def options(opt):
+	grp = opt.add_option_group('Softlink Libraries Options')
+	grp.add_option('--exclude', default='/usr/lib,/lib', help='No symbolic links are created for libs within [%default]')
+
+def configure(cnf):
+	cnf.find_program('ldd')
+	if not cnf.env.SOFTLINK_EXCLUDE:
+		cnf.env.SOFTLINK_EXCLUDE = cnf.options.exclude.split(',')
+
+ at feature('softlink_libs')
+ at after_method('process_rule')
+def add_finder(self):
+	tgt = self.path.find_or_declare(self.target)
+	self.create_task('sll_finder', tgt=tgt)
+	self.create_task('sll_installer', tgt=tgt)
+	always_run(sll_installer)
+
+class sll_finder(Task):
+	ext_out = 'softlink_libs'
+	def run(self):
+		bld = self.generator.bld
+		linked=[]
+		target_paths = []
+		for g in bld.groups:
+			for tgen in g:
+				# FIXME it might be better to check if there is a link_task (getattr?)
+				target_paths += [tgen.path.get_bld().bldpath()]
+				linked += [t.outputs[0].bldpath()
+					for t in getattr(tgen, 'tasks', [])
+					if t.__class__.__name__ in
+					['cprogram', 'cshlib', 'cxxprogram', 'cxxshlib']]
+		lib_list = []
+		if len(linked):
+			cmd = [self.env.LDD] + linked
+			# FIXME add DYLD_LIBRARY_PATH+PATH for osx+win32
+			ldd_env = {'LD_LIBRARY_PATH': ':'.join(target_paths + self.env.LIBPATH)}
+			# FIXME the with syntax will not work in python 2
+			with tmpfile() as result:
+				self.exec_command(cmd, env=ldd_env, stdout=result)
+				result.seek(0)
+				for line in result.readlines():
+					words = line.split()
+					if len(words) < 3 or words[1] != '=>': continue
+					lib = words[2]
+					if lib == 'not': continue
+					if any([lib.startswith(p) for p in
+							[bld.bldnode.abspath(), '('] +
+							self.env.SOFTLINK_EXCLUDE]):
+						continue
+					if not isabs(lib):
+						continue
+					lib_list.append(lib)
+			lib_list = sorted(set(lib_list))
+		self.outputs[0].write(linesep.join(lib_list + self.env.DYNAMIC_LIBS))
+		return 0
+
+class sll_installer(Task):
+	ext_in = 'softlink_libs'
+	def run(self):
+		tgt = self.outputs[0]
+		self.generator.bld.install_files('${LIBDIR}', tgt, postpone=False)
+		lib_list=tgt.read().split()
+		for lib in lib_list:
+			self.generator.bld.symlink_as('${LIBDIR}/'+basename(lib), lib, postpone=False)
+		return 0
+
diff --git a/xpdeint/waf/waflib/extras/subprocess.py b/xpdeint/waf/waflib/extras/subprocess.py
new file mode 100644
index 0000000..cb15178
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/subprocess.py
@@ -0,0 +1,620 @@
+# borrowed from python 2.5.2c1
+# Copyright (c) 2003-2005 by Peter Astrand <astrand at lysator.liu.se>
+# Licensed to PSF under a Contributor Agreement.
+
+import sys
+mswindows = (sys.platform == "win32")
+
+import os
+import types
+import traceback
+import gc
+
+class CalledProcessError(Exception):
+    def __init__(self, returncode, cmd):
+        self.returncode = returncode
+        self.cmd = cmd
+    def __str__(self):
+        return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
+
+if mswindows:
+    import threading
+    import msvcrt
+    if 0:
+        import pywintypes
+        from win32api import GetStdHandle, STD_INPUT_HANDLE, \
+                             STD_OUTPUT_HANDLE, STD_ERROR_HANDLE
+        from win32api import GetCurrentProcess, DuplicateHandle, \
+                             GetModuleFileName, GetVersion
+        from win32con import DUPLICATE_SAME_ACCESS, SW_HIDE
+        from win32pipe import CreatePipe
+        from win32process import CreateProcess, STARTUPINFO, \
+                                 GetExitCodeProcess, STARTF_USESTDHANDLES, \
+                                 STARTF_USESHOWWINDOW, CREATE_NEW_CONSOLE
+        from win32event import WaitForSingleObject, INFINITE, WAIT_OBJECT_0
+    else:
+        from _subprocess import *
+        class STARTUPINFO:
+            dwFlags = 0
+            hStdInput = None
+            hStdOutput = None
+            hStdError = None
+            wShowWindow = 0
+        class pywintypes:
+            error = IOError
+else:
+    import select
+    import errno
+    import fcntl
+    import pickle
+
+__all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", "CalledProcessError"]
+
+try:
+    MAXFD = os.sysconf("SC_OPEN_MAX")
+except:
+    MAXFD = 256
+
+try:
+    False
+except NameError:
+    False = 0
+    True = 1
+
+_active = []
+
+def _cleanup():
+    for inst in _active[:]:
+        if inst.poll(_deadstate=sys.maxint) >= 0:
+            try:
+                _active.remove(inst)
+            except ValueError:
+                pass
+
+PIPE = -1
+STDOUT = -2
+
+
+def call(*popenargs, **kwargs):
+    return Popen(*popenargs, **kwargs).wait()
+
+def check_call(*popenargs, **kwargs):
+    retcode = call(*popenargs, **kwargs)
+    cmd = kwargs.get("args")
+    if cmd is None:
+        cmd = popenargs[0]
+    if retcode:
+        raise CalledProcessError(retcode, cmd)
+    return retcode
+
+
+def list2cmdline(seq):
+    result = []
+    needquote = False
+    for arg in seq:
+        bs_buf = []
+
+        if result:
+            result.append(' ')
+
+        needquote = (" " in arg) or ("\t" in arg) or arg == ""
+        if needquote:
+            result.append('"')
+
+        for c in arg:
+            if c == '\\':
+                bs_buf.append(c)
+            elif c == '"':
+                result.append('\\' * len(bs_buf)*2)
+                bs_buf = []
+                result.append('\\"')
+            else:
+                if bs_buf:
+                    result.extend(bs_buf)
+                    bs_buf = []
+                result.append(c)
+
+        if bs_buf:
+            result.extend(bs_buf)
+
+        if needquote:
+            result.extend(bs_buf)
+            result.append('"')
+
+    return ''.join(result)
+
+class Popen(object):
+    def __init__(self, args, bufsize=0, executable=None,
+                 stdin=None, stdout=None, stderr=None,
+                 preexec_fn=None, close_fds=False, shell=False,
+                 cwd=None, env=None, universal_newlines=False,
+                 startupinfo=None, creationflags=0):
+        _cleanup()
+
+        self._child_created = False
+        if not isinstance(bufsize, (int, long)):
+            raise TypeError("bufsize must be an integer")
+
+        if mswindows:
+            if preexec_fn is not None:
+                raise ValueError("preexec_fn is not supported on Windows platforms")
+            if close_fds:
+                raise ValueError("close_fds is not supported on Windows platforms")
+        else:
+            if startupinfo is not None:
+                raise ValueError("startupinfo is only supported on Windows platforms")
+            if creationflags != 0:
+                raise ValueError("creationflags is only supported on Windows platforms")
+
+        self.stdin = None
+        self.stdout = None
+        self.stderr = None
+        self.pid = None
+        self.returncode = None
+        self.universal_newlines = universal_newlines
+
+        (p2cread, p2cwrite,
+         c2pread, c2pwrite,
+         errread, errwrite) = self._get_handles(stdin, stdout, stderr)
+
+        self._execute_child(args, executable, preexec_fn, close_fds,
+                            cwd, env, universal_newlines,
+                            startupinfo, creationflags, shell,
+                            p2cread, p2cwrite,
+                            c2pread, c2pwrite,
+                            errread, errwrite)
+
+        if mswindows:
+            if stdin is None and p2cwrite is not None:
+                os.close(p2cwrite)
+                p2cwrite = None
+            if stdout is None and c2pread is not None:
+                os.close(c2pread)
+                c2pread = None
+            if stderr is None and errread is not None:
+                os.close(errread)
+                errread = None
+
+        if p2cwrite:
+            self.stdin = os.fdopen(p2cwrite, 'wb', bufsize)
+        if c2pread:
+            if universal_newlines:
+                self.stdout = os.fdopen(c2pread, 'rU', bufsize)
+            else:
+                self.stdout = os.fdopen(c2pread, 'rb', bufsize)
+        if errread:
+            if universal_newlines:
+                self.stderr = os.fdopen(errread, 'rU', bufsize)
+            else:
+                self.stderr = os.fdopen(errread, 'rb', bufsize)
+
+
+    def _translate_newlines(self, data):
+        data = data.replace("\r\n", "\n")
+        data = data.replace("\r", "\n")
+        return data
+
+
+    def __del__(self, sys=sys):
+        if not self._child_created:
+            return
+        self.poll(_deadstate=sys.maxint)
+        if self.returncode is None and _active is not None:
+            _active.append(self)
+
+
+    def communicate(self, input=None):
+        if [self.stdin, self.stdout, self.stderr].count(None) >= 2:
+            stdout = None
+            stderr = None
+            if self.stdin:
+                if input:
+                    self.stdin.write(input)
+                self.stdin.close()
+            elif self.stdout:
+                stdout = self.stdout.read()
+            elif self.stderr:
+                stderr = self.stderr.read()
+            self.wait()
+            return (stdout, stderr)
+
+        return self._communicate(input)
+
+
+    if mswindows:
+        def _get_handles(self, stdin, stdout, stderr):
+            if stdin is None and stdout is None and stderr is None:
+                return (None, None, None, None, None, None)
+
+            p2cread, p2cwrite = None, None
+            c2pread, c2pwrite = None, None
+            errread, errwrite = None, None
+
+            if stdin is None:
+                p2cread = GetStdHandle(STD_INPUT_HANDLE)
+            if p2cread is not None:
+                pass
+            elif stdin is None or stdin == PIPE:
+                p2cread, p2cwrite = CreatePipe(None, 0)
+                p2cwrite = p2cwrite.Detach()
+                p2cwrite = msvcrt.open_osfhandle(p2cwrite, 0)
+            elif isinstance(stdin, int):
+                p2cread = msvcrt.get_osfhandle(stdin)
+            else:
+                p2cread = msvcrt.get_osfhandle(stdin.fileno())
+            p2cread = self._make_inheritable(p2cread)
+
+            if stdout is None:
+                c2pwrite = GetStdHandle(STD_OUTPUT_HANDLE)
+            if c2pwrite is not None:
+                pass
+            elif stdout is None or stdout == PIPE:
+                c2pread, c2pwrite = CreatePipe(None, 0)
+                c2pread = c2pread.Detach()
+                c2pread = msvcrt.open_osfhandle(c2pread, 0)
+            elif isinstance(stdout, int):
+                c2pwrite = msvcrt.get_osfhandle(stdout)
+            else:
+                c2pwrite = msvcrt.get_osfhandle(stdout.fileno())
+            c2pwrite = self._make_inheritable(c2pwrite)
+
+            if stderr is None:
+                errwrite = GetStdHandle(STD_ERROR_HANDLE)
+            if errwrite is not None:
+                pass
+            elif stderr is None or stderr == PIPE:
+                errread, errwrite = CreatePipe(None, 0)
+                errread = errread.Detach()
+                errread = msvcrt.open_osfhandle(errread, 0)
+            elif stderr == STDOUT:
+                errwrite = c2pwrite
+            elif isinstance(stderr, int):
+                errwrite = msvcrt.get_osfhandle(stderr)
+            else:
+                errwrite = msvcrt.get_osfhandle(stderr.fileno())
+            errwrite = self._make_inheritable(errwrite)
+
+            return (p2cread, p2cwrite,
+                    c2pread, c2pwrite,
+                    errread, errwrite)
+        def _make_inheritable(self, handle):
+            return DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), 0, 1, DUPLICATE_SAME_ACCESS)
+
+        def _find_w9xpopen(self):
+            w9xpopen = os.path.join(os.path.dirname(GetModuleFileName(0)), "w9xpopen.exe")
+            if not os.path.exists(w9xpopen):
+                w9xpopen = os.path.join(os.path.dirname(sys.exec_prefix), "w9xpopen.exe")
+                if not os.path.exists(w9xpopen):
+                    raise RuntimeError("Cannot locate w9xpopen.exe, which is needed for Popen to work with your shell or platform.")
+            return w9xpopen
+
+        def _execute_child(self, args, executable, preexec_fn, close_fds,
+                           cwd, env, universal_newlines,
+                           startupinfo, creationflags, shell,
+                           p2cread, p2cwrite,
+                           c2pread, c2pwrite,
+                           errread, errwrite):
+
+            if not isinstance(args, types.StringTypes):
+                args = list2cmdline(args)
+
+            if startupinfo is None:
+                startupinfo = STARTUPINFO()
+            if None not in (p2cread, c2pwrite, errwrite):
+                startupinfo.dwFlags |= STARTF_USESTDHANDLES
+                startupinfo.hStdInput = p2cread
+                startupinfo.hStdOutput = c2pwrite
+                startupinfo.hStdError = errwrite
+
+            if shell:
+                startupinfo.dwFlags |= STARTF_USESHOWWINDOW
+                startupinfo.wShowWindow = SW_HIDE
+                comspec = os.environ.get("COMSPEC", "cmd.exe")
+                args = comspec + " /c " + args
+                if (GetVersion() >= 0x80000000L or
+                        os.path.basename(comspec).lower() == "command.com"):
+                    w9xpopen = self._find_w9xpopen()
+                    args = '"%s" %s' % (w9xpopen, args)
+                    creationflags |= CREATE_NEW_CONSOLE
+
+            try:
+                hp, ht, pid, tid = CreateProcess(executable, args, None, None, 1, creationflags, env, cwd, startupinfo)
+            except pywintypes.error, e:
+                raise WindowsError(*e.args)
+
+            self._child_created = True
+            self._handle = hp
+            self.pid = pid
+            ht.Close()
+
+            if p2cread is not None:
+                p2cread.Close()
+            if c2pwrite is not None:
+                c2pwrite.Close()
+            if errwrite is not None:
+                errwrite.Close()
+
+
+        def poll(self, _deadstate=None):
+            if self.returncode is None:
+                if WaitForSingleObject(self._handle, 0) == WAIT_OBJECT_0:
+                    self.returncode = GetExitCodeProcess(self._handle)
+            return self.returncode
+
+
+        def wait(self):
+            if self.returncode is None:
+                obj = WaitForSingleObject(self._handle, INFINITE)
+                self.returncode = GetExitCodeProcess(self._handle)
+            return self.returncode
+
+        def _readerthread(self, fh, buffer):
+            buffer.append(fh.read())
+
+        def _communicate(self, input):
+            stdout = None
+            stderr = None
+
+            if self.stdout:
+                stdout = []
+                stdout_thread = threading.Thread(target=self._readerthread, args=(self.stdout, stdout))
+                stdout_thread.setDaemon(True)
+                stdout_thread.start()
+            if self.stderr:
+                stderr = []
+                stderr_thread = threading.Thread(target=self._readerthread, args=(self.stderr, stderr))
+                stderr_thread.setDaemon(True)
+                stderr_thread.start()
+
+            if self.stdin:
+                if input is not None:
+                    self.stdin.write(input)
+                self.stdin.close()
+
+            if self.stdout:
+                stdout_thread.join()
+            if self.stderr:
+                stderr_thread.join()
+
+            if stdout is not None:
+                stdout = stdout[0]
+            if stderr is not None:
+                stderr = stderr[0]
+
+            if self.universal_newlines and hasattr(file, 'newlines'):
+                if stdout:
+                    stdout = self._translate_newlines(stdout)
+                if stderr:
+                    stderr = self._translate_newlines(stderr)
+
+            self.wait()
+            return (stdout, stderr)
+
+    else:
+        def _get_handles(self, stdin, stdout, stderr):
+            p2cread, p2cwrite = None, None
+            c2pread, c2pwrite = None, None
+            errread, errwrite = None, None
+
+            if stdin is None:
+                pass
+            elif stdin == PIPE:
+                p2cread, p2cwrite = os.pipe()
+            elif isinstance(stdin, int):
+                p2cread = stdin
+            else:
+                p2cread = stdin.fileno()
+
+            if stdout is None:
+                pass
+            elif stdout == PIPE:
+                c2pread, c2pwrite = os.pipe()
+            elif isinstance(stdout, int):
+                c2pwrite = stdout
+            else:
+                c2pwrite = stdout.fileno()
+
+            if stderr is None:
+                pass
+            elif stderr == PIPE:
+                errread, errwrite = os.pipe()
+            elif stderr == STDOUT:
+                errwrite = c2pwrite
+            elif isinstance(stderr, int):
+                errwrite = stderr
+            else:
+                errwrite = stderr.fileno()
+
+            return (p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite)
+
+        def _set_cloexec_flag(self, fd):
+            try:
+                cloexec_flag = fcntl.FD_CLOEXEC
+            except AttributeError:
+                cloexec_flag = 1
+
+            old = fcntl.fcntl(fd, fcntl.F_GETFD)
+            fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag)
+
+        def _close_fds(self, but):
+            for i in xrange(3, MAXFD):
+                if i == but:
+                    continue
+                try:
+                    os.close(i)
+                except:
+                    pass
+
+        def _execute_child(self, args, executable, preexec_fn, close_fds,
+                           cwd, env, universal_newlines, startupinfo, creationflags, shell,
+                           p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite):
+
+            if isinstance(args, types.StringTypes):
+                args = [args]
+            else:
+                args = list(args)
+
+            if shell:
+                args = ["/bin/sh", "-c"] + args
+
+            if executable is None:
+                executable = args[0]
+
+            errpipe_read, errpipe_write = os.pipe()
+            self._set_cloexec_flag(errpipe_write)
+
+            gc_was_enabled = gc.isenabled()
+            gc.disable()
+            try:
+                self.pid = os.fork()
+            except:
+                if gc_was_enabled:
+                    gc.enable()
+                raise
+            self._child_created = True
+            if self.pid == 0:
+                try:
+                    if p2cwrite:
+                        os.close(p2cwrite)
+                    if c2pread:
+                        os.close(c2pread)
+                    if errread:
+                        os.close(errread)
+                    os.close(errpipe_read)
+
+                    if p2cread:
+                        os.dup2(p2cread, 0)
+                    if c2pwrite:
+                        os.dup2(c2pwrite, 1)
+                    if errwrite:
+                        os.dup2(errwrite, 2)
+
+                    if p2cread and p2cread not in (0,):
+                        os.close(p2cread)
+                    if c2pwrite and c2pwrite not in (p2cread, 1):
+                        os.close(c2pwrite)
+                    if errwrite and errwrite not in (p2cread, c2pwrite, 2):
+                        os.close(errwrite)
+
+                    if close_fds:
+                        self._close_fds(but=errpipe_write)
+
+                    if cwd is not None:
+                        os.chdir(cwd)
+
+                    if preexec_fn:
+                        apply(preexec_fn)
+
+                    if env is None:
+                        os.execvp(executable, args)
+                    else:
+                        os.execvpe(executable, args, env)
+
+                except:
+                    exc_type, exc_value, tb = sys.exc_info()
+                    exc_lines = traceback.format_exception(exc_type, exc_value, tb)
+                    exc_value.child_traceback = ''.join(exc_lines)
+                    os.write(errpipe_write, pickle.dumps(exc_value))
+
+                os._exit(255)
+
+            if gc_was_enabled:
+                gc.enable()
+            os.close(errpipe_write)
+            if p2cread and p2cwrite:
+                os.close(p2cread)
+            if c2pwrite and c2pread:
+                os.close(c2pwrite)
+            if errwrite and errread:
+                os.close(errwrite)
+
+            data = os.read(errpipe_read, 1048576)
+            os.close(errpipe_read)
+            if data != "":
+                os.waitpid(self.pid, 0)
+                child_exception = pickle.loads(data)
+                raise child_exception
+
+        def _handle_exitstatus(self, sts):
+            if os.WIFSIGNALED(sts):
+                self.returncode = -os.WTERMSIG(sts)
+            elif os.WIFEXITED(sts):
+                self.returncode = os.WEXITSTATUS(sts)
+            else:
+                raise RuntimeError("Unknown child exit status!")
+
+        def poll(self, _deadstate=None):
+            if self.returncode is None:
+                try:
+                    pid, sts = os.waitpid(self.pid, os.WNOHANG)
+                    if pid == self.pid:
+                        self._handle_exitstatus(sts)
+                except os.error:
+                    if _deadstate is not None:
+                        self.returncode = _deadstate
+            return self.returncode
+
+        def wait(self):
+            if self.returncode is None:
+                pid, sts = os.waitpid(self.pid, 0)
+                self._handle_exitstatus(sts)
+            return self.returncode
+
+        def _communicate(self, input):
+            read_set = []
+            write_set = []
+            stdout = None
+            stderr = None
+
+            if self.stdin:
+                self.stdin.flush()
+                if input:
+                    write_set.append(self.stdin)
+                else:
+                    self.stdin.close()
+            if self.stdout:
+                read_set.append(self.stdout)
+                stdout = []
+            if self.stderr:
+                read_set.append(self.stderr)
+                stderr = []
+
+            input_offset = 0
+            while read_set or write_set:
+                rlist, wlist, xlist = select.select(read_set, write_set, [])
+
+                if self.stdin in wlist:
+                    bytes_written = os.write(self.stdin.fileno(), buffer(input, input_offset, 512))
+                    input_offset += bytes_written
+                    if input_offset >= len(input):
+                        self.stdin.close()
+                        write_set.remove(self.stdin)
+
+                if self.stdout in rlist:
+                    data = os.read(self.stdout.fileno(), 1024)
+                    if data == "":
+                        self.stdout.close()
+                        read_set.remove(self.stdout)
+                    stdout.append(data)
+
+                if self.stderr in rlist:
+                    data = os.read(self.stderr.fileno(), 1024)
+                    if data == "":
+                        self.stderr.close()
+                        read_set.remove(self.stderr)
+                    stderr.append(data)
+
+            if stdout is not None:
+                stdout = ''.join(stdout)
+            if stderr is not None:
+                stderr = ''.join(stderr)
+
+            if self.universal_newlines and hasattr(file, 'newlines'):
+                if stdout:
+                    stdout = self._translate_newlines(stdout)
+                if stderr:
+                    stderr = self._translate_newlines(stderr)
+
+            self.wait()
+            return (stdout, stderr)
+
diff --git a/xpdeint/waf/waflib/extras/swig.py b/xpdeint/waf/waflib/extras/swig.py
new file mode 100644
index 0000000..47ffdea
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/swig.py
@@ -0,0 +1,172 @@
+#! /usr/bin/env python
+# encoding: UTF-8
+# Petar Forai
+# Thomas Nagy 2008-2010 (ita)
+
+import re
+from waflib import Task, Utils, Logs
+from waflib.TaskGen import extension, feature, after_method
+from waflib.Configure import conf
+from waflib.Tools import c_preproc
+
+"""
+tasks have to be added dynamically:
+- swig interface files may be created at runtime
+- the module name may be unknown in advance
+"""
+
+SWIG_EXTS = ['.swig', '.i']
+
+re_module = re.compile('%module(?:\s*\(.*\))?\s+(.+)', re.M)
+
+re_1 = re.compile(r'^%module.*?\s+([\w]+)\s*?$', re.M)
+re_2 = re.compile('%include "(.*)"', re.M)
+re_3 = re.compile('#include "(.*)"', re.M)
+
+class swig(Task.Task):
+	color   = 'BLUE'
+	run_str = '${SWIG} ${SWIGFLAGS} ${SWIGPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${SRC}'
+	ext_out = ['.h'] # might produce .h files although it is not mandatory
+
+	def runnable_status(self):
+		for t in self.run_after:
+			if not t.hasrun:
+				return Task.ASK_LATER
+
+		if not getattr(self, 'init_outputs', None):
+			self.init_outputs = True
+			if not getattr(self, 'module', None):
+				# search the module name
+				txt = self.inputs[0].read()
+				m = re_module.search(txt)
+				if not m:
+					raise ValueError("could not find the swig module name")
+				self.module = m.group(1)
+
+			swig_c(self)
+
+			# add the language-specific output files as nodes
+			# call funs in the dict swig_langs
+			for x in self.env['SWIGFLAGS']:
+				# obtain the language
+				x = x[1:]
+				try:
+					fun = swig_langs[x]
+				except KeyError:
+					pass
+				else:
+					fun(self)
+
+		return super(swig, self).runnable_status()
+
+	def scan(self):
+		"scan for swig dependencies, climb the .i files"
+		env = self.env
+
+		lst_src = []
+
+		seen = []
+		to_see = [self.inputs[0]]
+
+		while to_see:
+			node = to_see.pop(0)
+			if node in seen:
+				continue
+			seen.append(node)
+			lst_src.append(node)
+
+			# read the file
+			code = node.read()
+			code = c_preproc.re_nl.sub('', code)
+			code = c_preproc.re_cpp.sub(c_preproc.repl, code)
+
+			# find .i files and project headers
+			names = re_2.findall(code) + re_3.findall(code)
+			for n in names:
+				for d in self.generator.includes_nodes + [node.parent]:
+					u = d.find_resource(n)
+					if u:
+						to_see.append(u)
+						break
+				else:
+					Logs.warn('could not find %r' % n)
+
+		return (lst_src, [])
+
+# provide additional language processing
+swig_langs = {}
+def swigf(fun):
+	swig_langs[fun.__name__.replace('swig_', '')] = fun
+swig.swigf = swigf
+
+def swig_c(self):
+	ext = '.swigwrap_%d.c' % self.generator.idx
+	flags = self.env['SWIGFLAGS']
+	if '-c++' in flags:
+		ext += 'xx'
+	out_node = self.inputs[0].parent.find_or_declare(self.module + ext)
+
+	if '-c++' in flags:
+		c_tsk = self.generator.cxx_hook(out_node)
+	else:
+		c_tsk = self.generator.c_hook(out_node)
+
+	c_tsk.set_run_after(self)
+
+	ge = self.generator.bld.producer
+	ge.outstanding.insert(0, c_tsk)
+	ge.total += 1
+
+	try:
+		ltask = self.generator.link_task
+	except AttributeError:
+		pass
+	else:
+		ltask.set_run_after(c_tsk)
+		ltask.inputs.append(c_tsk.outputs[0])
+
+	self.outputs.append(out_node)
+
+	if not '-o' in self.env['SWIGFLAGS']:
+		self.env.append_value('SWIGFLAGS', ['-o', self.outputs[0].abspath()])
+
+ at swigf
+def swig_python(tsk):
+	tsk.set_outputs(tsk.inputs[0].parent.find_or_declare(tsk.module + '.py'))
+
+ at swigf
+def swig_ocaml(tsk):
+	tsk.set_outputs(tsk.inputs[0].parent.find_or_declare(tsk.module + '.ml'))
+	tsk.set_outputs(tsk.inputs[0].parent.find_or_declare(tsk.module + '.mli'))
+
+ at extension(*SWIG_EXTS)
+def i_file(self, node):
+	# the task instance
+	tsk = self.create_task('swig')
+	tsk.set_inputs(node)
+	tsk.module = getattr(self, 'swig_module', None)
+
+	flags = self.to_list(getattr(self, 'swig_flags', []))
+	tsk.env.append_value('SWIGFLAGS', flags)
+
+	# looks like this is causing problems
+	#if not '-outdir' in flags:
+	#	tsk.env.append_value('SWIGFLAGS', ['-outdir', node.parent.abspath()])
+
+ at conf
+def check_swig_version(self):
+	"""Check for a minimum swig version like conf.check_swig_version('1.3.28')
+	or conf.check_swig_version((1,3,28)) """
+	reg_swig = re.compile(r'SWIG Version\s(.*)', re.M)
+	swig_out = self.cmd_and_log('%s -version' % self.env['SWIG'])
+
+	swigver = tuple([int(s) for s in reg_swig.findall(swig_out)[0].split('.')])
+	self.env['SWIG_VERSION'] = swigver
+	msg = 'Checking for swig version'
+	self.msg(msg, '.'.join(map(str, swigver)))
+	return swigver
+
+def configure(conf):
+	swig = conf.find_program('swig', var='SWIG')
+	conf.env.SWIGPATH_ST = '-I%s'
+
diff --git a/xpdeint/waf/waflib/extras/syms.py b/xpdeint/waf/waflib/extras/syms.py
new file mode 100644
index 0000000..39ee7d8
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/syms.py
@@ -0,0 +1,71 @@
+#! /usr/bin/env python
+# encoding: utf-8
+
+"""
+this tool supports the export_symbols_regex to export the symbols in a shared library.
+by default, all symbols are exported by gcc, and nothing by msvc.
+to use the tool, do something like:
+
+def build(ctx):
+	ctx(features='c cshlib syms', source='a.c b.c', export_symbols_regex='mylib_.*', target='testlib')
+
+only the symbols starting with 'mylib_' will be exported.
+"""
+
+import re
+from waflib.Context import STDOUT
+from waflib.Task import Task
+from waflib.Errors import WafError
+from waflib.TaskGen import feature, after_method
+
+class gen_sym(Task):
+	def run(self):
+		obj = self.inputs[0]
+		if 'msvc' in (self.env.CC_NAME, self.env.CXX_NAME):
+			re_nm = re.compile(r'External\s+\|\s+_(' + self.generator.export_symbols_regex + r')\b')
+			cmd = ['dumpbin', '/symbols', obj.abspath()]
+		else:
+			if self.env.DEST_BINFMT == 'pe': #gcc uses nm, and has a preceding _ on windows
+				re_nm = re.compile(r'T\s+_(' + self.generator.export_symbols_regex + r')\b')
+			else:
+				re_nm = re.compile(r'T\s+(' + self.generator.export_symbols_regex + r')\b')
+			cmd = ['nm', '-g', obj.abspath()]
+		syms = re_nm.findall(self.generator.bld.cmd_and_log(cmd, quiet=STDOUT))
+		self.outputs[0].write('%r' % syms)
+
+class compile_sym(Task):
+	def run(self):
+		syms = {}
+		for x in self.inputs:
+			slist = eval(x.read())
+			for s in slist:
+				syms[s] = 1
+		lsyms = syms.keys()
+		lsyms.sort()
+		if self.env.DEST_BINFMT == 'pe':
+			self.outputs[0].write('EXPORTS\n' + '\n'.join(lsyms))
+		elif self.env.DEST_BINFMT == 'elf':
+			self.outputs[0].write('{ global:\n' + ';\n'.join(lsyms) + ";\nlocal: *; };\n")
+		else:
+			raise WafError('NotImplemented')
+
+ at feature('syms')
+ at after_method('process_source', 'process_use', 'apply_link', 'process_uselib_local')
+def do_the_symbol_stuff(self):
+	ins = [x.outputs[0] for x in self.compiled_tasks]
+	self.gen_sym_tasks = [self.create_task('gen_sym', x, x.change_ext('.%d.sym' % self.idx)) for x in ins]
+
+	tsk = self.create_task('compile_sym',
+			       [x.outputs[0] for x in self.gen_sym_tasks],
+			       self.path.find_or_declare(getattr(self, 'sym_filename', self.target + '.def')))
+	self.link_task.set_run_after(tsk)
+	self.link_task.dep_nodes = [tsk.outputs[0]]
+	if 'msvc' in (self.env.CC_NAME, self.env.CXX_NAME):
+		self.link_task.env.append_value('LINKFLAGS', ['/def:' + tsk.outputs[0].bldpath()])
+	elif self.env.DEST_BINFMT == 'pe': #gcc on windows takes *.def as an additional input
+		self.link_task.inputs.append(tsk.outputs[0])
+	elif self.env.DEST_BINFMT == 'elf':
+		self.link_task.env.append_value('LINKFLAGS', ['-Wl,-version-script', '-Wl,' + tsk.outputs[0].bldpath()])
+	else:
+		raise WafError('NotImplemented')
+
diff --git a/xpdeint/waf/waflib/extras/sync_exec.py b/xpdeint/waf/waflib/extras/sync_exec.py
new file mode 100644
index 0000000..baf4cfb
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/sync_exec.py
@@ -0,0 +1,31 @@
+#! /usr/bin/env python
+# encoding: utf-8
+
+"""
+Force the execution output to be synchronized
+May deadlock with a lot of output (subprocess limitation)
+"""
+
+import sys
+from waflib.Build import BuildContext
+from waflib import Utils, Logs
+
+def exec_command(self, cmd, **kw):
+	subprocess = Utils.subprocess
+	kw['shell'] = isinstance(cmd, str)
+	Logs.debug('runner: %r' % cmd)
+	Logs.debug('runner_env: kw=%s' % kw)
+	try:
+		kw['stdout'] = kw['stderr'] = subprocess.PIPE
+		p = subprocess.Popen(cmd, **kw)
+		(out, err) = p.communicate()
+		if out:
+			sys.stdout.write(out.decode(sys.stdout.encoding or 'iso8859-1'))
+		if err:
+			sys.stdout.write(err.decode(sys.stdout.encoding or 'iso8859-1'))
+		return p.returncode
+	except OSError:
+		return -1
+
+BuildContext.exec_command = exec_command
+
diff --git a/xpdeint/waf/waflib/extras/valadoc.py b/xpdeint/waf/waflib/extras/valadoc.py
new file mode 100644
index 0000000..fcc1129
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/valadoc.py
@@ -0,0 +1,107 @@
+#! /usr/bin/env python
+# encoding: UTF-8
+# Nicolas Joseph 2009
+
+"""
+ported from waf 1.5:
+TODO: tabs vs spaces
+"""
+
+from waflib import Task, Utils, Node, Errors
+from waflib.TaskGen import feature, extension, after_method
+from Logs import debug, warn, error
+
+VALADOC_STR = '${VALADOC}'
+
+class valadoc(Task.Task):
+	vars  = ['VALADOC', 'VALADOCFLAGS']
+	color = 'BLUE'
+	after = ['cprogram', 'cstlib', 'cshlib', 'cxxprogram', 'cxxstlib', 'cxxshlib']
+	quiet = True # no outputs .. this is weird
+
+	def __init__(self, *k, **kw):
+		Task.Task.__init__(*k, **kw)
+		self.output_dir = ''
+		self.doclet = ''
+		self.package_name = ''
+		self.package_version = ''
+		self.files = []
+		self.protected = True
+		self.private = False
+		self.inherit = False
+		self.deps = False
+		self.enable_non_null_experimental = False
+		self.force = False
+
+	def run(self):
+		if not self.env['VALADOCFLAGS']:
+			self.env['VALADOCFLAGS'] = ''
+		cmd = [Utils.subst_vars(VALADOC_STR, self.env)]
+		cmd.append ('-o %s' % self.output_dir)
+		if getattr(self, 'doclet', None):
+			cmd.append ('--doclet %s' % self.doclet)
+		cmd.append ('--package-name %s' % self.package_name)
+		if getattr(self, 'version', None):
+			cmd.append ('--package-version %s' % self.package_version)
+		if getattr(self, 'packages', None):
+			for package in self.packages:
+				cmd.append ('--pkg %s' % package)
+		if getattr(self, 'vapi_dirs', None):
+			for vapi_dir in self.vapi_dirs:
+				cmd.append ('--vapidir %s' % vapi_dir)
+		if not getattr(self, 'protected', None):
+			cmd.append ('--no-protected')
+		if getattr(self, 'private', None):
+			cmd.append ('--private')
+		if getattr(self, 'inherit', None):
+			cmd.append ('--inherit')
+		if getattr(self, 'deps', None):
+			cmd.append ('--deps')
+		if getattr(self, 'enable_non_null_experimental', None):
+			cmd.append ('--enable-non-null-experimental')
+		if getattr(self, 'force', None):
+			cmd.append ('--force')
+		cmd.append (' '.join ([x.relpath_gen (self.generator.bld.bldnode) for x in self.files]))
+		return self.generator.bld.exec_command(' '.join(cmd))
+
+ at feature('valadoc')
+def process_valadoc(self):
+	task = self.create_task('valadoc')
+	if getattr(self, 'output_dir', None):
+		task.output_dir = self.output_dir
+	else:
+		Errors.WafError('no output directory')
+	if getattr(self, 'doclet', None):
+		task.doclet = self.doclet
+	else:
+		Errors.WafError('no doclet directory')
+	if getattr(self, 'package_name', None):
+		task.package_name = self.package_name
+	else:
+		Errors.WafError('no package name')
+	if getattr(self, 'package_version', None):
+		task.package_version = self.package_version
+	if getattr(self, 'packages', None):
+		task.packages = Utils.to_list(self.packages)
+	if getattr(self, 'vapi_dirs', None):
+		task.vapi_dirs = Utils.to_list(self.vapi_dirs)
+	if getattr(self, 'files', None):
+		task.files = self.files
+	else:
+		Errors.WafError('no input file')
+	if getattr(self, 'protected', None):
+		task.protected = self.protected
+	if getattr(self, 'private', None):
+		task.private = self.private
+	if getattr(self, 'inherit', None):
+		task.inherit = self.inherit
+	if getattr(self, 'deps', None):
+		task.deps = self.deps
+	if getattr(self, 'enable_non_null_experimental', None):
+		task.enable_non_null_experimental = self.enable_non_null_experimental
+	if getattr(self, 'force', None):
+		task.force = self.force
+
+def configure(conf):
+	conf.find_program('valadoc', errmsg='You must install valadoc <http://live.gnome.org/Valadoc> for generate the API documentation')
+
diff --git a/xpdeint/waf/waflib/extras/why.py b/xpdeint/waf/waflib/extras/why.py
new file mode 100644
index 0000000..4bb774f
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/why.py
@@ -0,0 +1,73 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2010 (ita)
+
+"""
+This tool modifies the task signature scheme to store and obtain
+information about the task execution (why it must run, etc)::
+
+	def configure(conf):
+		conf.load('why')
+
+After adding the tool, a full rebuild is necessary.
+"""
+
+from waflib import Task, Utils, Logs, Errors
+
+def signature(self):
+	# compute the result one time, and suppose the scan_signature will give the good result
+	try: return self.cache_sig
+	except AttributeError: pass
+
+	self.m = Utils.md5()
+	self.m.update(self.hcode.encode())
+	id_sig = self.m.digest()
+
+	# explicit deps
+	self.sig_explicit_deps()
+	exp_sig = self.m.digest()
+
+	# env vars
+	self.sig_vars()
+	var_sig = self.m.digest()
+
+	# implicit deps / scanner results
+	if self.scan:
+		try:
+			self.sig_implicit_deps()
+		except Errors.TaskRescan:
+			return self.signature()
+
+	ret = self.cache_sig = self.m.digest() + id_sig + exp_sig + var_sig
+	return ret
+
+
+Task.Task.signature = signature
+
+old = Task.Task.runnable_status
+def runnable_status(self):
+	ret = old(self)
+	if ret == Task.RUN_ME:
+		try:
+			old_sigs = self.generator.bld.task_sigs[self.uid()]
+		except:
+			Logs.debug("task: task must run as no previous signature exists")
+		else:
+			new_sigs = self.cache_sig
+			def v(x):
+				return Utils.to_hex(x)
+
+			Logs.debug("Task %r" % self)
+			msgs = ['Task must run', '* Task code', '* Source file or manual dependency', '* Configuration data variable']
+			tmp = 'task: -> %s: %s %s'
+			for x in range(len(msgs)):
+				l = len(Utils.SIG_NIL)
+				a = new_sigs[x*l : (x+1)*l]
+				b = old_sigs[x*l : (x+1)*l]
+				if (a != b):
+					Logs.debug(tmp % (msgs[x].ljust(35), v(a), v(b)))
+					if x > 0:
+						break
+	return ret
+Task.Task.runnable_status = runnable_status
+
diff --git a/xpdeint/waf/waflib/extras/xcode.py b/xpdeint/waf/waflib/extras/xcode.py
new file mode 100644
index 0000000..3ae584e
--- /dev/null
+++ b/xpdeint/waf/waflib/extras/xcode.py
@@ -0,0 +1,312 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# XCode 3/XCode 4 generator for Waf
+# Nicolas Mercier 2011
+
+"""
+Usage:
+
+def options(opt):
+	opt.load('xcode')
+
+$ waf configure xcode
+"""
+
+# TODO: support iOS projects
+
+from waflib import Context, TaskGen, Build, Utils
+import os, sys, random, time
+
+HEADERS_GLOB = '**/(*.h|*.hpp|*.H|*.inl)'
+
+MAP_EXT = {
+	'.h' :  "sourcecode.c.h",
+
+	'.hh':  "sourcecode.cpp.h",
+	'.inl': "sourcecode.cpp.h",
+	'.hpp': "sourcecode.cpp.h",
+
+	'.c':   "sourcecode.c.c",
+
+	'.m':   "sourcecode.c.objc",
+
+	'.mm':  "sourcecode.cpp.objcpp",
+
+	'.cc':  "sourcecode.cpp.cpp",
+
+	'.cpp': "sourcecode.cpp.cpp",
+	'.C':   "sourcecode.cpp.cpp",
+	'.cxx': "sourcecode.cpp.cpp",
+	'.c++': "sourcecode.cpp.cpp",
+
+	'.l':   "sourcecode.lex", # luthor
+	'.ll':  "sourcecode.lex",
+
+	'.y':   "sourcecode.yacc",
+	'.yy':  "sourcecode.yacc",
+
+	'.plist': "text.plist.xml",
+	".nib":   "wrapper.nib",
+	".xib":   "text.xib",
+}
+
+
+part1 = 0
+part2 = 10000
+part3 = 0
+id = 562000999
+def newid():
+	global id
+	id = id + 1
+	return "%04X%04X%04X%012d" % (0, 10000, 0, id)
+
+class XCodeNode:
+	def __init__(self):
+		self._id = newid()
+
+	def tostring(self, value):
+		if isinstance(value, dict):
+			result = "{\n"
+			for k,v in value.items():
+				result = result + "\t\t\t%s = %s;\n" % (k, self.tostring(v))
+			result = result + "\t\t}"
+			return result
+		elif isinstance(value, str):
+			return "\"%s\"" % value
+		elif isinstance(value, list):
+			result = "(\n"
+			for i in value:
+				result = result + "\t\t\t%s,\n" % self.tostring(i)
+			result = result + "\t\t)"
+			return result
+		elif isinstance(value, XCodeNode):
+			return value._id
+		else:
+			return str(value)
+
+	def write_recursive(self, value, file):
+		if isinstance(value, dict):
+			for k,v in value.items():
+				self.write_recursive(v, file)
+		elif isinstance(value, list):
+			for i in value:
+				self.write_recursive(i, file)
+		elif isinstance(value, XCodeNode):
+			value.write(file)
+
+	def write(self, file):
+		for attribute,value in self.__dict__.items():
+			if attribute[0] != '_':
+				self.write_recursive(value, file)
+
+		w = file.write
+		w("\t%s = {\n" % self._id)
+		w("\t\tisa = %s;\n" % self.__class__.__name__)
+		for attribute,value in self.__dict__.items():
+			if attribute[0] != '_':
+				w("\t\t%s = %s;\n" % (attribute, self.tostring(value)))
+		w("\t};\n\n")
+
+
+
+# Configurations
+class XCBuildConfiguration(XCodeNode):
+	def __init__(self, name, settings = {}, env=None):
+		XCodeNode.__init__(self)
+		self.baseConfigurationReference = ""
+		self.buildSettings = settings
+		self.name = name
+		if env and env.ARCH:
+			settings['ARCHS'] = " ".join(env.ARCH)
+
+
+class XCConfigurationList(XCodeNode):
+	def __init__(self, settings):
+		XCodeNode.__init__(self)
+		self.buildConfigurations = settings
+		self.defaultConfigurationIsVisible = 0
+		self.defaultConfigurationName = settings and settings[0].name or ""
+
+# Group/Files
+class PBXFileReference(XCodeNode):
+	def __init__(self, name, path, filetype = '', sourcetree = "SOURCE_ROOT"):
+		XCodeNode.__init__(self)
+		self.fileEncoding = 4
+		if not filetype:
+			_, ext = os.path.splitext(name)
+			filetype = MAP_EXT.get(ext, 'text')
+		self.lastKnownFileType = filetype
+		self.name = name
+		self.path = path
+		self.sourceTree = sourcetree
+
+class PBXGroup(XCodeNode):
+	def __init__(self, name, sourcetree = "<group>"):
+		XCodeNode.__init__(self)
+		self.children = []
+		self.name = name
+		self.sourceTree = sourcetree
+
+	def add(self, root, sources):
+		folders = {}
+		def folder(n):
+			if n == root:
+				return self
+			try:
+				return folders[n]
+			except KeyError:
+				f = PBXGroup(n.name)
+				p = folder(n.parent)
+				folders[n] = f
+				p.children.append(f)
+				return f
+		for s in sources:
+			f = folder(s.parent)
+			source = PBXFileReference(s.name, s.abspath())
+			f.children.append(source)
+
+
+# Targets
+class PBXLegacyTarget(XCodeNode):
+	def __init__(self, action, target=''):
+		XCodeNode.__init__(self)
+		self.buildConfigurationList = XCConfigurationList([XCBuildConfiguration('waf', {})])
+		if not target:
+			self.buildArgumentsString = "%s %s" % (sys.argv[0], action)
+		else:
+			self.buildArgumentsString = "%s %s --targets=%s" % (sys.argv[0], action, target)
+		self.buildPhases = []
+		self.buildToolPath = sys.executable
+		self.buildWorkingDirectory = ""
+		self.dependencies = []
+		self.name = target or action
+		self.productName = target or action
+		self.passBuildSettingsInEnvironment = 0
+
+class PBXShellScriptBuildPhase(XCodeNode):
+	def __init__(self, action, target):
+		XCodeNode.__init__(self)
+		self.buildActionMask = 2147483647
+		self.files = []
+		self.inputPaths = []
+		self.outputPaths = []
+		self.runOnlyForDeploymentPostProcessing = 0
+		self.shellPath = "/bin/sh"
+		self.shellScript = "%s %s %s --targets=%s" % (sys.executable, sys.argv[0], action, target)
+
+class PBXNativeTarget(XCodeNode):
+	def __init__(self, action, target, node, env):
+		XCodeNode.__init__(self)
+		conf = XCBuildConfiguration('waf', {'PRODUCT_NAME':target, 'CONFIGURATION_BUILD_DIR':node.parent.abspath()}, env)
+		self.buildConfigurationList = XCConfigurationList([conf])
+		self.buildPhases = [PBXShellScriptBuildPhase(action, target)]
+		self.buildRules = []
+		self.dependencies = []
+		self.name = target
+		self.productName = target
+		self.productType = "com.apple.product-type.application"
+		self.productReference = PBXFileReference(target, node.abspath(), 'wrapper.application', 'BUILT_PRODUCTS_DIR')
+
+# Root project object
+class PBXProject(XCodeNode):
+	def __init__(self, name, version):
+		XCodeNode.__init__(self)
+		self.buildConfigurationList = XCConfigurationList([XCBuildConfiguration('waf', {})])
+		self.compatibilityVersion = version[0]
+		self.hasScannedForEncodings = 1;
+		self.mainGroup = PBXGroup(name)
+		self.projectRoot = ""
+		self.projectDirPath = ""
+		self.targets = []
+		self._objectVersion = version[1]
+		self._output = PBXGroup('out')
+		self.mainGroup.children.append(self._output)
+
+	def write(self, file):
+		w = file.write
+		w("// !$*UTF8*$!\n")
+		w("{\n")
+		w("\tarchiveVersion = 1;\n")
+		w("\tclasses = {\n")
+		w("\t};\n")
+		w("\tobjectVersion = %d;\n" % self._objectVersion)
+		w("\tobjects = {\n\n")
+
+		XCodeNode.write(self, file)
+
+		w("\t};\n")
+		w("\trootObject = %s;\n" % self._id)
+		w("}\n")
+
+	def add_task_gen(self, tg):
+		if not getattr(tg, 'mac_app', False):
+			self.targets.append(PBXLegacyTarget('build', tg.name))
+		else:
+			target = PBXNativeTarget('build', tg.name, tg.link_task.outputs[0].change_ext('.app'), tg.env)
+			self.targets.append(target)
+			self._output.children.append(target.productReference)
+
+class xcode(Build.BuildContext):
+	cmd = 'xcode'
+	fun = 'build'
+
+	def collect_source(self, tg):
+		source_files = tg.to_nodes(getattr(tg, 'source', []))
+		plist_files = tg.to_nodes(getattr(tg, 'mac_plist', []))
+		resource_files = [tg.path.find_node(i) for i in Utils.to_list(getattr(tg, 'mac_resources', []))]
+		include_dirs = Utils.to_list(getattr(tg, 'includes', [])) + Utils.to_list(getattr(tg, 'export_dirs', []))
+		include_files = []
+		for x in include_dirs:
+			if not isinstance(x, str):
+				include_files.append(x)
+				continue
+			d = tg.path.find_node(x)
+			if d:
+				lst = [y for y in d.ant_glob(HEADERS_GLOB, flat=False)]
+				include_files.extend(lst)
+
+		# remove duplicates
+		source = list(set(source_files + plist_files + resource_files + include_files))
+		source.sort(key=lambda x: x.abspath())
+		return source
+
+	def execute(self):
+		"""
+		Entry point
+		"""
+		self.restore()
+		if not self.all_envs:
+			self.load_envs()
+		self.recurse([self.run_dir])
+
+		appname = getattr(Context.g_module, Context.APPNAME, os.path.basename(self.srcnode.abspath()))
+		p = PBXProject(appname, ('Xcode 3.2', 46))
+
+		for g in self.groups:
+			for tg in g:
+				if not isinstance(tg, TaskGen.task_gen):
+					continue
+
+				tg.post()
+
+				features = Utils.to_list(getattr(tg, 'features', ''))
+
+				group = PBXGroup(tg.name)
+				group.add(tg.path, self.collect_source(tg))
+				p.mainGroup.children.append(group)
+
+				if 'cprogram' or 'cxxprogram' in features:
+					p.add_task_gen(tg)
+
+
+		# targets that don't produce the executable but that you might want to run
+		p.targets.append(PBXLegacyTarget('configure'))
+		p.targets.append(PBXLegacyTarget('dist'))
+		p.targets.append(PBXLegacyTarget('install'))
+		p.targets.append(PBXLegacyTarget('check'))
+		node = self.srcnode.make_node('%s.xcodeproj' % appname)
+		node.mkdir()
+		node = node.make_node('project.pbxproj')
+		p.write(open(node.abspath(), 'w'))
+
+
diff --git a/xpdeint/waf/waflib/fixpy2.py b/xpdeint/waf/waflib/fixpy2.py
new file mode 100644
index 0000000..2896962
--- /dev/null
+++ b/xpdeint/waf/waflib/fixpy2.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2010 (ita)
+
+"""
+burn a book, save a tree
+"""
+
+import os
+all_modifs = {}
+
+def fixdir(dir):
+	"""call all the substitution functions on the waf folders"""
+	global all_modifs
+	for k in all_modifs:
+		for v in all_modifs[k]:
+			modif(os.path.join(dir, 'waflib'), k, v)
+
+def modif(dir, name, fun):
+	"""execute a substitution function"""
+	if name == '*':
+		lst = []
+		for y in '. Tools extras'.split():
+			for x in os.listdir(os.path.join(dir, y)):
+				if x.endswith('.py'):
+					lst.append(y + os.sep + x)
+		for x in lst:
+			modif(dir, x, fun)
+		return
+
+	filename = os.path.join(dir, name)
+	f = open(filename, 'r')
+	txt = f.read()
+	f.close()
+
+	txt = fun(txt)
+
+	f = open(filename, 'w')
+	f.write(txt)
+	f.close()
+
+def subst(*k):
+	"""register a substitution function"""
+	def do_subst(fun):
+		global all_modifs
+		for x in k:
+			try:
+				all_modifs[x].append(fun)
+			except KeyError:
+				all_modifs[x] = [fun]
+		return fun
+	return do_subst
+
+ at subst('*')
+def r1(code):
+	"utf-8 fixes for python < 2.6"
+	code = code.replace('as e:', ',e:')
+	code = code.replace(".decode(sys.stdout.encoding or 'iso8859-1')", '')
+	code = code.replace('.encode()', '')
+	return code
+
+ at subst('Runner.py')
+def r4(code):
+	"generator syntax"
+	code = code.replace('next(self.biter)', 'self.biter.next()')
+	return code
+
diff --git a/xpdeint/waf_extensions/cheetah.py b/xpdeint/waf_extensions/cheetah.py
new file mode 100644
index 0000000..daccc55
--- /dev/null
+++ b/xpdeint/waf_extensions/cheetah.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+cheetah.py
+
+Created by Graham Dennis on 2009-02-28.
+"""
+
+try:
+    from Cheetah.Template import Template
+except ImportError:
+    Template = None
+
+from waflib import Task, TaskGen
+
+def configure(conf):
+    conf.start_msg('Checking for the Cheetah python module')
+    if Template:
+        conf.end_msg('ok')
+    else:
+        conf.end_msg('Not found')
+
+class cheetah(Task.Task):
+    ext_in  = ['.tmpl']
+    ext_out = ['.py']
+    vars = ['CHEETAH_SETTINGS']
+    
+    def run(self):
+        env = self.env
+        bld = self.generator.bld
+
+        input_node = self.inputs[0]
+        output_node = self.outputs[0]
+
+        compilerSettings = 'CHEETAH_SETTINGS' in env and env['CHEETAH_SETTINGS'] or {}
+
+        basename = input_node.change_ext('').name
+
+        pysrc = Template.compile(
+            file = input_node.abspath(),
+            compilerSettings = compilerSettings,
+            moduleName = basename,
+            className = basename,
+            returnAClass = False,
+        )
+
+        output_node.write(pysrc)
+        return 0
+    
+
+ at TaskGen.extension('.tmpl')
+def cheetah_callback(self, node):
+    out = node.change_ext('.py').name
+    self.create_task('cheetah', node, node.parent.find_or_declare(out))
diff --git a/xpdeint/waf_extensions/cheetah.pyc b/xpdeint/waf_extensions/cheetah.pyc
new file mode 100644
index 0000000..a66835d
Binary files /dev/null and b/xpdeint/waf_extensions/cheetah.pyc differ
diff --git a/xpdeint/wscript b/xpdeint/wscript
new file mode 100644
index 0000000..d3a263c
--- /dev/null
+++ b/xpdeint/wscript
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+wscript
+
+The waf build script to compile all Cheetah templates.
+
+Created by Graham Dennis on 2009-02-22.
+
+Copyright (c) 2009-2012, Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+top = '.'
+out = '.'
+
+def options(opt):
+    opt.load('cheetah', tooldir='waf_extensions')
+
+def configure(conf):
+    conf.load('cheetah', tooldir='waf_extensions')
+    conf.env['CHEETAH_SETTINGS'] = {
+            'directiveStartToken': '@',
+            'commentStartToken': '@#',
+            'multiLineCommentStartToken': '@*',
+            'multiLineCommentEndToken': '*@',
+        }
+
+def build(bld):
+    sources = bld.path.ant_glob('**/*.tmpl')
+    if bld.cmd == 'clean':
+        for n in sources:
+            n.change_ext('.py').delete()
+        for n in bld.path.ant_glob('**/*.pyc'):
+            n.delete()
+    else:
+        bld(source=sources)
+
diff --git a/xpdeint/xsil2graphics2/MathematicaImport.py b/xpdeint/xsil2graphics2/MathematicaImport.py
new file mode 100644
index 0000000..b674f25
--- /dev/null
+++ b/xpdeint/xsil2graphics2/MathematicaImport.py
@@ -0,0 +1,418 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.794166
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/xsil2graphics2/MathematicaImport.tmpl'
+__CHEETAH_srcLastModified__ = 'Wed Jun  5 14:30:43 2013'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class MathematicaImport(Template):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(MathematicaImport, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Creates text to import data from XSIL files into Mathematica. at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Creates text to import data from XSIL files into Mathematica.''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def printMathematicaListOrElement(self, listOrElement, **KWS):
+
+
+
+        ## CHEETAH: generated from @def printMathematicaListOrElement(listOrElement) at line 29, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        #  This is a function to turn an array into a Mathematica list.  Called recursively, and assumes the elements are floats or lists.
+        if isinstance(listOrElement,float): # generated from line 31, col 3
+            _v = VFFSL(SL,"format",False)(float(listOrElement),'f') # u"${format(float(listOrElement),'f')}" on line 32, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u"${format(float(listOrElement),'f')}")) # from line 32, col 1.
+        else: # generated from line 33, col 3
+            write(u'''{''')
+            _v = ', '.join([VFFSL(SL,"printMathematicaListOrElement",False)(element) for element in listOrElement]) # u"${', '.join([$printMathematicaListOrElement(element) for element in listOrElement])}" on line 34, col 2
+            if _v is not None: write(_filter(_v, rawExpr=u"${', '.join([$printMathematicaListOrElement(element) for element in listOrElement])}")) # from line 34, col 2.
+            write(u'''}''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def loadXSILFile(self, xsilFile, **KWS):
+
+
+
+        ## CHEETAH: generated from @def loadXSILFile($xsilFile) at line 38, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        write(u'''SetDirectory[NotebookDirectory[]];
+''')
+        declaredVars = []
+        for objectNum, xsilObject in enumerate(xsilFile.xsilObjects): # generated from line 42, col 2
+            if xsilObject.data.format == 'ascii': # generated from line 43, col 4
+                nIndepVar = len(xsilObject.independentVariables)
+                for var in xsilObject.independentVariables: # generated from line 45, col 6
+                    varName = var["name"].replace('_','') + str(objectNum + 1)
+                    declaredVars.append(varName)
+                    write(u'''Clear[''')
+                    _v = VFFSL(SL,"varName",True) # u'$varName' on line 48, col 7
+                    if _v is not None: write(_filter(_v, rawExpr=u'$varName')) # from line 48, col 7.
+                    write(u''']
+''')
+                    _v = VFFSL(SL,"varName",True) # u'$varName' on line 49, col 1
+                    if _v is not None: write(_filter(_v, rawExpr=u'$varName')) # from line 49, col 1.
+                    write(u''' = {''')
+                    _v = ', '.join([format(float(e),'f') for e in var["array"]]) # u'${\', \'.join([format(float(e),\'f\') for e in var["array"]])}' on line 49, col 13
+                    if _v is not None: write(_filter(_v, rawExpr=u'${\', \'.join([format(float(e),\'f\') for e in var["array"]])}')) # from line 49, col 13.
+                    write(u'''};
+''')
+                for varD in xsilObject.dependentVariables: # generated from line 51, col 6
+                    varName = varD["name"].replace('_','') + str(objectNum + 1)
+                    declaredVars.append(varName)
+                    write(u'''Clear[''')
+                    _v = VFFSL(SL,"varName",True) # u'$varName' on line 54, col 7
+                    if _v is not None: write(_filter(_v, rawExpr=u'$varName')) # from line 54, col 7.
+                    write(u''']
+''')
+                    _v = VFFSL(SL,"varName",True) # u'$varName' on line 55, col 1
+                    if _v is not None: write(_filter(_v, rawExpr=u'$varName')) # from line 55, col 1.
+                    write(u''' = ''')
+                    _v = VFFSL(SL,"printMathematicaListOrElement",False)(VFFSL(SL,"varD",True)["array"]) # u'$printMathematicaListOrElement($varD["array"])' on line 55, col 12
+                    if _v is not None: write(_filter(_v, rawExpr=u'$printMathematicaListOrElement($varD["array"])')) # from line 55, col 12.
+                    write(u''';      
+''')
+                #  Binary output, so we merely link to the requisite data file and write a script to import it
+            elif xsilObject.data.format == 'binary': # generated from line 58, col 4
+                nIndepVar = len(xsilObject.independentVariables)
+                machineFormat = {'BigEndian': '1', 'LittleEndian': '-1'}.get(xsilObject.data.encoding, '$ByteOrdering')
+                uLongFormat = {'uint32': 'UnsignedInteger32', 'uint64': 'UnsignedInteger64'}.get(xsilObject.data.uLong, 'UnsignedInteger32')
+                outputPrecision = {'single': 'Real32', 'double': 'Real64'}.get(xsilObject.data.precision, 'Real64')
+                write(u'''fpDat = OpenRead["''')
+                _v = VFFSL(SL,"xsilObject.data.filename",True) # u'$xsilObject.data.filename' on line 63, col 19
+                if _v is not None: write(_filter(_v, rawExpr=u'$xsilObject.data.filename')) # from line 63, col 19.
+                write(u'''",BinaryFormat -> True];
+''')
+                for var in xsilObject.independentVariables: # generated from line 64, col 6
+                    varName = var["name"].replace('_','') + str(objectNum + 1)
+                    declaredVars.append(varName)
+                    _v = VFFSL(SL,"varName",True) # u'$(varName)' on line 67, col 1
+                    if _v is not None: write(_filter(_v, rawExpr=u'$(varName)')) # from line 67, col 1.
+                    write(u'''Len = BinaryRead[fpDat, "''')
+                    _v = VFFSL(SL,"uLongFormat",True) # u'$uLongFormat' on line 67, col 36
+                    if _v is not None: write(_filter(_v, rawExpr=u'$uLongFormat')) # from line 67, col 36.
+                    write(u'''", ByteOrdering->''')
+                    _v = VFFSL(SL,"machineFormat",True) # u'$machineFormat' on line 67, col 65
+                    if _v is not None: write(_filter(_v, rawExpr=u'$machineFormat')) # from line 67, col 65.
+                    write(u'''];
+''')
+                    _v = VFFSL(SL,"varName",True) # u'$(varName)' on line 68, col 1
+                    if _v is not None: write(_filter(_v, rawExpr=u'$(varName)')) # from line 68, col 1.
+                    write(u''' = Flatten[BinaryReadList[fpDat, {"''')
+                    _v = VFFSL(SL,"outputPrecision",True) # u'$outputPrecision' on line 68, col 46
+                    if _v is not None: write(_filter(_v, rawExpr=u'$outputPrecision')) # from line 68, col 46.
+                    write(u'''"}, ''')
+                    _v = VFFSL(SL,"varName",True) # u'$(varName)' on line 68, col 66
+                    if _v is not None: write(_filter(_v, rawExpr=u'$(varName)')) # from line 68, col 66.
+                    write(u'''Len, ByteOrdering->''')
+                    _v = VFFSL(SL,"machineFormat",True) # u'$machineFormat' on line 68, col 95
+                    if _v is not None: write(_filter(_v, rawExpr=u'$machineFormat')) # from line 68, col 95.
+                    write(u''']];
+''')
+                for varD in xsilObject.dependentVariables: # generated from line 70, col 6
+                    varName = varD["name"].replace('_','') + str(objectNum + 1)
+                    declaredVars.append(varName)
+                    _v = VFFSL(SL,"varName",True) # u'$(varName)' on line 73, col 1
+                    if _v is not None: write(_filter(_v, rawExpr=u'$(varName)')) # from line 73, col 1.
+                    write(u'''Len = BinaryRead[fpDat, "''')
+                    _v = VFFSL(SL,"uLongFormat",True) # u'$uLongFormat' on line 73, col 36
+                    if _v is not None: write(_filter(_v, rawExpr=u'$uLongFormat')) # from line 73, col 36.
+                    write(u'''", ByteOrdering->''')
+                    _v = VFFSL(SL,"machineFormat",True) # u'$machineFormat' on line 73, col 65
+                    if _v is not None: write(_filter(_v, rawExpr=u'$machineFormat')) # from line 73, col 65.
+                    write(u'''];
+''')
+                    if nIndepVar<=1: # generated from line 74, col 9
+                        _v = VFFSL(SL,"varName",True) # u'$varName' on line 75, col 1
+                        if _v is not None: write(_filter(_v, rawExpr=u'$varName')) # from line 75, col 1.
+                        write(u''' = Flatten[BinaryReadList[fpDat, {"''')
+                        _v = VFFSL(SL,"outputPrecision",True) # u'$outputPrecision' on line 75, col 44
+                        if _v is not None: write(_filter(_v, rawExpr=u'$outputPrecision')) # from line 75, col 44.
+                        write(u'''"}, ''')
+                        _v = VFFSL(SL,"varName",True) # u'$(varName)' on line 75, col 64
+                        if _v is not None: write(_filter(_v, rawExpr=u'$(varName)')) # from line 75, col 64.
+                        write(u'''Len, ByteOrdering->''')
+                        _v = VFFSL(SL,"machineFormat",True) # u'$machineFormat' on line 75, col 93
+                        if _v is not None: write(_filter(_v, rawExpr=u'$machineFormat')) # from line 75, col 93.
+                        write(u''']];
+''')
+                    else: # generated from line 76, col 9
+                        _v = VFFSL(SL,"varName",True) # u'$varName' on line 77, col 1
+                        if _v is not None: write(_filter(_v, rawExpr=u'$varName')) # from line 77, col 1.
+                        write(u''' = Flatten[Table[BinaryReadList[fpDat, {"''')
+                        _v = VFFSL(SL,"outputPrecision",True) # u'$outputPrecision' on line 77, col 50
+                        if _v is not None: write(_filter(_v, rawExpr=u'$outputPrecision')) # from line 77, col 50.
+                        write(u'''"}, ''')
+                        _v = VFN(VFFSL(SL,"xsilObject",True),"independentVariables",True)[-1]["name"] # u'$(xsilObject.independentVariables[-1]["name"])' on line 77, col 70
+                        if _v is not None: write(_filter(_v, rawExpr=u'$(xsilObject.independentVariables[-1]["name"])')) # from line 77, col 70.
+                        _v = VFFSL(SL,"objectNum",True)+1 # u'$(objectNum+1)' on line 77, col 116
+                        if _v is not None: write(_filter(_v, rawExpr=u'$(objectNum+1)')) # from line 77, col 116.
+                        write(u'''Len, ByteOrdering->''')
+                        _v = VFFSL(SL,"machineFormat",True) # u'$machineFormat' on line 77, col 149
+                        if _v is not None: write(_filter(_v, rawExpr=u'$machineFormat')) # from line 77, col 149.
+                        write(u''']''')
+                        for varIndex, varI in enumerate(xsilObject.independentVariables[0:-1]): # generated from line 78, col 11
+                            write(u''',{j''')
+                            _v = VFFSL(SL,"varIndex",True)+1 # u'$(varIndex+1)' on line 79, col 4
+                            if _v is not None: write(_filter(_v, rawExpr=u'$(varIndex+1)')) # from line 79, col 4.
+                            write(u''',1,''')
+                            _v = VFN(VFFSL(SL,"varI",True)["name"],"replace",False)('_','') # u'$(varI["name"].replace(\'_\',\'\'))' on line 79, col 20
+                            if _v is not None: write(_filter(_v, rawExpr=u'$(varI["name"].replace(\'_\',\'\'))')) # from line 79, col 20.
+                            _v = VFFSL(SL,"objectNum",True)+1 # u'$(objectNum+1)' on line 79, col 51
+                            if _v is not None: write(_filter(_v, rawExpr=u'$(objectNum+1)')) # from line 79, col 51.
+                            write(u'''Len}''')
+                        write(u'''],{''')
+                        for varIndex, varI2 in enumerate(xsilObject.independentVariables[0:-1]): # generated from line 82, col 11
+                            write(u'''{''')
+                            _v = VFFSL(SL,"varIndex",True)+1 # u'$(varIndex+1)' on line 83, col 2
+                            if _v is not None: write(_filter(_v, rawExpr=u'$(varIndex+1)')) # from line 83, col 2.
+                            write(u'''},''')
+                        write(u'''{''')
+                        _v = VFFSL(SL,"nIndepVar",True) # u'$nIndepVar' on line 85, col 2
+                        if _v is not None: write(_filter(_v, rawExpr=u'$nIndepVar')) # from line 85, col 2.
+                        write(u''',''')
+                        _v = VFFSL(SL,"nIndepVar",True)+1 # u'$(nIndepVar+1)' on line 85, col 13
+                        if _v is not None: write(_filter(_v, rawExpr=u'$(nIndepVar+1)')) # from line 85, col 13.
+                        write(u'''}}];
+''')
+                write(u'''Close[fpDat];
+''')
+            elif xsilObject.data.format == 'hdf5': # generated from line 89, col 4
+                variables = xsilObject.independentVariables[:]
+                variables.extend(xsilObject.dependentVariables)
+                filename = xsilObject.data.filename
+                groupName = xsilObject.data.groupName
+                for var in variables: # generated from line 94, col 6
+                    varName = var["name"].replace('_', '') + str(objectNum + 1)
+                    declaredVars.append(varName)
+                    _v = VFFSL(SL,"varName",True) # u'${varName}' on line 97, col 1
+                    if _v is not None: write(_filter(_v, rawExpr=u'${varName}')) # from line 97, col 1.
+                    write(u''' = Import["''')
+                    _v = VFFSL(SL,"filename",True) # u'${filename}' on line 97, col 22
+                    if _v is not None: write(_filter(_v, rawExpr=u'${filename}')) # from line 97, col 22.
+                    write(u'''", {"Datasets", "''')
+                    _v = VFFSL(SL,"groupName",True) # u'${groupName}' on line 97, col 50
+                    if _v is not None: write(_filter(_v, rawExpr=u'${groupName}')) # from line 97, col 50.
+                    write(u'''/''')
+                    _v = VFFSL(SL,"var.name",True) # u'${var.name}' on line 97, col 63
+                    if _v is not None: write(_filter(_v, rawExpr=u'${var.name}')) # from line 97, col 63.
+                    write(u'''"}];
+''')
+            else: # generated from line 99, col 4
+                raise Exception("No support for Mathematica output for XSIL format '%s'." % xsilObject.data.format)
+        write(u'''ResetDirectory[];
+
+declaredVariables={''')
+        _v = ', '.join([''.join([u'"',str(VFFSL(SL,"dV",True)),u'"']) for dV in declaredVars]) # u'${\', \'.join([c\'"$dV"\' for dV in declaredVars])}' on line 105, col 20
+        if _v is not None: write(_filter(_v, rawExpr=u'${\', \'.join([c\'"$dV"\' for dV in declaredVars])}')) # from line 105, col 20.
+        write(u'''}
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def respond(self, trans=None):
+
+
+
+        ## CHEETAH: main method generated for this template
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # MathematicaImport.tmpl
+        # 
+        # Created by Joe Hope on 2009-01-07.
+        # Modified by Graham Dennis on 2009-01-29
+        # 
+        # Copyright (c) 2009-2012, Joe Hope and Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    name = 'Mathematica 6+'
+
+    defaultExtension = 'nb'
+
+    _mainCheetahMethod_for_MathematicaImport= 'respond'
+
+## END CLASS DEFINITION
+
+if not hasattr(MathematicaImport, '_initCheetahAttributes'):
+    templateAPIClass = getattr(MathematicaImport, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(MathematicaImport)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=MathematicaImport()).run()
+
+
diff --git a/xpdeint/xsil2graphics2/MathematicaImport.tmpl b/xpdeint/xsil2graphics2/MathematicaImport.tmpl
new file mode 100644
index 0000000..62f1ecd
--- /dev/null
+++ b/xpdeint/xsil2graphics2/MathematicaImport.tmpl
@@ -0,0 +1,106 @@
+@*
+MathematicaImport.tmpl
+
+Created by Joe Hope on 2009-01-07.
+Modified by Graham Dennis on 2009-01-29
+
+Copyright (c) 2009-2012, Joe Hope and Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+
+ at def description: Creates text to import data from XSIL files into Mathematica.
+ at attr $name = 'Mathematica 6+'
+
+ at attr $defaultExtension = 'nb'
+
+ at def printMathematicaListOrElement(listOrElement)
+  @# This is a function to turn an array into a Mathematica list.  Called recursively, and assumes the elements are floats or lists.
+  @if isinstance(listOrElement,float):
+${format(float(listOrElement),'f')}@slurp
+  @else:
+{${', '.join([$printMathematicaListOrElement(element) for element in listOrElement])}}@slurp
+  @end if
+ at end def
+
+ at def loadXSILFile($xsilFile)
+ @#
+SetDirectory[NotebookDirectory[]];
+ @set declaredVars=[]
+ @for objectNum, xsilObject in enumerate(xsilFile.xsilObjects):
+   @if xsilObject.data.format == 'ascii':
+     @set nIndepVar = len(xsilObject.independentVariables)
+     @for var in xsilObject.independentVariables:
+       @set varName = var["name"].replace('_','') + str(objectNum + 1)
+       @silent declaredVars.append(varName)
+Clear[$varName]
+$varName = {${', '.join([format(float(e),'f') for e in var["array"]])}};
+     @end for
+     @for varD in xsilObject.dependentVariables:
+       @set varName = varD["name"].replace('_','') + str(objectNum + 1)
+       @silent declaredVars.append(varName)
+Clear[$varName]
+$varName = $printMathematicaListOrElement($varD["array"]);      
+     @end for 
+@# Binary output, so we merely link to the requisite data file and write a script to import it
+   @elif xsilObject.data.format == 'binary':
+     @set nIndepVar = len(xsilObject.independentVariables)
+     @set machineFormat = {'BigEndian': '1', 'LittleEndian': '-1'}.get(xsilObject.data.encoding, '$ByteOrdering')
+     @set uLongFormat = {'uint32': 'UnsignedInteger32', 'uint64': 'UnsignedInteger64'}.get(xsilObject.data.uLong, 'UnsignedInteger32')
+     @set outputPrecision = {'single': 'Real32', 'double': 'Real64'}.get(xsilObject.data.precision, 'Real64')
+fpDat = OpenRead["$xsilObject.data.filename",BinaryFormat -> True];
+     @for var in xsilObject.independentVariables:
+        @set varName = var["name"].replace('_','') + str(objectNum + 1)
+        @silent declaredVars.append(varName)
+$(varName)Len = BinaryRead[fpDat, "$uLongFormat", ByteOrdering->$machineFormat];
+$(varName) = Flatten[BinaryReadList[fpDat, {"$outputPrecision"}, $(varName)Len, ByteOrdering->$machineFormat]];
+     @end for
+     @for varD in xsilObject.dependentVariables:
+        @set varName = varD["name"].replace('_','') + str(objectNum + 1)
+        @silent declaredVars.append(varName)
+$(varName)Len = BinaryRead[fpDat, "$uLongFormat", ByteOrdering->$machineFormat];
+        @if nIndepVar<=1:
+$varName = Flatten[BinaryReadList[fpDat, {"$outputPrecision"}, $(varName)Len, ByteOrdering->$machineFormat]];
+        @else:
+$varName = Flatten[Table[BinaryReadList[fpDat, {"$outputPrecision"}, $(xsilObject.independentVariables[-1]["name"])$(objectNum+1)Len, ByteOrdering->$machineFormat]@slurp
+          @for varIndex, varI in enumerate(xsilObject.independentVariables[0:-1])
+,{j$(varIndex+1),1,$(varI["name"].replace('_',''))$(objectNum+1)Len}@slurp
+          @end for
+],{@slurp
+          @for varIndex, varI2 in enumerate(xsilObject.independentVariables[0:-1]):
+{$(varIndex+1)}, at slurp
+          @end for
+{$nIndepVar,$(nIndepVar+1)}}];
+        @end if
+     @end for
+Close[fpDat];
+   @elif xsilObject.data.format == 'hdf5'
+     @set $variables = xsilObject.independentVariables[:]
+     @silent variables.extend(xsilObject.dependentVariables)
+     @set $filename = xsilObject.data.filename
+     @set $groupName = xsilObject.data.groupName
+     @for var in variables
+       @set varName = var["name"].replace('_', '') + str(objectNum + 1)
+       @silent declaredVars.append(varName)
+${varName} = Import["${filename}", {"Datasets", "${groupName}/${var.name}"}];
+     @end for
+   @else
+     @raise Exception("No support for Mathematica output for XSIL format '%s'." % xsilObject.data.format)
+   @end if
+ @end for
+ResetDirectory[];
+
+declaredVariables={${', '.join([c'"$dV"' for dV in declaredVars])}}
+ at end def
diff --git a/xpdeint/xsil2graphics2/MatlabOctaveImport.py b/xpdeint/xsil2graphics2/MatlabOctaveImport.py
new file mode 100644
index 0000000..63a8846
--- /dev/null
+++ b/xpdeint/xsil2graphics2/MatlabOctaveImport.py
@@ -0,0 +1,686 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.883388
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/xsil2graphics2/MatlabOctaveImport.tmpl'
+__CHEETAH_srcLastModified__ = 'Mon Jul 29 21:30:22 2013'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class MatlabOctaveImport(Template):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(MatlabOctaveImport, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Creates text to import data from XSIL files into Matlab or Octave (where they are identical). at line 24, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Creates text to import data from XSIL files into Matlab or Octave (where they are identical).''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def printMatlabListOrElement(self, listOrElement, currentDepth, **KWS):
+
+
+
+        ## CHEETAH: generated from @def printMatlabListOrElement(listOrElement, currentDepth) at line 30, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        #  This is a function to turn an array into a Matlab list.  Called recursively, and assumes the elements are floats or lists.
+        if isinstance(listOrElement,float): # generated from line 32, col 3
+            _v = VFFSL(SL,"format",False)(float(listOrElement),VFFSL(SL,"stringFormat",True)) # u'${format(float(listOrElement),$stringFormat)}' on line 33, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${format(float(listOrElement),$stringFormat)}')) # from line 33, col 1.
+        else: # generated from line 34, col 3
+            write(u'''cat(''')
+            _v = VFFSL(SL,"currentDepth",True) # u'$currentDepth' on line 35, col 5
+            if _v is not None: write(_filter(_v, rawExpr=u'$currentDepth')) # from line 35, col 5.
+            write(u''', ''')
+            _v = ', '.join([VFFSL(SL,"printMatlabListOrElement",False)(element, currentDepth - 1) for element in listOrElement]) # u"${', '.join([$printMatlabListOrElement(element, currentDepth - 1) for element in listOrElement])}" on line 35, col 20
+            if _v is not None: write(_filter(_v, rawExpr=u"${', '.join([$printMatlabListOrElement(element, currentDepth - 1) for element in listOrElement])}")) # from line 35, col 20.
+            write(u''')''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def permuteDimensionsOfMATLABVariable(self, varName, **KWS):
+
+
+
+        ## CHEETAH: generated from @def permuteDimensionsOfMATLABVariable(varName) at line 39, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        _v = VFFSL(SL,"varName",True) # u'${varName}' on line 40, col 1
+        if _v is not None: write(_filter(_v, rawExpr=u'${varName}')) # from line 40, col 1.
+        write(u''' = permute(''')
+        _v = VFFSL(SL,"varName",True) # u'${varName}' on line 40, col 22
+        if _v is not None: write(_filter(_v, rawExpr=u'${varName}')) # from line 40, col 22.
+        write(u''', ndims(''')
+        _v = VFFSL(SL,"varName",True) # u'${varName}' on line 40, col 40
+        if _v is not None: write(_filter(_v, rawExpr=u'${varName}')) # from line 40, col 40.
+        write(u'''):-1:1);
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def generateVariableName(self, xsilVariable, xsilObjectNumber, **KWS):
+
+
+
+        ## CHEETAH: generated from @def generateVariableName(xsilVariable, xsilObjectNumber) at line 43, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        return ''.join([str(VFFSL(SL,"xsilVariable.name",True)),u'_',str(VFFSL(SL,"xsilObjectNumber",True)+1)])
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def loadXSILFile(self, xsilFile, **KWS):
+
+
+
+        ## CHEETAH: generated from @def loadXSILFile($xsilFile) at line 47, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        for objectNum, xsilObject in enumerate(xsilFile.xsilObjects): # generated from line 48, col 3
+            if xsilObject.data.format == 'ascii': # generated from line 49, col 5
+                _v = VFFSL(SL,"handleASCIIXSILObject",False)(objectNum, xsilObject) # u'${handleASCIIXSILObject(objectNum, xsilObject)}' on line 50, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${handleASCIIXSILObject(objectNum, xsilObject)}')) # from line 50, col 1.
+            elif xsilObject.data.format == 'binary': # generated from line 51, col 5
+                _v = VFFSL(SL,"handleBinaryXSILObject",False)(objectNum, xsilObject) # u'${handleBinaryXSILObject(objectNum, xsilObject)}' on line 52, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${handleBinaryXSILObject(objectNum, xsilObject)}')) # from line 52, col 1.
+            elif xsilObject.data.format == 'hdf5': # generated from line 53, col 5
+                _v = VFFSL(SL,"handleHDF5XSILObject",False)(objectNum, xsilObject) # u'${handleHDF5XSILObject(objectNum, xsilObject)}' on line 54, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'${handleHDF5XSILObject(objectNum, xsilObject)}')) # from line 54, col 1.
+            else: # generated from line 55, col 5
+                raise Exception("No support for Matlab/Octave output for XSIL format '%s'." % xsilObject.data.format)
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def handleASCIIXSILObject(self, objectNum, xsilObject, **KWS):
+
+
+
+        ## CHEETAH: generated from @def handleASCIIXSILObject(objectNum, xsilObject) at line 61, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        nIndepVar = len(xsilObject.independentVariables)
+        for var in xsilObject.independentVariables: # generated from line 63, col 3
+            varName = VFFSL(SL,"generateVariableName",False)(var, objectNum)
+            write(u'''clear ''')
+            _v = VFFSL(SL,"varName",True) # u'$varName' on line 65, col 7
+            if _v is not None: write(_filter(_v, rawExpr=u'$varName')) # from line 65, col 7.
+            write(u'''
+''')
+            _v = VFFSL(SL,"varName",True) # u'$varName' on line 66, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'$varName')) # from line 66, col 1.
+            write(u''' = [''')
+            _v = ', '.join([format(float(e),VFFSL(SL,"stringFormat",True)) for e in var["array"]]) # u'${\', \'.join([format(float(e),$stringFormat) for e in var["array"]])}' on line 66, col 13
+            if _v is not None: write(_filter(_v, rawExpr=u'${\', \'.join([format(float(e),$stringFormat) for e in var["array"]])}')) # from line 66, col 13.
+            write(u'''];
+''')
+        for varD in xsilObject.dependentVariables: # generated from line 68, col 3
+            varName = VFFSL(SL,"generateVariableName",False)(var, objectNum)
+            write(u'''clear ''')
+            _v = VFFSL(SL,"varName",True) # u'$varName' on line 70, col 7
+            if _v is not None: write(_filter(_v, rawExpr=u'$varName')) # from line 70, col 7.
+            write(u'''
+''')
+            if nIndepVar == 1: # generated from line 71, col 5
+                _v = VFFSL(SL,"varName",True) # u'$varName' on line 72, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'$varName')) # from line 72, col 1.
+                write(u''' = [''')
+                _v = ', '.join([format(float(e), VFFSL(SL,"stringFormat",True)) for e in varD["array"]]) # u'${\', \'.join([format(float(e), $stringFormat) for e in varD["array"]])}' on line 72, col 13
+                if _v is not None: write(_filter(_v, rawExpr=u'${\', \'.join([format(float(e), $stringFormat) for e in varD["array"]])}')) # from line 72, col 13.
+                write(u'''];
+''')
+            elif nIndepVar == 2: # generated from line 73, col 5
+                _v = VFFSL(SL,"varName",True) # u'$varName' on line 74, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'$varName')) # from line 74, col 1.
+                write(u''' = [''')
+                _v = ';'.join([(','.join([format(float(val), VFFSL(SL,"stringFormat",True)) for val in subArray])) for subArray in varD["array"]]) # u'${\';\'.join([(\',\'.join([format(float(val), $stringFormat) for val in subArray])) for subArray in varD["array"]])}' on line 74, col 13
+                if _v is not None: write(_filter(_v, rawExpr=u'${\';\'.join([(\',\'.join([format(float(val), $stringFormat) for val in subArray])) for subArray in varD["array"]])}')) # from line 74, col 13.
+                write(u'''];
+''')
+            else: # generated from line 75, col 5
+                _v = VFFSL(SL,"varName",True) # u'$varName' on line 76, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'$varName')) # from line 76, col 1.
+                write(u''' = ''')
+                _v = VFFSL(SL,"printMatlabListOrElement",False)(VFFSL(SL,"varD",True)["array"], VFFSL(SL,"nIndepVar",True)) # u'$printMatlabListOrElement($varD["array"], $nIndepVar)' on line 76, col 12
+                if _v is not None: write(_filter(_v, rawExpr=u'$printMatlabListOrElement($varD["array"], $nIndepVar)')) # from line 76, col 12.
+                write(u''';
+''')
+            _v = VFFSL(SL,"permuteDimensionsOfMATLABVariable",False)(varName) # u'${permuteDimensionsOfMATLABVariable(varName)}' on line 78, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${permuteDimensionsOfMATLABVariable(varName)}')) # from line 78, col 1.
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def handleBinaryXSILObject(self, objectNum, xsilObject, **KWS):
+
+
+
+        ## CHEETAH: generated from @def handleBinaryXSILObject(objectNum, xsilObject) at line 82, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        variablesToClear = ['fpDat', 'xmds_variableShape']
+        nIndepVar = len(xsilObject.independentVariables)
+        machineFormat = {'BigEndian': 'ieee-be', 'LittleEndian': 'ieee-le'}.get(xsilObject.data.encoding, 'native')
+        uLongFormat = {'uint32': 'uint32', 'uint64': 'uint64'}.get(xsilObject.data.uLong, 'uint64')
+        outputPrecision = {'single': 'single', 'double': 'double'}.get(xsilObject.data.precision, 'double')
+        write(u"""fpDat = fopen('""")
+        _v = VFFSL(SL,"xsilObject.data.filename",True) # u'$xsilObject.data.filename' on line 88, col 16
+        if _v is not None: write(_filter(_v, rawExpr=u'$xsilObject.data.filename')) # from line 88, col 16.
+        write(u"""','r', '""")
+        _v = VFFSL(SL,"machineFormat",True) # u'$machineFormat' on line 88, col 49
+        if _v is not None: write(_filter(_v, rawExpr=u'$machineFormat')) # from line 88, col 49.
+        write(u"""');
+if (fpDat < 0)
+  disp('Cannot open binary data file: """)
+        _v = VFFSL(SL,"xsilObject.data.filename",True) # u'${xsilObject.data.filename}' on line 90, col 39
+        if _v is not None: write(_filter(_v, rawExpr=u'${xsilObject.data.filename}')) # from line 90, col 39.
+        write(u"""');
+  return;
+end
+xmds_variableShape = [];
+""")
+        for var in xsilObject.independentVariables: # generated from line 94, col 3
+            varName = VFFSL(SL,"generateVariableName",False)(var, objectNum)
+            variablesToClear.append(''.join([str(VFFSL(SL,"varName",True)),u'Len']))
+            _v = VFFSL(SL,"varName",True) # u'$(varName)' on line 97, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'$(varName)')) # from line 97, col 1.
+            write(u"""Len = fread(fpDat, 1, '""")
+            _v = VFFSL(SL,"uLongFormat",True) # u'$uLongFormat' on line 97, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'$uLongFormat')) # from line 97, col 34.
+            write(u"""');
+""")
+            _v = VFFSL(SL,"varName",True) # u'$(varName)' on line 98, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'$(varName)')) # from line 98, col 1.
+            write(u''' = fread(fpDat, ''')
+            _v = VFFSL(SL,"varName",True) # u'$(varName)' on line 98, col 27
+            if _v is not None: write(_filter(_v, rawExpr=u'$(varName)')) # from line 98, col 27.
+            write(u"""Len, '""")
+            _v = VFFSL(SL,"outputPrecision",True) # u'$outputPrecision' on line 98, col 43
+            if _v is not None: write(_filter(_v, rawExpr=u'$outputPrecision')) # from line 98, col 43.
+            write(u"""');
+xmds_variableShape = [""")
+            _v = VFFSL(SL,"varName",True) # u'${varName}' on line 99, col 23
+            if _v is not None: write(_filter(_v, rawExpr=u'${varName}')) # from line 99, col 23.
+            write(u'''Len xmds_variableShape];
+''')
+        write(u'''if (length(xmds_variableShape) == 0)
+  xmds_variableShape = [1 1];
+elseif (length(xmds_variableShape) == 1)
+  xmds_variableShape(end+1) = 1;
+end
+''')
+        for varD in xsilObject.dependentVariables: # generated from line 106, col 3
+            varName = VFFSL(SL,"generateVariableName",False)(varD, objectNum)
+            variablesToClear.append(''.join([str(VFFSL(SL,"varName",True)),u'Len']))
+            _v = VFFSL(SL,"varName",True) # u'$(varName)' on line 109, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'$(varName)')) # from line 109, col 1.
+            write(u"""Len = fread(fpDat, 1, '""")
+            _v = VFFSL(SL,"uLongFormat",True) # u'$uLongFormat' on line 109, col 34
+            if _v is not None: write(_filter(_v, rawExpr=u'$uLongFormat')) # from line 109, col 34.
+            write(u"""', 0, '""")
+            _v = VFFSL(SL,"machineFormat",True) # u'$machineFormat' on line 109, col 53
+            if _v is not None: write(_filter(_v, rawExpr=u'$machineFormat')) # from line 109, col 53.
+            write(u"""');
+""")
+            _v = VFFSL(SL,"varName",True) # u'$varName' on line 110, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'$varName')) # from line 110, col 1.
+            write(u''' = fread(fpDat, ''')
+            _v = VFFSL(SL,"varName",True) # u'$(varName)' on line 110, col 25
+            if _v is not None: write(_filter(_v, rawExpr=u'$(varName)')) # from line 110, col 25.
+            write(u"""Len, '""")
+            _v = VFFSL(SL,"outputPrecision",True) # u'$outputPrecision' on line 110, col 41
+            if _v is not None: write(_filter(_v, rawExpr=u'$outputPrecision')) # from line 110, col 41.
+            write(u"""');
+""")
+            _v = VFFSL(SL,"varName",True) # u'$varName' on line 111, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'$varName')) # from line 111, col 1.
+            write(u''' = reshape(''')
+            _v = VFFSL(SL,"varName",True) # u'$varName' on line 111, col 20
+            if _v is not None: write(_filter(_v, rawExpr=u'$varName')) # from line 111, col 20.
+            write(u''', xmds_variableShape);
+''')
+            _v = VFFSL(SL,"permuteDimensionsOfMATLABVariable",False)(varName) # u'${permuteDimensionsOfMATLABVariable(varName)}' on line 112, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${permuteDimensionsOfMATLABVariable(varName)}')) # from line 112, col 1.
+        write(u'''fclose(fpDat);
+clear ''')
+        _v = ' '.join(variablesToClear) # u"${' '.join(variablesToClear)}" on line 115, col 7
+        if _v is not None: write(_filter(_v, rawExpr=u"${' '.join(variablesToClear)}")) # from line 115, col 7.
+        write(u'''
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def handleHDF5XSILObject(self, objectNum, xsilObject, **KWS):
+
+
+
+        ## CHEETAH: generated from @def handleHDF5XSILObject(objectNum, xsilObject) at line 118, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u"""if (exist('OCTAVE_VERSION', 'builtin')) % Octave
+  """)
+        _v = VFFSL(SL,"handleHDF5XSILObjectForOctave",False)(objectNum, xsilObject) # u'${handleHDF5XSILObjectForOctave(objectNum, xsilObject), autoIndent=True}' on line 120, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${handleHDF5XSILObjectForOctave(objectNum, xsilObject), autoIndent=True}')) # from line 120, col 3.
+        write(u'''else % MATLAB
+  ''')
+        _v = VFFSL(SL,"handleHDF5XSILObjectForMATLAB",False)(objectNum, xsilObject) # u'${handleHDF5XSILObjectForMATLAB(objectNum, xsilObject), autoIndent=True}' on line 122, col 3
+        if _v is not None: write(_filter(_v, autoIndent=True, rawExpr=u'${handleHDF5XSILObjectForMATLAB(objectNum, xsilObject), autoIndent=True}')) # from line 122, col 3.
+        write(u'''end
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def handleHDF5XSILObjectForMATLAB(self, objectNum, xsilObject, **KWS):
+
+
+
+        ## CHEETAH: generated from @def handleHDF5XSILObjectForMATLAB(objectNum, xsilObject) at line 127, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        filename = xsilObject.data.filename
+        groupName = xsilObject.data.groupName
+        for var in xsilObject.independentVariables: # generated from line 130, col 3
+            outName = VFFSL(SL,"generateVariableName",False)(var, objectNum)
+            _v = VFFSL(SL,"outName",True) # u'${outName}' on line 132, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${outName}')) # from line 132, col 1.
+            write(u""" = hdf5read('""")
+            _v = VFFSL(SL,"filename",True) # u'${filename}' on line 132, col 24
+            if _v is not None: write(_filter(_v, rawExpr=u'${filename}')) # from line 132, col 24.
+            write(u"""', '""")
+            _v = VFFSL(SL,"groupName",True) # u'${groupName}' on line 132, col 39
+            if _v is not None: write(_filter(_v, rawExpr=u'${groupName}')) # from line 132, col 39.
+            write(u'''/''')
+            _v = VFFSL(SL,"var.name",True) # u'${var.name}' on line 132, col 52
+            if _v is not None: write(_filter(_v, rawExpr=u'${var.name}')) # from line 132, col 52.
+            write(u"""');
+""")
+        for var in xsilObject.dependentVariables: # generated from line 134, col 3
+            outName = VFFSL(SL,"generateVariableName",False)(var, objectNum)
+            _v = VFFSL(SL,"outName",True) # u'${outName}' on line 136, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${outName}')) # from line 136, col 1.
+            write(u""" = hdf5read('""")
+            _v = VFFSL(SL,"filename",True) # u'${filename}' on line 136, col 24
+            if _v is not None: write(_filter(_v, rawExpr=u'${filename}')) # from line 136, col 24.
+            write(u"""', '""")
+            _v = VFFSL(SL,"groupName",True) # u'${groupName}' on line 136, col 39
+            if _v is not None: write(_filter(_v, rawExpr=u'${groupName}')) # from line 136, col 39.
+            write(u'''/''')
+            _v = VFFSL(SL,"var.name",True) # u'${var.name}' on line 136, col 52
+            if _v is not None: write(_filter(_v, rawExpr=u'${var.name}')) # from line 136, col 52.
+            write(u"""');
+""")
+            _v = VFFSL(SL,"permuteDimensionsOfMATLABVariable",False)(outName) # u'${permuteDimensionsOfMATLABVariable(outName)}' on line 137, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${permuteDimensionsOfMATLABVariable(outName)}')) # from line 137, col 1.
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def handleHDF5XSILObjectForOctave(self, objectNum, xsilObject, **KWS):
+
+
+
+        ## CHEETAH: generated from @def handleHDF5XSILObjectForOctave(objectNum, xsilObject) at line 141, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        filename = xsilObject.data.filename
+        variables = xsilObject.independentVariables[:]
+        write(u'''load ''')
+        _v = VFFSL(SL,"filename",True) # u'${filename}' on line 144, col 6
+        if _v is not None: write(_filter(_v, rawExpr=u'${filename}')) # from line 144, col 6.
+        write(u'''
+''')
+        for var in xsilObject.independentVariables: # generated from line 145, col 3
+            outName = VFFSL(SL,"generateVariableName",False)(var, objectNum)
+            #  We have to do an eval here because variables with leading underscores are not valid in MATLAB
+            #  (although accepted by Octave), and the MATLAB parser dies if there are expressions with leading underscores.
+            _v = VFFSL(SL,"outName",True) # u'${outName}' on line 149, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${outName}')) # from line 149, col 1.
+            write(u""" = eval('_""")
+            _v = VFFSL(SL,"objectNum",True)+1 # u'${objectNum+1}' on line 149, col 21
+            if _v is not None: write(_filter(_v, rawExpr=u'${objectNum+1}')) # from line 149, col 21.
+            write(u'''.''')
+            _v = VFFSL(SL,"var.name",True) # u'${var.name}' on line 149, col 36
+            if _v is not None: write(_filter(_v, rawExpr=u'${var.name}')) # from line 149, col 36.
+            write(u"""');
+""")
+        for var in xsilObject.dependentVariables: # generated from line 151, col 3
+            outName = VFFSL(SL,"generateVariableName",False)(var, objectNum)
+            _v = VFFSL(SL,"outName",True) # u'${outName}' on line 153, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${outName}')) # from line 153, col 1.
+            write(u""" = eval('_""")
+            _v = VFFSL(SL,"objectNum",True)+1 # u'${objectNum+1}' on line 153, col 21
+            if _v is not None: write(_filter(_v, rawExpr=u'${objectNum+1}')) # from line 153, col 21.
+            write(u'''.''')
+            _v = VFFSL(SL,"var.name",True) # u'${var.name}' on line 153, col 36
+            if _v is not None: write(_filter(_v, rawExpr=u'${var.name}')) # from line 153, col 36.
+            write(u"""');
+""")
+            _v = VFFSL(SL,"permuteDimensionsOfMATLABVariable",False)(outName) # u'${permuteDimensionsOfMATLABVariable(outName)}' on line 154, col 1
+            if _v is not None: write(_filter(_v, rawExpr=u'${permuteDimensionsOfMATLABVariable(outName)}')) # from line 154, col 1.
+        write(u'''clear _''')
+        _v = VFFSL(SL,"objectNum",True)+1 # u'${objectNum+1}' on line 156, col 8
+        if _v is not None: write(_filter(_v, rawExpr=u'${objectNum+1}')) # from line 156, col 8.
+        write(u''';
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def respond(self, trans=None):
+
+
+
+        ## CHEETAH: main method generated for this template
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # MatlabOctaveImport.tmpl
+        # 
+        # Created by Joe Hope on 2009-01-07.
+        # Modified by Gregory Bogomiagkov and Liam Madge on 2013-07-18.
+        # 
+        # Copyright (c) 2009-2013, Joe Hope and Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+
+
+
+
+
+
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    defaultExtension = 'm'
+
+    stringFormat = '.12e'
+
+    name = 'MATLAB/Octave'
+
+    _mainCheetahMethod_for_MatlabOctaveImport= 'respond'
+
+## END CLASS DEFINITION
+
+if not hasattr(MatlabOctaveImport, '_initCheetahAttributes'):
+    templateAPIClass = getattr(MatlabOctaveImport, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(MatlabOctaveImport)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=MatlabOctaveImport()).run()
+
+
diff --git a/xpdeint/xsil2graphics2/MatlabOctaveImport.tmpl b/xpdeint/xsil2graphics2/MatlabOctaveImport.tmpl
new file mode 100644
index 0000000..be94172
--- /dev/null
+++ b/xpdeint/xsil2graphics2/MatlabOctaveImport.tmpl
@@ -0,0 +1,158 @@
+@*
+MatlabOctaveImport.tmpl
+
+Created by Joe Hope on 2009-01-07.
+Modified by Gregory Bogomiagkov and Liam Madge on 2013-07-18.
+
+Copyright (c) 2009-2013, Joe Hope and Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+
+ at def description: Creates text to import data from XSIL files into Matlab or Octave (where they are identical).
+
+ at attr $defaultExtension = 'm'
+ at attr $stringFormat = '.12e'
+ at attr $name = 'MATLAB/Octave'
+
+ at def printMatlabListOrElement(listOrElement, currentDepth)
+  @# This is a function to turn an array into a Matlab list.  Called recursively, and assumes the elements are floats or lists.
+  @if isinstance(listOrElement,float):
+${format(float(listOrElement),$stringFormat)}@slurp
+  @else:
+cat($currentDepth, ${', '.join([$printMatlabListOrElement(element, currentDepth - 1) for element in listOrElement])})@slurp
+  @end if
+ at end def
+
+ at def permuteDimensionsOfMATLABVariable(varName)
+${varName} = permute(${varName}, ndims(${varName}):-1:1);
+ at end def
+
+ at def generateVariableName(xsilVariable, xsilObjectNumber)
+  @return c'${xsilVariable.name}_${xsilObjectNumber+1}'
+ at end def
+
+ at def loadXSILFile($xsilFile)
+  @for objectNum, xsilObject in enumerate(xsilFile.xsilObjects):
+    @if xsilObject.data.format == 'ascii':
+${handleASCIIXSILObject(objectNum, xsilObject)}@slurp
+    @elif xsilObject.data.format == 'binary':
+${handleBinaryXSILObject(objectNum, xsilObject)}@slurp
+    @elif xsilObject.data.format == 'hdf5'
+${handleHDF5XSILObject(objectNum, xsilObject)}@slurp
+    @else
+      @raise Exception("No support for Matlab/Octave output for XSIL format '%s'." % xsilObject.data.format)
+    @end if
+  @end for
+ at end def
+
+ at def handleASCIIXSILObject(objectNum, xsilObject)
+  @set nIndepVar = len(xsilObject.independentVariables)
+  @for var in xsilObject.independentVariables:
+    @set varName = $generateVariableName(var, objectNum)
+clear $varName
+$varName = [${', '.join([format(float(e),$stringFormat) for e in var["array"]])}];
+  @end for
+  @for varD in xsilObject.dependentVariables:
+    @set varName = $generateVariableName(var, objectNum)
+clear $varName
+    @if nIndepVar == 1:
+$varName = [${', '.join([format(float(e), $stringFormat) for e in varD["array"]])}];
+    @else if nIndepVar == 2:
+$varName = [${';'.join([(','.join([format(float(val), $stringFormat) for val in subArray])) for subArray in varD["array"]])}];
+    @else
+$varName = $printMatlabListOrElement($varD["array"], $nIndepVar);
+    @end if
+${permuteDimensionsOfMATLABVariable(varName)}@slurp
+  @end for
+ at end def
+
+ at def handleBinaryXSILObject(objectNum, xsilObject)
+  @set variablesToClear = ['fpDat', 'xmds_variableShape']
+  @set nIndepVar = len(xsilObject.independentVariables)
+  @set machineFormat = {'BigEndian': 'ieee-be', 'LittleEndian': 'ieee-le'}.get(xsilObject.data.encoding, 'native')
+  @set uLongFormat = {'uint32': 'uint32', 'uint64': 'uint64'}.get(xsilObject.data.uLong, 'uint64')
+  @set outputPrecision = {'single': 'single', 'double': 'double'}.get(xsilObject.data.precision, 'double')
+fpDat = fopen('$xsilObject.data.filename','r', '$machineFormat');
+if (fpDat < 0)
+  disp('Cannot open binary data file: ${xsilObject.data.filename}');
+  return;
+end
+xmds_variableShape = [];
+  @for var in xsilObject.independentVariables:
+    @set varName = $generateVariableName(var, objectNum)
+    @silent variablesToClear.append(c'${varName}Len')
+$(varName)Len = fread(fpDat, 1, '$uLongFormat');
+$(varName) = fread(fpDat, $(varName)Len, '$outputPrecision');
+xmds_variableShape = [${varName}Len xmds_variableShape];
+  @end for
+if (length(xmds_variableShape) == 0)
+  xmds_variableShape = [1 1];
+elseif (length(xmds_variableShape) == 1)
+  xmds_variableShape(end+1) = 1;
+end
+  @for varD in xsilObject.dependentVariables:
+    @set varName = $generateVariableName(varD, objectNum)
+    @silent variablesToClear.append(c'${varName}Len')
+$(varName)Len = fread(fpDat, 1, '$uLongFormat', 0, '$machineFormat');
+$varName = fread(fpDat, $(varName)Len, '$outputPrecision');
+$varName = reshape($varName, xmds_variableShape);
+${permuteDimensionsOfMATLABVariable(varName)}@slurp
+  @end for
+fclose(fpDat);
+clear ${' '.join(variablesToClear)}
+ at end def
+
+ at def handleHDF5XSILObject(objectNum, xsilObject)
+if (exist('OCTAVE_VERSION', 'builtin')) % Octave
+  ${handleHDF5XSILObjectForOctave(objectNum, xsilObject), autoIndent=True}@slurp
+else % MATLAB
+  ${handleHDF5XSILObjectForMATLAB(objectNum, xsilObject), autoIndent=True}@slurp
+end
+ at end def
+
+
+ at def handleHDF5XSILObjectForMATLAB(objectNum, xsilObject)
+  @set $filename = xsilObject.data.filename
+  @set $groupName = xsilObject.data.groupName
+  @for var in xsilObject.independentVariables:
+    @set outName = $generateVariableName(var, objectNum)
+${outName} = hdf5read('${filename}', '${groupName}/${var.name}');
+  @end for
+  @for var in xsilObject.dependentVariables:
+    @set outName = $generateVariableName(var, objectNum)
+${outName} = hdf5read('${filename}', '${groupName}/${var.name}');
+${permuteDimensionsOfMATLABVariable(outName)}@slurp
+  @end for
+ at end def
+
+ at def handleHDF5XSILObjectForOctave(objectNum, xsilObject)
+  @set $filename = xsilObject.data.filename
+  @set $variables = xsilObject.independentVariables[:]
+load ${filename}
+  @for var in xsilObject.independentVariables:
+    @set outName = $generateVariableName(var, objectNum)
+    @# We have to do an eval here because variables with leading underscores are not valid in MATLAB
+    @# (although accepted by Octave), and the MATLAB parser dies if there are expressions with leading underscores.
+${outName} = eval('_${objectNum+1}.${var.name}');
+  @end for
+  @for var in xsilObject.dependentVariables:
+    @set outName = $generateVariableName(var, objectNum)
+${outName} = eval('_${objectNum+1}.${var.name}');
+${permuteDimensionsOfMATLABVariable(outName)}@slurp
+  @end for
+clear _${objectNum+1};
+ at end def
+
diff --git a/xpdeint/xsil2graphics2/PythonImport.py b/xpdeint/xsil2graphics2/PythonImport.py
new file mode 100644
index 0000000..2ad4682
--- /dev/null
+++ b/xpdeint/xsil2graphics2/PythonImport.py
@@ -0,0 +1,256 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+try:
+    import builtins as builtin
+except ImportError:
+    import __builtin__ as builtin
+from os.path import getmtime, exists
+import time
+import types
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import *
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+
+##################################################
+## MODULE CONSTANTS
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.4.4'
+__CHEETAH_versionTuple__ = (2, 4, 4, 'development', 0)
+__CHEETAH_genTime__ = 1380322833.89898
+__CHEETAH_genTimestamp__ = 'Sat Sep 28 09:00:33 2013'
+__CHEETAH_src__ = '/Users/graham/Library/XMDS/src/xmds2/admin/staging/xmds-2.1.4/xpdeint/xsil2graphics2/PythonImport.tmpl'
+__CHEETAH_srcLastModified__ = 'Sun Jul 28 14:51:41 2013'
+__CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+    raise AssertionError(
+      'This template was compiled with Cheetah version'
+      ' %s. Templates compiled before version %s must be recompiled.'%(
+         __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class PythonImport(Template):
+
+    ##################################################
+    ## CHEETAH GENERATED METHODS
+
+
+    def __init__(self, *args, **KWs):
+
+        super(PythonImport, self).__init__(*args, **KWs)
+        if not self._CHEETAH__instanceInitialized:
+            cheetahKWArgs = {}
+            allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+            for k,v in KWs.items():
+                if k in allowedKWs: cheetahKWArgs[k] = v
+            self._initCheetahInstance(**cheetahKWArgs)
+        
+
+    def description(self, **KWS):
+
+
+
+        ## Generated from @def description: Creates text to import data from XSIL files into PyLab. at line 25, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''Creates text to import data from XSIL files into PyLab.''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def loadXSILFile(self, xsilFile, **KWS):
+
+
+
+        ## CHEETAH: generated from @def loadXSILFile($xsilFile) at line 31, col 1.
+        trans = KWS.get("trans")
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        write(u'''#!/usr/bin/env python
+from xpdeint.XSILFile import XSILFile
+
+xsilFile = XSILFile("''')
+        _v = VFFSL(SL,"xsilFile.filename",True) # u'$xsilFile.filename' on line 35, col 22
+        if _v is not None: write(_filter(_v, rawExpr=u'$xsilFile.filename')) # from line 35, col 22.
+        write(u'''")
+
+def firstElementOrNone(enumerable):
+  for element in enumerable:
+    return element
+  return None
+
+''')
+        for objectNum, xsilObject in enumerate(xsilFile.xsilObjects): # generated from line 42, col 3
+            for var in xsilObject.independentVariables: # generated from line 43, col 5
+                varName = ''.join([str(VFFSL(SL,"var.name",True)),u'_',str(VFFSL(SL,"objectNum",True)+1)])
+                _v = VFFSL(SL,"varName",True) # u'$varName' on line 45, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'$varName')) # from line 45, col 1.
+                write(u''' = firstElementOrNone(_["array"] for _ in xsilFile.xsilObjects[''')
+                _v = VFFSL(SL,"objectNum",True) # u'$objectNum' on line 45, col 72
+                if _v is not None: write(_filter(_v, rawExpr=u'$objectNum')) # from line 45, col 72.
+                write(u'''].independentVariables if _["name"] == "''')
+                _v = VFFSL(SL,"var.name",True) # u'${var.name}' on line 45, col 122
+                if _v is not None: write(_filter(_v, rawExpr=u'${var.name}')) # from line 45, col 122.
+                write(u'''")
+''')
+            for var in xsilObject.dependentVariables: # generated from line 47, col 5
+                varName = ''.join([str(VFFSL(SL,"var.name",True)),u'_',str(VFFSL(SL,"objectNum",True)+1)])
+                _v = VFFSL(SL,"varName",True) # u'$varName' on line 49, col 1
+                if _v is not None: write(_filter(_v, rawExpr=u'$varName')) # from line 49, col 1.
+                write(u''' = firstElementOrNone(_["array"] for _ in xsilFile.xsilObjects[''')
+                _v = VFFSL(SL,"objectNum",True) # u'$objectNum' on line 49, col 72
+                if _v is not None: write(_filter(_v, rawExpr=u'$objectNum')) # from line 49, col 72.
+                write(u'''].dependentVariables if _["name"] == "''')
+                _v = VFFSL(SL,"var.name",True) # u'${var.name}' on line 49, col 120
+                if _v is not None: write(_filter(_v, rawExpr=u'${var.name}')) # from line 49, col 120.
+                write(u'''")
+''')
+        write(u'''
+# Write your plotting commands here.
+# You may want to import pylab (from pylab import *) or matplotlib (from matplotlib import *)
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+
+    def respond(self, trans=None):
+
+
+
+        ## CHEETAH: main method generated for this template
+        if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+            trans = self.transaction # is None unless self.awake() was called
+        if not trans:
+            trans = DummyTransaction()
+            _dummyTrans = True
+        else: _dummyTrans = False
+        write = trans.response().write
+        SL = self._CHEETAH__searchList
+        _filter = self._CHEETAH__currentFilter
+        
+        ########################################
+        ## START - generated method body
+        
+        # 
+        # PythonImport.tmpl
+        # 
+        # Created by Thomas Antioch on 2013-05-31.
+        # Modified by Thomas Antioch on 2013-07-18.
+        # Modified by Graham Dennis on 2013-07-28.
+        # 
+        # Copyright (c) 2009-2013, Joe Hope and Graham Dennis
+        # 
+        # This program is free software: you can redistribute it and/or modify
+        # it under the terms of the GNU General Public License as published by
+        # the Free Software Foundation, either version 2 of the License, or
+        # (at your option) any later version.
+        # 
+        # This program is distributed in the hope that it will be useful,
+        # but WITHOUT ANY WARRANTY; without even the implied warranty of
+        # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        # GNU General Public License for more details.
+        # 
+        # You should have received a copy of the GNU General Public License
+        # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        # 
+        write(u'''
+
+
+
+''')
+        
+        ########################################
+        ## END - generated method body
+        
+        return _dummyTrans and trans.response().getvalue() or ""
+        
+    ##################################################
+    ## CHEETAH GENERATED ATTRIBUTES
+
+
+    _CHEETAH__instanceInitialized = False
+
+    _CHEETAH_version = __CHEETAH_version__
+
+    _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+    _CHEETAH_genTime = __CHEETAH_genTime__
+
+    _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+    _CHEETAH_src = __CHEETAH_src__
+
+    _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+    name = 'Python'
+
+    defaultExtension = 'py'
+
+    _mainCheetahMethod_for_PythonImport= 'respond'
+
+## END CLASS DEFINITION
+
+if not hasattr(PythonImport, '_initCheetahAttributes'):
+    templateAPIClass = getattr(PythonImport, '_CHEETAH_templateClass', Template)
+    templateAPIClass._addCheetahPlumbingCodeToClass(PythonImport)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+    from Cheetah.TemplateCmdLineIface import CmdLineIface
+    CmdLineIface(templateObj=PythonImport()).run()
+
+
diff --git a/xpdeint/xsil2graphics2/PythonImport.tmpl b/xpdeint/xsil2graphics2/PythonImport.tmpl
new file mode 100755
index 0000000..00c59ac
--- /dev/null
+++ b/xpdeint/xsil2graphics2/PythonImport.tmpl
@@ -0,0 +1,56 @@
+@*
+PythonImport.tmpl
+
+Created by Thomas Antioch on 2013-05-31.
+Modified by Thomas Antioch on 2013-07-18.
+Modified by Graham Dennis on 2013-07-28.
+
+Copyright (c) 2009-2013, Joe Hope and Graham Dennis
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*@
+
+ at def description: Creates text to import data from XSIL files into PyLab.
+ at attr $name = 'Python'
+
+ at attr $defaultExtension = 'py'
+
+
+ at def loadXSILFile($xsilFile)
+#!/usr/bin/env python
+from xpdeint.XSILFile import XSILFile
+
+xsilFile = XSILFile("$xsilFile.filename")
+
+def firstElementOrNone(enumerable):
+  for element in enumerable:
+    return element
+  return None
+
+  @for objectNum, xsilObject in enumerate(xsilFile.xsilObjects)
+    @for var in xsilObject.independentVariables
+      @set varName = c'${var.name}_${objectNum+1}'
+$varName = firstElementOrNone(_["array"] for _ in xsilFile.xsilObjects[$objectNum].independentVariables if _["name"] == "${var.name}")
+    @end for
+    @for var in xsilObject.dependentVariables
+      @set varName = c'${var.name}_${objectNum+1}'
+$varName = firstElementOrNone(_["array"] for _ in xsilFile.xsilObjects[$objectNum].dependentVariables if _["name"] == "${var.name}")
+    @end for
+  @end for
+
+# Write your plotting commands here.
+# You may want to import pylab (from pylab import *) or matplotlib (from matplotlib import *)
+
+ at end def
diff --git a/xpdeint/xsil2graphics2/__init__.py b/xpdeint/xsil2graphics2/__init__.py
new file mode 100644
index 0000000..4287ca8
--- /dev/null
+++ b/xpdeint/xsil2graphics2/__init__.py
@@ -0,0 +1 @@
+#
\ No newline at end of file
diff --git a/xpdeint/xsil2graphicsParser.py b/xpdeint/xsil2graphicsParser.py
new file mode 100755
index 0000000..15d0f25
--- /dev/null
+++ b/xpdeint/xsil2graphicsParser.py
@@ -0,0 +1,165 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+xsil2graphicsParser.py
+
+Created by Joe Hope on 2009-01-06.
+Modified by Thomas Antioch on 2013-07-18.
+
+Copyright (c) 2009-2012, Joe Hope
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+import os
+import sys
+import getopt
+
+from xpdeint.XSILFile import XSILFile
+from xpdeint.IndentFilter import IndentFilter
+
+# Hack for Mac OS X so it doesn't import the web rendering
+# framework WebKit when Cheetah tries to import the Python
+# web application framework WebKit
+if sys.platform == 'darwin':
+  module = type(sys)
+  sys.modules['WebKit'] = module('WebKit')
+
+from xpdeint.xsil2graphics2.MathematicaImport import MathematicaImport
+from xpdeint.xsil2graphics2.MatlabOctaveImport import MatlabOctaveImport
+from xpdeint.xsil2graphics2.PythonImport import PythonImport
+
+
+# The help message printed when --help is used as an argument
+help_message = '''
+usage: xsil2graphics2 [options] filenames [...]
+
+Options and arguments for xsil2graphics2:
+-h          : Print this message (also --help)
+-o filename : This overrides the name of the output file to be generated (also --output)
+-d          : Debug mode (also --debug)
+
+Options:
+  infile(s):        required, the input xsil file or files
+  -h/--help:        optional, display this information
+  -m/--matlab:      optional, produce matlab output (default, also supports Octave)
+  -e/--mathematica: optional, produce mathematica output
+  -8/--octave:      optional, produce octave output (identical to MATLAB output)
+  -p/--python:      optional, produce Python/pylab/matplotlib script (HDF5 requires h5py)
+  -o/--outfile:     optional, alternate output file name (one input file only)
+  --debug:          Debug mode
+  
+
+For further help, please see http://www.xmds.org
+'''
+
+class Usage(Exception):
+  """
+  Exception class used when an error occurs parsing command
+  line arguments.
+  """
+  def __init__(self, msg):
+    self.msg = msg
+  
+
+def main(argv=None):
+  # Default to not being verbose with error messages
+  # If debug is true, then when an error occurs during parsing,
+  # the Python backtrace will be shown in addition to the XML location
+  # where the error occurred.
+  debug = False
+  
+  # Import version information
+  from Preferences import versionString
+  from Version import subversionRevisionString
+  
+  print "xsil2graphics2 from xmds2 version %(versionString)s (%(subversionRevisionString)s)" % locals()
+  
+  # Attempt to parse command line arguments
+  if argv is None:
+    argv = sys.argv
+  try:
+    try:
+      opts, args = getopt.gnu_getopt(argv[1:], "hm8epo:", ["help", "matlab", "octave", "mathematica", "python", "outfile=", "debug"])
+    except getopt.error, msg:
+      raise Usage(msg)
+    
+    userSpecifiedFilename = None
+    defaultExtension = None
+    outputTemplateClass = MatlabOctaveImport
+    
+    optionList = [
+      ("-m", "--matlab", MatlabOctaveImport),
+      ("-8", "--octave", MatlabOctaveImport),
+      ("-e", "--mathematica", MathematicaImport),
+      ("-p", "--python", PythonImport),
+    ]
+    
+    # option processing
+    for option, value in opts:
+      if option in ("-h", "--help"):
+        raise Usage(help_message)
+      if option in ("-o", "--outfile"):
+        userSpecifiedFilename = value
+      if option == '--debug':
+        debug = True
+      for shortOpt, longOpt, importClass in optionList:
+        if option in (shortOpt, longOpt):
+          outputTemplateClass = importClass 
+    
+    if userSpecifiedFilename and len(args) > 1:
+      print >> sys.stderr, "The '-o' option cannot be used when processing multiple xsil files."
+    if not args:
+      # No xsil files to process
+      raise Usage(help_message)
+  
+  except Usage, err:
+    print >> sys.stderr, sys.argv[0].split("/")[-1] + ": " + str(err.msg)
+    print >> sys.stderr, "\t for help use --help"
+    return 2
+    
+  outputTemplate = outputTemplateClass(filter=IndentFilter)
+  print "Generating output for %s." % outputTemplate.name
+  
+  
+  for xsilInputName in args:
+    # If an output name wasn't specified, construct a default
+    if not userSpecifiedFilename:
+      # Strip off the '.xsil' extension
+      baseName = os.path.splitext(xsilInputName)[0]
+      # Grab the default extension from the output template
+      outputFilename = baseName + '.' + outputTemplateClass.defaultExtension
+    else:
+      outputFilename = userSpecifiedFilename
+    
+    print "Writing import script for '%(xsilInputName)s' to '%(outputFilename)s'." % locals()
+    
+    try:
+      inputXSILFile = XSILFile(xsilInputName, loadData='ascii')
+    except IOError, err:
+      print >> sys.stderr, "Exception raised while trying to read xsil file:", err
+      if debug:
+        raise
+      return
+    
+    # Now actually write the simulation to disk.
+    try:
+      file(outputFilename, 'w').write(outputTemplate.loadXSILFile(inputXSILFile))
+    except Exception, err:
+      print >> sys.stderr, 'ERROR:', err
+    
+  
+
+if __name__ == "__main__":
+  sys.exit(main())

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/xmds2.git



More information about the debian-science-commits mailing list